?

緩沖區溢出攻擊的原理和防范技術分析

2013-09-25 14:13姜燕劉娜
電子設計工程 2013年8期
關鍵詞:編譯器堆棧字符串

姜燕,劉娜

(湖北醫藥學院 公共管理學院,湖北 十堰 442000)

緩沖區溢出是指向緩沖區中傳輸的數據超出了緩沖區所能容納的最大長度,從而使提交的數據超過相應的邊界而進入了其他區域[1]。緩沖區溢出攻擊則是人為將大于緩沖區長度的數據傳輸到緩沖區,從而覆蓋其他區域的數據,達到破壞性目的的操作。緩沖區溢出已成為一種十分普遍和危險的安全漏洞,存在于各種操作系統和應用軟件中。利用緩沖區溢出攻擊,可以導致程序運行失敗、系統死機、計算機重新啟動等后果,更為嚴重的是可以利用它執行非授權指令,甚至可以取得系統特權,進而進行各種非法操作。

1 緩沖區溢出攻擊的原理

程序執行時的內存從邏輯上可以分為代碼區和數據區兩大部分,而數據區又可以分為靜態數據區、堆棧和堆3個部分。代碼區存放可執行代碼,只能讀不能寫,因此相對比較安全;數據區的數據經常隨著程序的運行變化,是攻擊發生的主要地方。本文以在堆棧中的溢出說明緩沖區溢出攻擊的原理。

堆棧是在程序運行過程中由操作系統分配的內存區域,當程序中發生函數調用時,主要完成如下操作:首先把函數參數壓入堆棧;然后向堆棧壓入指令寄存器(IP)中的內容,作為返回地址 (RET);接下來放入堆棧的是基址寄存器(EBP),把當前的棧指針(ESP)拷貝到 EBP,做為新的基地址;最后把ESP減去適當的數值,為本地變量留出一定空間[2]。堆棧的情形如圖1所示。

圖1 堆棧的情形Fig.1 Stack situation

通過以下程序的執行過程可以說明對堆棧的操作和溢出的產生過程。

編譯運行以上代碼,輸入“network”結果會輸出network,其中對堆棧的操作是先在棧底壓入返回地址,接著將棧指針EBP入棧,此時EBP等于現在的ESP,之后ESP減10,即向上增長10個字節,用來存放strbuffer數組。最后,從main返回,彈出RET里的返回地址并賦值給IP,CPU繼續執行IP所指向的命令。如果我們輸入的字符串長度超過10個字節,則由于輸入的字符串太長,strbuffer數組容納不下,只好向堆棧的底部方向繼續寫入。這些超出10字節部分的數據覆蓋了堆棧的基地址寄存器、RET或函數參數部分的數據。從main返回時,就必然會把新的數據視作返回地址,CPU會試圖執行新數據所指向的指令,結果出現難以預料的后果,這樣就產生了一次堆棧溢出。

除了上述攻擊外,還有針對堆的溢出攻擊和基于lib庫的緩沖區溢出攻擊及格式化串[3]的攻擊,無論是何種攻擊,最根本的原因是由于C語言的char*這種數據結構的存在。在進行字符串處理時不能自動進行長度的檢查,留下了很多的安全隱患。

緩沖區溢出攻擊通常分為 3步[4]:1)在目標程序中植入攻擊代碼(shellcode);2)拷貝數據到需要溢出的緩沖區并破壞鄰近區域的數據結構;3)獲得shell執行攻擊代碼(shellcode)。其中第二步是進行攻擊的主要環節。

2 緩沖區溢出攻擊的防范

面對緩沖區溢出攻擊的挑戰,根據各種攻擊的機制,提出了不同的防范措施,這些措施包括技術層面的和非技術層面的,在技術層面有軟件技術手段和硬件技術手段。常見的防范措施主要有如下幾種。

2.1 數組邊界檢查

根據緩沖區溢出的特點,只要對輸入字符串或傳遞給函數的字符串參數的長度做邊界檢查,就可以有效地防止緩沖區溢出的發生,從而也就不可能發生任何緩沖區溢出攻擊。因此,防范緩沖區溢出攻擊的首要方法是使用帶邊界檢查機制的安全計算機語言編寫程序,如Java、Pascal、Perl和Python等。若使用的是C語言等不帶邊界檢查機制的語言,則需要在編寫程序時由程序員負責考慮各種可能發生緩沖區溢出的情況并加以避免或使用一些輔助技術進行檢查。

2.1.1 人工檢查

C語言中很多的字符串處理函數如strcpy()、strcat()、sprintf()、vsprintf()、gets()、scanf()等都不能進行數組邊界的判定,因此需要在使用這些函數之前加上一些邊界檢查語句判斷源字符串的長度,再進行拷貝操作?;蚴褂肅語言之后改進的帶有邊界檢查功能的標準函數如strncpy()、strncat()、snprintf()、fgets()等替換上述函數。

此方法的優點是直接簡單,缺點是對人的依賴性太高,而現實中程序員要受各個方面因素的影響,難以取得較好的效果。

2.1.2 靜態發現技術

靜態發現技術是在程序設計過程中,根據一定的規則發現源代碼中潛在的漏洞,以便程序員進行改進?,F在已經發展了很多成熟的靜態發現技術,主要有 ITS4、Flawfinder、RATS和 BOON 等[5-6]。

ITS4(It’s the Software Stupid Source Scanner)是一種命令模式的交互式程序漏洞掃描工具,它能對C/C++程序的每一個函數進行代碼分析,根據所建立的模式庫匹配,然后依據危險級別給用戶一個修改提示報告。

Flawfinder是基于Python語言開發的用來輔助進行C/C++程序安全審查的工具,運行于類UNIX平臺。它內嵌了一些類似于ITS4的程序漏洞數據庫,如緩沖區溢出、格式化串漏洞等,掃描速度較快。

RATS(Rough Auditing Tool for Security)作為程序安全性的審計工具,比Flawfinder支持更多的語言,提供了對C、C++、Perl、PHP以及 Python語言的漏洞掃描。

BOON (Buffer Overrun detectiON)是加州伯克利 David Wagner博士論文的實現原型,是專門針對C程序緩沖區溢出漏洞的檢測工具。BOON借鑒面向對象思想,對每個字符串變量設置了兩個屬性,一個描述該字符串被分配的大小,另一個描述字符串實際被使用的大小。所有的字符串處理函數都將參考這兩個屬性對字符串進行操作。BOON通過掃描計算后得出源程序中的安全漏洞級別,程序員根據BOON的報告然后手動改正源程序的缺陷。BOON不檢查有關格式化串漏洞的掃描。

完全找出程序中所有的錯誤是不可能的,所以靜態發現技術是不完整的解決方案,它只是降低了程序被攻擊的可能性,而且靜態發現工具還需要維護一個與漏洞有關的不斷變化的規則庫。

2.1.3 動態防御技術

動態防御技術是從操作系統和編譯系統角度,通過編譯器自動地在程序中添加額外的代碼以及讓操作系統提供一些輔助的手段,來動態地發現運行的程序是否有緩沖區溢出 。 主要方法如下[5,7-8]:

Austin等人提出的安全指針方法將指針的表現形式擴展為安全指針,包含原指針的基地址及可訪問范圍信息。安全指針可以十分方便地實現邊界檢查。但由于改變了原有指針的表現形式,會與現有程序的代碼形式不兼容,需要重新編寫源代碼。

Richard Jones和Paul Kelly針對安全指針的兼容性問題提出了另一種保留原指針形態的實時緩沖區邊界檢查方法。該方法將程序運行時創建的每個緩沖區視為一個對象,并動態地維護一張含有所有對象的列表。當需要進行緩沖區的指針操作時,通過將該指針映射到相應的對象來獲得緩沖區的長度信息,從而實現邊界檢查。

Purify是C程序調試時查看存儲器使用的工具,Purify檢查所有的存儲器存取,通過用Purify鏈接工具鏈接,可執行代碼在執行的時候檢查對數組的所有引用來保證其合法性。

LibSafe針對C庫中的潛在有緩沖區溢出漏洞的函數重新包裝,在函數調用前先計算目標地址有否被緩沖區溢出的可能,即要先進行邊界檢查,然后才調用以完成該函數正常的功能。LibSafe在實現時,其邊界檢查只是計算目標緩沖區是否會溢出到函數返回地址,對函數內部用到的局部變量(如函數指針)就檢查不到,所以該方法不是萬能的。LibSafe的優點是不需要重新編譯源程序,只需更改系統的庫函數即可。

此外,在編譯器方面,當編譯含有字符串數組的程序時編譯器在程序開頭預留出足夠的空間后,接著就將這些空間進行初始化。編譯器為函數中的字符串數組分配了空間,但并沒有標志數組的末尾位置,所以根本無法正確測量字符串數組的確切大小。應該修改現有編譯器的初始化操作,使它在字符串數組的末尾加上結束標志“91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合