快取溢出

快取溢出

快取溢出(Buffer overflow),是指在存在快取溢出安全漏洞的計算機中,攻擊者可以用超出常規長度的字元數來填滿一個域,通常是記憶體區地址。在某些情況下,這些過量的字元能夠作為“可執行”代碼來運行。從而使得攻擊者可以不受安全措施的約束來控制被攻擊的計算機。

基本介紹

  • 中文名:快取溢出
  • 外文名:Buffer Overflow
概述,快取溢出攻擊方式,破壞活動記錄,破壞堆數據,更改函式指針,溢出固定快取區,檢測和預防技術,基於源碼的靜態分析技術,基於源碼的動態分析技術,基於二進制代碼的分析技術,其他檢測和預防技術,黑客如何攪亂快取,組成部分,防範緩衝區溢出,

概述

快取溢出(或譯為緩衝溢出)為黑客最為常用的攻擊手段之一,蠕蟲病毒對作業系統高危漏洞的溢出高速與大規模傳播均是利用此技術。快取溢出攻擊從理論上來講可以用於攻擊任何有缺陷不完美的程式,包括對防毒軟體防火牆等安全產品的攻擊以及對銀行程式的攻擊。
快取區溢出存在於各種電腦程式中,特別是廣泛存在於用C、C++等這些本身不提供記憶體越界檢測功能的語言編寫的程式中。現在C、C++作為程式設計基礎語言的地位還沒發生改變,它們仍然被廣泛套用於作業系統、商業軟體的編寫中,每年都會有很多快取區溢出漏洞被人們從已發布和還在開發的軟體中發現出來。從CERT漏洞資料庫和國家漏洞資料庫NVD中統計2001—2012年每一年發現的快取區溢出漏洞數如圖所示。雖然從圖上看出快取區溢出數相比2007年已經大幅減少,但在2011年的CWE/SANS最危險的軟體漏洞排行榜上,“沒進行輸入大小檢測的快取區複製”漏洞排名第三。可見,如何檢測和預防快取區溢出漏洞仍然是一個非常棘手的問題。
快取溢出

快取溢出攻擊方式

為實現快取區溢出攻擊,攻擊者必須在程式的地址空間裡安排適當的代碼及進行適當的初始化暫存器和記憶體,讓程式跳轉到入侵者安排的地址空間執行。控制程式轉移到攻擊代碼的方法有如下幾種:

破壞活動記錄

函式調用發生時,調用者會在棧中留下函式的活動記錄,包含當前被調函式的參數、返回地址、前棧指針、變數快取區等值,它們在棧中的存放順序如圖所示。由它們在棧中的存放順序可知,返回地址、棧指針與變數快取區緊鄰,且返回地址指向函式結束後要執行的下一條指令。棧指針指向上一個函式的活動記錄,這樣攻擊者可以利用變數快取區溢出來修改返回地址值和棧指針,從而改變程式的執行流。
快取溢出

破壞堆數據

程式運行時,用戶用C、C++記憶體操作庫函式如malloc、free等在堆記憶體空間分配存儲和釋放刪除用戶數據,對記憶體的使用情況如記憶體塊的大小、它前後指向的記憶體塊用一個連結類的數據結構予以記錄管理,管理數據同樣存放於堆中,且管理數據與用戶數據是相鄰的。這樣,攻擊者可以像破壞活動記錄一樣來溢出堆記憶體中分配的用戶數據空間,從而破壞管理數據。因為堆記憶體數據中沒有指針信息,所以即使破壞了管理數據也不會改變程式的執行流,但它還是會使正常的堆操作出錯,導致不可預知的結果。

更改函式指針

指針在C、C++等程式語言中使用得非常頻繁,空指針可以指向任何對象的特性使得指針的使用更加靈活,但同時也需要人們對指針的使用更加謹慎小心,特別是空的函式指針,它可以使程式執行轉移到任何地方。攻擊者充分利用了指針的這些特性,千方百計地溢出與指針相鄰的變數、快取區,從而修改函式指針指向達到轉移程式執行流的目的。溢出的具體方法可以參考文獻,本文不再詳述。

溢出固定快取區

C標準庫函式中提供了一對長跳轉函式setjmp/longjmp來進行程式執行流的非局部跳轉,意思是在某一個檢查點設定setjmp(buffer),在程式執行過程中用longjmp(buffer)使程式執行流跳到先前設定的檢查點。它們跟函式指針有些相似,在給用戶提供了方便性的同時也帶來了安全隱患,攻擊者同樣只需找一個與longjmp(buffer)相鄰的快取區並使它溢出,這樣就能跳轉到攻擊者要運行的代碼空間。典型的例子有Perl5.003的緩衝區溢出漏洞,攻擊者首先進入用來恢復緩衝區溢出的longjmp緩衝區,然後誘導進入恢復模式,這樣就使Perl的解釋器跳轉到攻擊代碼上了。

檢測和預防技術

快取區溢出首次進入公共視野是在1988年的第一種快取區溢出攻擊---Morris蠕蟲,被羅伯特等人製造出來造成全世界6000多台網路伺服器癱瘓後,人們開始關注快取區溢出,並相繼提出了各種各樣的快取區溢出檢測與預防技術和工具。本文參考李毅超、夏一民等人的分類,根據技術是作用於源碼還是二進制代碼、是只靜態分析代碼還是要重新編譯運行代碼,把所有的快取區溢出檢測和預防技術進行分類,如圖所示。隨後介紹了主流的檢測和預防技術的原理、發展歷程和優缺點。
快取溢出

基於源碼的靜態分析技術

模型化
模型化方法是靜態分析里一種常用的方法,它可以用在程式分析的很多方面,如判斷可執行路徑中正確屬性是否發生的nevertrace方法,能以較低花費支持安全需求進化過程的模型監測方法;同時它還能把快取區的定義與使用信息及其之間的關係與快取區有關的語句和函式都予以建模,把快取區溢出檢測問題等價地轉換為模型驗證問題。將快取區溢出檢測轉換為整數限制求解問題,把C字元串作為一個抽象數據類型,每一個快取區用兩個整數來描述,一個是整數表示快取區被分配的大小,另一個表示快取區使用的當前位置。標準庫函式被模型化為單純的長度賦值語句,判斷每次快取區操作時快取區使用的當前位置是否超過它所占記憶體的範圍,這樣即可把快取區溢出檢測問題轉換為整數限制求解問題。但由於整數範圍分析得不夠精確,使得該方法存在誤報,且報告快取區溢出時不能提供導致該溢出的相關信息,因而人工驗證的成本很高。CodeAuditor是上述技術的另一種實現方式,所不同的是快取區溢出檢測不再轉換為整數限制求解問題,而是轉換為模型驗證問題。CodeAuditor把與快取區有關的語句和函式轉換為整數轉移函式和約束(這些函式與約束就是判斷快取區是否溢出),在原始碼的AST樹上插入函式和約束的驗證語句,用模型驗證方法來判斷這些函式和約束是否能得到滿足。該方法有效地解決了因為範圍分析不夠精確而導致的誤報率過高問題。從上面分析可知,模型化的方法對模型的質量要求很高,模型不夠全面的話會漏掉很多錯誤;由於是把原問題轉換為其他問題求解,丟失了原來的一些信息,也容易導致誤報;當產生錯誤報告時不能提供為改正該錯誤有用的信息,因而錯誤修改亦不方便。
路徑分析
路徑分析是根據程式的控制流圖對每條執行路徑進行分析,判斷沿著路徑的執行是否導致快取區溢出。對路徑既可以正向遍歷亦可以反向遍歷。正向遍歷是在原程式的快取區操作前加入檢測語句,程式順序執行並運行檢測語句來判斷快取區是否溢出;反向遍歷是當遇到一個快取區操作時,逆向遍歷經過該快取區的所有路徑,得到快取區的分配使用信息,比較分配使用值的大小關係即能判斷快取區是否溢出。SecTAC是一個路徑再測試工具,它重用以前的測試用例來產生執行路徑,每條路徑符號執行後都會生成程式約束和安全約束,當程式變數滿足程式約束但是不滿足安全約束時,錯誤報告就會產生。該方法受產生執行路徑的測試用例的限制,如果測試用例不夠全面,漏報就會很多;當程式大且複雜時,執行路徑太多,SecTACSL的處理時間就會很長。Marple把路徑分為infeasible、safe、vulnerable、overflow-input-independent和don’t-know五類,它首先用分析器分析程式剔除不可能存在快取區溢出漏洞的路徑,從可能存在快取區溢出漏洞的語句上提出查詢;然後反向遍歷控制流程圖,並從源碼中提取出快取區相關信息;再建立漏洞模型來構造、更新、求解該查詢。當遇到進入infeasible路徑塊、收集的信息已夠解決該查詢和到函式入口時查詢還未解決這三種情況時,分析結束。如由收集的信息判斷出現了快取區溢出,Marple會返回可能導致產生該溢出的路徑信息。Marple的缺陷是它把很多庫函式調用、循環語句、共享的全局變數等作為don’t-know類型來處理,這樣就漏掉了很多漏洞。除了上面這兩種方法外,還有其他的路徑分析方法,如已有方法把可能導致快取區溢出的路徑分為三種模式:語法使用、元素訪問和塊移動。先用語法分析器把所有的語法使用錯誤都剔除,然後用受限的符號評價系統對後兩種模式進行分析,找出存在的快取區溢出漏洞。該方法對用戶自定義的操作不兼容,因而存在誤報與漏報。雖然路徑分析方法能綜合上下文對快取區溢出進行檢測,減少了快取區溢出檢測的誤報率,能對檢測語句進行最佳化,減少了處理時間,但從上面的敘述可以看出,它存在很明顯的漏報。對於大型的複雜的程式,因為路徑過多,檢測效果就更加不理想了。

基於源碼的動態分析技術

擴展編譯器
1)值驗證
為預防破壞活動記錄的攻擊,可以在返回地址和局部變數之間插入一個固定值,如果快取區溢出了必然會使該固定值發生改變,在訪問返回地址前先判斷該值是否發生了變化就可以預防這種攻擊。Cowan等人提出了函式調用時在快取區與返回地址之前插入一個canary值,在函式結束返回前判斷這個值是否被修改,如果被修改了就說明出現了棧溢出。隨後他們又提出了最佳化方法PointGuard,對函式指針和longjmp快取區之後也增加了canary值保護,防止被快取區溢出操作改寫。ProPolice繼承了Cowan的方法,所不同的是ProPolice重排了局部變數,使得攻擊者很難找到要溢出的快取區;複製函式參數內的指針到某一個安全區域使得這些指針不會被污染;同時對插樁代碼進行了最佳化。Hasabnis等人根據canary值原理提出了另一種邊界值檢測方法(LBC)。他們把每個對象的前後都插入一個guardzone,如果程式運行時訪問到任一個guardzone就提示出現了訪問錯誤。他們對guardzone的取值大小和如何插入這些guardzone進行了詳細的研究,但是沒有考慮到當guardzone與源程式代碼片段相同時該怎樣解決;當偏移使得指針從一個對象跳到另一個對象時,該方法也處理不了。為使攻擊者不能猜到canary值,canary取值必須隨機化。又因為該方法只是通過檢測canary值是否改變了來進行快取區溢出的判斷,不能對唯讀上溢和下溢進行判斷,也不能對堆溢出進行檢測等。
2)參考對象
早期的參考對象技術是在數組越界檢測里用一個包含指針基地址、指針所指向的空間大小、指針在檔案中所處的位置等作為一個多元組來擴展指針的表現形式。在程式中把所有的原指針都以新的指針訪問形式替換,這樣在程式運行時就能根據多元組裡的信息判斷指針訪問是否正確,如CCured、Cyclone等。因為該方法改變了指針的表現形式,導致處理後代碼與未處理的代碼不兼容。Jones等人提出了一種不改變指針表現形式的方法,它把單個有效的記憶體塊(變數、數組、結構、聯合等所被分配的記憶體)作為一個參考對象,用一個全局的對象表收集所有參考對象的基地址、空間大小等信息。在程式運行過程中,當對象創建時,把該對象的相關信息添加到對象表中,當程式運行超出了該對象的作用域或是對象被銷毀時,則從表中刪除該對象信息。在訪問該對象時,先查找表,判斷當前訪問是否超出了基地址加大小的範圍,如果超出了,這提示存在快取區溢出並結束程式。該方法當一個指針訪問出錯時,指向該指針的指針也不能再被檢測,即如果指針p訪問越界,則認為指向p的指針q也是越界的,即使q沒有越界。CRED是對Jones方法的最佳化,它以ILLEGAL表示一個越界指針,用一個寬鬆的越界判斷標準解決了上述問題。Dhurjati等人進一步最佳化了參考對象方法,他們用自動的池分配技術(automatic pool allocation)把一棵擴展樹分解成多棵樹,極大地減小了指示對象的查找時間,同時從擴展樹上刪除了一些多餘的對象,使樹整體上變小了。但是把整數強制轉換為指針等問題沒有很好地被解決。雖然Jones的系列方法解決了程式兼容性問題,但他們把數據類型為數組、結構、聯合等的變數分配的空間單獨作為一個參考,故不能對其中的成員元素進行越界檢測;它只能對在編譯時就已經明確的操作命令進行檢測,如*p,s.a等這些命令,當對它們取別名用別名來訪問時,就不能被處理。
3)影子記憶體
影子記憶體技術是把程式所占的記憶體所處的狀態映射到一個安全的區域(影子記憶體)中去,如Dr.Memory就把程式所占記憶體每一比特的狀態分為不可訪問、未初始化、已經定義的三種狀態。當訪問記憶體時先查找影子記憶體中對應比特的狀態,如果是不可訪問的話就說明出現訪問錯誤。典型的映射方法還有直接把地址空間的數值範圍和偏移映射到一個單一的影子地址空間或映射到表結構的影子空間。如TaintTrace用一塊與原地址空間同樣大小的影子空間;Dr.Memory用一個表結構作為影子空間的存儲結構,在訪問時要進行表的查找。為使地址空間的排列更加靈活,一些工具用了多層的映射機制,如Valgrind,在64位的平台上用額外的表來存儲高於32G的地址,LBC用兩級影子記憶體存放相應的信息。還有其他最佳化方法如Umbra,憑藉non-uniform避免了表查找操作,同時動態地調整了數值範圍與偏移機制;AddressSanitizer用了128-1的映射關係來進行影子狀態的編碼使得記憶體更加緊湊等。影子記憶體技術是在位層位對記憶體進行操作,故映射機制的好壞直接決定了所需影子記憶體的大小和查找所需要時間的長短。
另寫分析工具
Frama-C提出了一般規格語言ACSL和旨在消除靜態分析和動態分析工具之間區別的ACSL子語言E-ACSL,這兩種語言引入的“注釋”概念是指程式運行中要滿足的一些性質,如檢查指針訪問是否有效、變數有沒有溢出、數組訪問是否越界等。Frama-C在檢測程式時先用“注釋”生成外掛程式,如RTE,把“注釋”插入到原代碼中滿足E-ACSL規範的外掛程式;把這些“注釋”翻譯成C語言,編譯運行翻譯後的代碼,當“注釋”在程式運行過程中不被滿足時,程式終止執行並給出“注釋”所在行列號等信息。如果所有“注釋”在程式運行中都被滿足了,程式不會產生額外的信息,程式所做的功能與未插入“注釋”前是完全一樣的。Frama-C本質上仍然是一種運行時驗證技術,所不同的是它引入了產生“注釋”這一中間過程,把程式的靜態分析與動態分析有機地結合在一起。Frama-C用一個記憶體監測機制來監測記憶體的使用情況,在程式執行過程中記錄記憶體塊的有效性和初始化信息到一個專門的記憶體區域(該記憶體區域的存儲結構可以是表、樹等),在記憶體訪問時執行查詢語句來查找該區域以確定記憶體的訪問是否正確。雖然現在ASCS、E-ACSL語言已能處理大部分C語言錯誤,但是它對原程式的性能影響很大,最近Kosmatov等人最佳化了記錄存儲內容,比較了以哈希表、鍊表、伸展樹、Patricia樹等作為存儲結構對記錄查詢效率的影響,同時還改進了查詢算法,用靜態分析最佳化了插樁過程,進一步提高了該類語言的可用性。雖然以外掛程式的形式來編寫其他功能代碼使得Frama-C的擴展非常容易,但是從另一方面來說,該系列的語言過於複雜,導致最後插樁生成的可執行的C檔案代碼膨脹過大,程式執行效率降低很多;同時它們對C源檔案的處理過程是要先插入“注釋”,然後再把“注釋”翻譯成C類型語言,處理過程複雜,所需時間也長。

基於二進制代碼的分析技術

本文把基於二進制代碼的分析技術分為基於二進制代碼的靜態分析技術和動態分析技術。基於二進制代碼的靜態分析技術是在可執行的二進制代碼上進行靜態分析,找出感興趣的點(如函式調用、快取區訪問等),在這些點中插入一些語句來檢測程式的運行情況;然後重新生成新的二進制代碼,運行該代碼,如果運行過程中有錯誤發生(如數組越界),則停止程式的執行並報告錯誤。基於二進制代碼的動態分析技術不需要原始碼,在可執行的二進制代碼上修改或添加新的二進制代碼,程式運行過程中調用這些代碼來進行檢測。是否要重新生成新的可執行二進制代碼是基於二進制代碼的靜態分析技術與動態分析技術的不同點。
基於二進制代碼的靜態插樁技術
1)庫函式替換
該技術是在程式連結時用重新編寫過的能進行邊界值檢查的函式來替換C、C++標準庫函式中不進行邊界值檢查的函式,這樣當程式運行時,如果邊界檢查未通過,則報告出現快取區溢出並終止運行。Valgrind是一個開源的直接在二進制上進行插樁的快取區溢出檢測工具。插入相應的代碼攔截malloc和free函式的運行,然後在一個虛擬的x86處理器上模擬插樁之後代碼的執行,當模擬執行崩潰時,說明快取區操作出錯,Valgrind會產生相應的錯誤報告。處理相同的程式,Valgrind會比gcc多花25~50倍的時間。Seward等人還擴展了Valgrind的使用,在位精度層面對使用未定義的變數錯誤進行了檢測;在2007年把Valgrind正式擴展為一個動態二進制插樁工具。Chaperon同樣在可執行的二進制代碼上插入代碼來攔截替換malloc、free等函式的執行,通過新的函式來進行堆訪問有效性的驗證、記憶體泄露、訪問未定義變數錯誤的檢測。Chaperon能對堆快取區進行有效的檢測,但對棧快取區的檢測效果不行;當程式因為其他問題而崩潰時,Chaperon也不能進行有效的工作;Chaperon是一個不開源的商業工具,很難對它進行擴展。雖然庫函式替換的方法是在二進制上進行操作,不需要重新編譯源碼,但每調用一次庫函式都要進行邊界值的檢測:對原程式的執行效率影響很大;對靜態連線庫無效;不能預防基於堆或BSS數據段的攻擊等。
2)地址隨機化
地址隨機化技術是另一種二進制代碼靜態分析方法,它把程式代碼段、數據段等所在記憶體空間的地址打亂,使攻擊者很難知道某一段代碼、某一個數據在記憶體空間的地址位置,如隨機化變數和函式的順序、隨機化系統調用映射和改變庫的入口地址等。一般是用改變傳統的記憶體分配算法,在程式載入時將記憶體布局打亂。打亂的原則有隨機化代碼與數據的絕對地址和數據地址之間相對的距離。例如地址空間隨機化就是把進程空間的地址隨機化,使得用絕對地址空間進行攻擊的方法找不到它要攻擊的記憶體地址,這樣即使被攻擊,程式也只是崩潰而不會被控制。還有其他隨機化方法。例如:PaXASLR能在作業系統的支持下隨機化棧、堆、全局空間,但是不能隨機化代碼段和靜態數據段的地址;Addressobfuscation擴展了PaxASLR的方法,在編譯器的幫助下能隨機化靜態代碼段和數據段的地址,但是導致了11%的性能損耗;PIE能對全局對象進行處理,該對象基地址的數據段都能被重定位,它也會導致14%的性能損耗。可見這些方法共有的缺陷是隨機化不充分,能被暴力破解,對原程式的性能影響很大。Addressspacelayoutpermutation(ASLP)能對所有的空間地址進行隨機化,它用一個二進制重寫工具能隨機定位靜態數據段和代碼段,重排列代碼段的函式、數據段的數據對象。又因為是在二進制代碼上進行操作,故不需要原始碼;修改Linux核心使得它能夠隨機化棧、堆、記憶體映射區域。在二進制重寫工具和核心的支持下,ASLP能對32位結構下的29位進行隨機化,並且只損失了1%的性能。但是ASLP不能對棧框架進行隨機化,如它不能預防重定位到庫函式的攻擊;如果缺失重定位的信息,ASLP必須重新連結或是重新編譯。
基於二進制代碼的動態插樁技術(程式執行流更改)
該技術是在二進制代碼上替換要檢測的函式調用的入口、出口地址,在程式執行過程中,如果遇到函式調用語句,程式執行流直接跳到額外添加的代碼並執行,執行完再跳回原程式執行。Libverify利用_init()函式進行代碼插樁,插樁代碼的功能包括如何確定用戶代碼的位置和大小,如何確定在用戶代碼中函式的開始地址和對每一個函式的操作(複製函式到堆記憶體,在原函式調用前添加調用函式wrapper_entry和在原函式返回前添加調用函式wrapper_exit),這樣,在每個函式調用前把函式的返回地址通過wrapper_entry函式保存,在函式返回前用wrapper_exit函式來判斷返回地址是否被修改,如果被修改了就說明出現了棧溢出。Gupta等人最佳化了Libverify方法,他們沒有作函式代碼的複製,只是在二進制代碼上更改了函式的調用代碼,但是他們只能對5Byte的指令進行安全的跳轉,當編譯生成的二進制代碼中沒有5Byte的代碼可用來放置跳轉指令時,程式就會出現錯誤。而不同的編譯器對函式調用語句生成的二進制代碼的格式一般是不同的,可見該方法不能通用。雖然程式執行流更改技術現在只能對棧快取區溢出漏洞進行檢測,但是它在修改原來的二進制代碼後,不必重新編譯連結生成新的可執行二進制代碼,也就是說它不需要原始碼,這對那些未開源的程式測試是非常有意義的。同時還可以擴展該技術使得在不中斷服務的基礎上對那些提供服務的程式進行檢測。

其他檢測和預防技術

快取區溢出漏洞自動檢測與修復技術是近幾年才出現的,Arcuri於2008年首次提出了軟體bug自動修復的方法,他用合適的函式(自己設計或是從軟體說明書中自動生成)來進化程式(如用遺傳算法編寫的程式),使之能夠通過一系列單元測試用例,在進化過程中程式得到了修復與完善。雖然該方法存在修復的程式(遺傳程式GP)計算複雜、GP的搜尋空間太大、對完整複雜的程式測試不了、複雜的bug也不能被修復等問題,作者還是在一個冒泡排序程式上進行了實驗,說明了其方法是切實可行的。相比Arcuri的方法可以對各種不同的錯誤進行自動修復,SafeStack只能對棧快取區溢出漏洞進行修復。以往的自動修復技術需要中斷原程式的執行,修復完之後再重新運行程式,SafeStack是當原程式運行到可能存在快取區溢出的代碼片段時,跳到SafeStack執行,修復完成後返回原程式執行,因此它不會中斷原程式的執行。它通過記憶體訪問虛擬化技術把可能存在快取區溢出的代碼片段移到一個受保護的記憶體區域中,在該記憶體中對漏洞進行檢測、補丁生成、補丁測試、補丁運用等操作。SafeStack每一步實現借鑑了其他的技術,如檢測是否存在快取區溢出的canary方法,補丁生成和評測的First-Aid技術等。可見,快取區溢出的自動檢測與修復技術可以用協同進化的方法,也可以把現有的檢測技術與修復技術有機地結合在一起。結合的方式一般是先用檢測模組找出程式中的快取區溢出漏洞,然後傳遞給修復模組進行修復,修復完成後再輸入檢測模組進行檢測,直到不再有漏洞被檢測出來為止。流程如圖所示。還有很多其他的檢測和預防技術如增加硬體支持技術、增加一個新的堆疊來存放返回地址。在函式返回前判斷該堆疊里的地址與原堆疊中的返回地址是否一致來防止返回地址被修改,該類技術對源碼影響小、速度快,但作業系統和編譯器都需要相應的修改;使堆疊不可執行技術,該類技術能有效地預防堆疊快取區溢出攻擊,同樣需要修改作業系統和編譯器等等。
快取溢出

黑客如何攪亂快取

下面讓我們了解一下快取溢出的原理。眾說周知,c語言不進行數組的邊界檢查,在許多運用c語言實現的應用程式中,都假定緩衝區的大小是足夠的,其容量肯定大於要拷貝的字元串的長度。然而事實並不總是這樣,當程式出錯或者惡意的用戶故意送入一過長的字元串時,便有許多意想不到的事情發生,超過的那部分字元將會覆蓋與數組相鄰的其他變數的空間,使變數出現不可預料的值。如果碰巧,數組子程式的返回地址鄰近時,便有可能由於超出的一部分字元串覆蓋了子程式的返回地址,而使得子程式執行完畢返回時轉向了另一個無法預料的地址,使程式的執行流程發生了錯誤。甚至,由於應用程式訪問了不在進程地址空間範圍的地址,而使進程發生違例的故障。這種錯誤其實是編程中常犯的。

組成部分

一個利用緩衝區溢出而企圖破壞或非法進入系統的程式通常由如下幾個部分組成:
1. 準備一段可以調出一個shell的機器碼形成的字元串,在下面我們將它稱為shellcode。
2. 申請一個緩衝區,並將機器碼填入緩衝區的低端。
3. 估算機器碼堆疊中可能的起始位置,並將這個位置寫入緩衝區的高端。這個起始的位置也是我們執行這一程式時需要反覆調用的一個參數。
4. 將這個緩衝區作為系統一個有緩衝區溢出錯誤程式的入口參數,並執行這個有錯誤的程式。
通過以上的分析和實例,我們可以看到快取溢出對系統的安全帶來的巨大威脅。在unix系統中,使用一類精心編寫的程式,利用suid程式中存在的這種錯誤可以很輕易地取得系統的超級用戶的許可權。當服務程式在連線埠提供服務時,緩衝區溢出程式可以輕易地將這個服務關閉,使得系統的服務在一定的時間內癱瘓,嚴重的可能使系統立刻宕機,從而變成一種拒絕服務的攻擊。這種錯誤不僅是程式設計師的錯誤,系統本身在實現的時候出現的這種錯誤更多。如今,緩衝區溢出的錯誤正源源不斷地從unix、windows、路由器網關以及其他的網路設備中被發現,並構成了對系統安全威脅數量最大、程度較大的一類。

防範緩衝區溢出

緩衝區溢出是代碼中固有的漏洞,除了在開發階段要注意編寫正確的代碼之外,對於用戶而言,一般的防範錯誤為
–關閉連線埠或服務。管理員應該知道自己的系統上安裝了什麼,並且哪些服務正在運行
–安裝軟體廠商的補丁,漏洞一公布,大的廠商就會及時提供補丁
–在防火牆上過濾特殊的流量,無法阻止內部人員的溢出攻擊
–自己檢查關鍵的服務程式,看看是否有可怕的漏洞
-以所需要的最小許可權運行軟體

相關詞條

熱門詞條

聯絡我們