摘要:基于緩沖區溢出的攻擊是一種常見的安全攻擊手段,也是目前惟一最重要最常見的安全威脅。在所有的軟件安全漏洞中,緩沖區溢出漏洞大約占一半。該文從編程的角度分析了緩沖區溢出攻擊,并提出在源代碼階段盡量避免緩沖區溢出的方法。
關鍵詞:堆棧;緩沖區;溢出;緩沖區溢出攻擊
中圖分類號:TP311文獻標識碼:A文章編號:1009-3044(2008)36-2839-02
Prevention Technology Based on Buffer Overflow of Source Code
ZHANG Chuan-juan
(Fujian Communication Technology College, Fuzhou 350007, China)
Abstract: The attack, based on the buffer overflow, is a common means of security attacks and is the only most common security threats at present. Buffer overflow vulnerabilities account for about half Of all the software vulnerabilities. In this paper, from programming point of view, the buffer overflow attacks are analyzed and the methods of avoiding buffer overflow at the stage of source code are introduced.
Key words: stack; buffer; overflow; buffer overflow attacks
1 引言
1988年的Morris蠕蟲,是第一次利用緩沖區溢出缺陷的攻擊,導致6000多臺機器被感染,損失在$100 000至$10 000 000之間。之后,緩沖區溢出缺陷的攻擊愈來愈多,成為最常見也是最危險的網絡攻擊。
緩沖區溢出是由于程序或編譯器沒有對緩沖區進行邊界檢查導致的。發展C語言的初衷是為了編寫操作系統,后來被廣泛使用,其運行高效、精確控制資源等優點成為系統程序員最喜歡選擇的編程語言,很多商業軟件都是使用C語言編寫的。但C語言缺少安全機制,對數組和指針不做邊界檢查,由此帶來很多緩沖區溢出隱患。最直接的預防方法是編程時嚴格按照規則對邊界進行檢查,但實際效果不盡如人意,即使是經過嚴格培訓的程序員也會產生錯誤。為了防止緩沖區溢出,專家學者研究了很多的檢測和預防技術。本文將緩沖區溢出的原理進行分析,并對其檢測和預防技術進行一次介紹。
2 緩沖區溢出的原理
緩沖區溢出的原因是由于字符串處理函數(gets,strcpy等)沒有對數組的越界加以監視和限制,結果覆蓋了老的堆棧數據。
在計算機內的程序是按以下形式存儲的,見圖1。
01
圖1 程序在內存中的存儲
緩沖區溢出的造成的影響有兩個方面:1)覆蓋緩沖區相鄰內存中的數據,破壞程序數據的完整性;2)覆蓋了前一個棧基指針(ebp)、堆棧中的函數返回地址或函數參數,從而改變程序的流程。
許多C 程序都有緩沖區溢出的漏洞,一方面因為很多程序員在寫程序時都只考慮到程序的執行效率而忽視錯誤檢查與出錯處理。同時,標準C 庫函數本身就存在嚴重漏洞,如常用的strcat()、strcpy()、sprintf()、vsprintf()、bcopy()、gets()、scanf()等。
3 攻擊種類與實施過程
C語言中能改變內存地址內容的語句主要有兩類:1)*A=B; /*指針型語句*/;2)A[i]=B; /*數組型語句*/;
其中,A,B均為變量,*A為指針,A[]為數組,i 為數組下標。
在第一 類語句(指針型語句)中,由于A 所指向的內存地址取得B 的值,因而攻擊者能利用該聲明來改變函數的返回地址。由此可構成第一種攻擊方法,又可稱為指針型攻擊方法。
在第二類語句(數組型語句)中,數組A[]中的第i個元素A[i]取得B 的值。這類攻擊方式必須滿足下列條件:
1)一個循環聲明,用于將用戶輸入數據復制到一個緩沖區數組,而且不能檢查數據量,同時數組必須緊靠變量B;
2)一個循環聲明,用于將用戶輸入數據復制到數組A,而且不能檢查A 的上界,每次循環后i的值加1,同時數組A必須緊靠一個返回地址。
在此條件下可構造出兩種攻擊方式。
A)通過(1)改變B 的值,然后通過(2)將B 的新值循環輸入數組A,直到返回地址也被該新值覆蓋。這種攻擊中,不僅返回地址被改變,而且介于數組A與返回地址之間的所有內存區域也全被改寫。這種方法在緩沖區溢出攻擊中使用得最多。
B)假設A[k]存有函數的返回地址。如果我們用第一種攻擊方法使A[k]溢出,就可將返回地址的值改寫成任何需要的值。
4 緩沖區溢出攻擊舉例
下面的程序是典型的緩沖區溢出攻擊:
/*StackOverrun.c*/
void OverFlow(char *str)
{char buffer[16];
strcpy(buffer,str);}
void main ()
{char str[256];
int I;
for(i=0;i<255;i++) str[i]='A';
OverFlow(str);}
函數OverFlow()將一個字符串不經邊界檢查就拷貝到另一內存區域。顯然程序執行的結果是Segmentation fault (core dumped) 或類似出錯信息。因為從buffer 開始的256 個字節都將被*str的內容A 覆蓋,包括SFP,RET,甚至str。A 的十六進值為0x41,所以函數的返回地址變成了0x41414141,超出了程序的地址空間。結果證明我們的應用程序是可以被人利用的,所以一定要擔心!
5 檢測和常用預防技術
為解決緩沖區溢出問題,我們做了大量的工作,下面介紹幾種技術。
5.1 源代碼的靜態分析
ITS4使用潛在危險結構數據庫來檢測安全問題。很多程序員在進行安全審計時使用grep 命令查找危險的函數調用。ITS4的設計者目的是提供比grep 更智能的工具,在找到危險的函數調用時,ITS4 還能提供有用的安全建議。類似ITS4的分析工具還有Flawfinder、RATS、 FlexeLint、Pscan等。靜態分析的好處是快捷簡單,但沒有考慮程序的語義,忽略了過程之間的交互、變量值和控制流。
BogoSec是一個源代碼安全測量工具,它捆綁了幾種源代碼掃描器(ITS4 、Flawfinder、RATS),最后產生源代碼安全質量值。
5.2 擴展編譯器功能
編譯器是源碼變成可執行代碼的橋梁。有很多緩沖區溢出脆弱性檢測和預防技術解決方案是通過擴展編譯器功能,增加緩沖區邊界信息并插入邊界檢查代碼來實現的。
1)StackGuard:StackGuard對編譯器進行擴展,調用函數是在堆棧的局部變量和返回地址之間存放一個程序運行時的隨機產生的4個字節的“canary”字。若“canary”被破壞,則表明有緩沖區溢出產生,程序被終止。
2)StackShield: StackShield創建一個特別的堆棧---地址棧,用來儲存函數返回地址的一份拷貝。把返回地址壓棧同時保存到這個特別的地址棧中,在返回地址出棧前把從地址棧中取出返回地址。即使堆棧中的返回地址等信息被破壞,仍然可以保證不會跳轉到錯誤的地方執行。
3)LibSafe:在已知的緩沖區溢出漏洞中,大部分是因為沒有正確的使用gets,sscanf,sprintf 等字符串和io 函數. 基于這一事實,LibSafe 提供了一套和標準庫兼容的庫,用于替換已知的有安全隱患的庫。
4)Visual C++.Net 的/GS選項:Visual C++.Net 的/GS選項與StackGuard,它在聲明于棧上的變量與EBP指針、返回的地址指針幾函數特定的異常處理之間放置一個“canary”。
5)DIRA:DIRA是GCC編譯器的擴展。在編譯時插入適當的內存修改日志代碼,然后在所有對敏感數據引用的地方插入檢查代碼,最后在程序中插入識別攻擊代碼和修復程序的函數。
6 結束語
以上是基于源代碼的檢測安全漏洞的方法,沒有運行時的開銷,是編寫代碼及調試過程進行緩沖區檢測的常用技術。目前提出了對程序的可執行文件進行滲透測試及對操作系統進行改進設置基于堆棧和堆不可執行、段長限制、使用兩個堆棧等。每種技術都有不足之處,根本解決問題的方案是開發出全系列的能預防緩沖區溢出的操作系統、庫、編譯器和編程語言。
參考文獻:
[1] Foster J.C. 緩沖區溢出攻擊——檢測、剖析與預防[M].北京:清華大學出版社,2006.
[2] 許治坤,王偉,郭添森,等.網絡滲透技術[M].北京:電子工業出版社,2005.
[3] 張小斌,嚴望佳.黑客分析與防范技術[M].北京:清華大學出版社,1999.
[4] 楊朝龍,須文波.嵌入式系統安全中緩沖區溢出防止技術的研究與實現[J].嵌入式系統應用,2005(25):15-17.
[5] 單國棟,戴英俠,王航.計算機漏洞分類研究[J].計算機工程,2002(10):11-14.