[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 安全技術 > 系統 > 正文
緩沖區溢出:十年來攻擊和防衛的弱點
本文出自:http://www.xici.net 作者:大鷹 (2001-08-01 15:00:00)

在過去的十年中,以緩沖區溢出為類型的安全漏洞佔是最為常見的一種形式了。更為嚴重的是,緩沖區溢出漏
洞佔了遠程網絡攻擊的絕大多數,這種攻擊可以使得一個匿名的Internet用戶有機會獲得一台主機的部分或全
部的控制權!如果能有效地消除緩沖區溢出的漏洞,則很大一部分的安全威脅可以得到緩解。在本文中,我們
研究了各種類型的緩沖區溢出漏洞和攻擊手段,同時我們也研究了各種的防御手段,這些手段用來消除這些漏
洞所造成的影響,其中包括我們自己的堆棧保護方法。然我們要考慮如何在保証現有系統功能和性能不變的
情況下,如何使用這些方法來消除這些安全漏洞。

 
一、前言
 
  在過去的十年中,以緩沖區溢出為類型的安全漏洞佔是最為常見的一種形式了。更為嚴重的是,緩沖區溢出
漏洞佔了遠程網絡攻擊的絕大多數,這種攻擊可以使得一個匿名的Internet用戶有機會獲得一台主機的部分或全
部的控制權!由這類攻擊使任何人都有可能取得主機的控制權,所以它代表了一類極其嚴重的安全威脅。
 
  緩沖區溢出攻擊之所以成為一種常見安全攻擊手段其原因在緩沖區溢出漏洞太普通了,並且易實現。而
且,緩沖區溢出成為遠程攻擊的主要手段其原因在緩沖區溢出漏洞給予了攻擊者他所想要的一切:殖入並且執
行攻擊代碼。被殖入的攻擊代碼以一定的權限運行有緩沖區溢出漏洞的程序,從而得到被攻擊主機的控制權。
 
  比如,在1998年Lincoln實驗室用來評估入侵檢測的的5種遠程攻擊中,有3種是基社會工程學的信任關系,
2種是緩沖區溢出。而在1998年CERT的13份建議中,有9份是是與緩沖區溢出有關的,在1999年,至少有半數的建
議是和緩沖區溢出有關的。在Bugtraq的調查中,有2/3的被調查者認為緩沖區溢出漏洞是一個很嚴重的安全問題。
 
  緩沖區溢出漏洞和攻擊有很多種形式,我們會在第二部分對他們進行描述和分類。相應地防衛手段也隨者攻
擊方法的不同而不同,我們會放在第三部分描述,它的內容包括針對每種攻擊類型的有效的防衛手段。我們還要
要介紹堆棧保護方法,這種方法在解決緩沖區溢出的漏洞方面很有效果,並且沒有犧牲系統的兼容性和性能。在
第四部分,我們要討論各種防衛方法的綜合使用。最在第五部分是我們的結論。
 
二、緩沖區溢出的漏洞和攻擊
 
  緩沖區溢出攻擊的目的在擾亂具有某些特權運行的程序的功能,這樣可以使得攻擊者取得程序的控制權,
如果該程序具有足夠的權限,那整個主機就被控制了。一般而言,攻擊者攻擊root程序,然執行類似
“exec(sh)”的執行代碼來獲得root的shell,但不一直是這樣的。為了達到這個目的,攻擊者必須達到如下的兩
個目標:
 
1. 在程序的地址空間裡安排適當的代碼。
2. 通過適當地初始化寄存器和存儲器,讓程序跳轉到我們安排的地址空間執行。
 
  我們根據這兩個目標來對緩沖區溢出攻擊進行分類。在2.1部分,我們將描述攻擊代碼是如何放入被攻擊程序
的地址空間的(這個就是“緩沖區”名字的的由來)。在2.2部分,我們介紹攻擊者如何使一個程序的緩沖區溢出,
並且執行轉移到攻擊代碼(這個就是“溢出”的由來)。在2.3部分,我們介紹綜合在2.1和2.2部分所討論的代碼
安排和控制程序執行流程的技術。
 

2.1 在程序的地址空間裡安排適當的代碼的方法
 
有兩種在被攻擊程序地址空間裡安排攻擊代碼的方法:

殖入法:
  攻擊者向被攻擊的程序輸入一個字符串,程序會把這個字符串放到緩沖區裡。這個字符串包含的數據是可以在
這個被攻擊的硬件平台上運行的指令序列。在這裡攻擊者用被攻擊程序的緩沖區來存放攻擊代碼。具體的方式有以
下兩種差別:
 
1. 攻擊者不必為達到此目的而溢出任何緩沖區,可以找到足夠的空間來放置攻擊代碼 
2. 緩沖區可以設在任何地方:堆棧(自動變量)、堆(動態分配的)和靜態數據區(初始化或者未初始化的數據)
 
利用已經存在的代碼:
  有時候,攻擊者想要的代碼已經在被攻擊的程序中了,攻擊者所要做的只是對代碼傳遞一些參數,然使程序跳
轉到我們的目標。比如,攻擊代碼要求執行“exec("/bin/sh")”,而在libc庫中的代碼執行“exec(arg)”,其中
arg使一個指向一個字符串的指針參數,那攻擊者只要把傳入的參數指針改向指向"/bin/sh",然調轉到libc庫
中的相應的指令序列。
 
2.2 控制程序轉移到攻擊代碼的方法
 
  所有的這些方法都是在尋求改變程序的執行流程,使之跳轉到攻擊代碼。最基本的就是溢出一個沒有邊界檢查
或者其他弱點的緩沖區,這樣就擾亂了程序的正常的執行順序。通過溢出一個緩沖區,攻擊者可以用近乎暴力的方
法改寫相鄰的程序空間而直接跳過了系統的檢查。
 
  這裡分類的基準是攻擊者所尋求的緩沖區溢出的程序空間類型。原則上是可以任意的空間。比如,最初的
Morris Worm使用了fingerd程序的緩沖區溢出,擾亂fingerd要執行的文件的名字。實際上,許多的緩沖區溢出是用
暴力的方法來尋求改變程序指針的。這類程序的不同的地方就是程序空間的突破和內存空間的定位不同。
 
(圖1)

激活紀錄(Activation Records):
  每當一個函數調用發生時,調用者會在堆棧中留下一個激活紀錄,它包含了函數結束時
返回的地址。攻擊者通過溢出這些自動變量,使這個返回地址指向攻擊代碼,如圖1所示。通過改變程序的返回地址,
當函數調用結束時,程序就跳轉到攻擊者設定的地址,而不是原先的地址。這類的緩沖區溢出被稱為
“stack smashing attack”,使目前常用的緩沖區溢出攻擊方式。
 
函數指針(Function Pointers):
  “void (* foo)()”聲明了一個返回值為void函數指針的變量foo。函數指針可以用來定
位任何地址空間,所以攻擊者只需在任何空間內的函數指針附近找到一個能夠溢出的緩沖區,然溢出這個緩沖區來
改變函數指針。在某一時刻,當程序通過函數指針調用函數時,程序的流程就按攻擊者的意圖實現了!它的一個攻擊
范例就是在Linux系統下的superprobe程序。
 
長跳轉緩沖區(Longjmp buffers):
  在C語言中包含了一個簡單的檢驗/恢復系統,稱為setjmp/longjmp。意思是在檢驗點設
定“setjmp(buffer)”,用“longjmp(buffer)”來恢復檢驗點。然而,如果攻擊者能夠進入緩沖區的空間,那
“longjmp(buffer)”實際上是跳轉到攻擊者的代碼。象函數指針一樣,longjmp緩沖區能夠指向任何地方,所以攻
擊者所要做的就是找到一個可供溢出的緩沖區。一個典型的例子就是Perl 5.003,攻擊者首先進入用來恢復緩沖區
溢出的的longjmp緩沖區,然誘導進入恢復模式,這樣就使Perl的解釋器跳轉到攻擊代碼上了!
 

2.3 綜合代碼殖入和流程控制技術
 
現在我們研究綜合代碼殖入和流程控制的技術。
 
  最簡單和常見的緩沖區溢出攻擊類型就是在一個字符串裡綜合了代碼殖入和激活紀錄。攻擊者定位一個可供溢
出的自動變量,然向程序傳遞一個很大的字符串,在引發緩沖區溢出改變激活紀錄的同時殖入了代碼。這個是由
Levy指出的攻擊的模板。因為C在習慣上只為用戶和參數開辟很小的緩沖區,因此這種漏洞攻擊的實例不在少數。
 
  代碼殖入和緩沖區溢出不一定要在在一次動作內完成。攻擊者可以在一個緩沖區內放置代碼,這是不能溢出緩
沖區。然,攻擊者通過溢出另外一個緩沖區來轉移程序的指針。這種方法一般用來解決可供溢出的緩沖區不夠大
(不能放下全部的代碼)的情況。
 
  如果攻擊者試圖使用已經常駐的代碼而不是從外部殖入代碼,他們通常有必須把代碼作為參數化。舉例來說,
在libc(幾乎所有的C程序都要它來連接)中的部分代碼段會執行“exec(something)”,其中somthing就是參數。
攻擊者然使用緩沖區溢出改變程序的參數,然利用另一個緩沖區溢出使程序指針指向libc中的特定的代碼段。
 
3. 緩沖區溢出的保護方法
 
  目前有四種基本的方法保護緩沖區免受緩沖區溢出的攻擊和影響。在3.1中介紹了強制寫正確的代碼的方法。
在3.2中介紹了通過操作系統使得緩沖區不可執行,從而阻止攻擊者殖入攻擊代碼。這種方法有效地阻止了很多緩沖
區溢出的攻擊,但是攻擊者並不一定要殖入攻擊代碼來實現緩沖區溢出的攻擊(參見2.1節),所以這種方法還是存
在很弱點的。在3.3中,我們介紹了利用編譯器的邊界檢查來實現緩沖區的保護。這個方法使得緩沖區溢出不可能出
現,從而完全消除了緩沖區溢出的威脅,但是相對而言代價比較大。在3.4中我們介紹一種間接的方法,這個方法在
程序指針失效前進行完整性檢查。這樣雖然這種方法不能使得所有的緩沖區溢出失效,但它的的確確阻止了絕大多數
的緩沖區溢出攻擊,而能夠逃脫這種方法保護的緩沖區溢出也很難實現。然在3.5,我們要分析這種保護方法的兼
容性和性能優勢(與數組邊界檢查)。
 

3.1 編寫正確的代碼
 

  編寫正確的代碼是一件非常有意義但耗時的工作,特別象編寫C語言那種具有容易出錯傾向的程序(如:字符串的
零結尾),這種風格是由追求性能而忽視正確性的傳統引起的。盡管花了很長的時間使得人們知道了如何編寫安全
的程序,具有安全漏洞的程序依舊出現。因此人們開發了一些工具和技術來幫助經驗不足的程序員編寫安全正確的程
序。
 
  最簡單的方法就是用grep來搜索源代碼中容易產生漏洞的庫的調用,比如對strcpy和sprintf的調用,這兩個函數
都沒有檢查輸入參數的長度。事實上,各個版本C的標準庫均有這樣的問題存在。
 
  為了尋找一些常見的諸如緩沖區溢出和操作系統競爭條件等漏洞,代碼檢查小組檢查了很多的代碼。然而依然有漏
網之魚存在。盡管採用了strncpy和snprintf這些替代函數來防止緩沖區溢出的發生,但是由編寫代碼的問題,仍舊會
有這種情況發生。比如lprm程序就是最好的例子,雖然它通過了代碼的安全檢查,但仍然有緩沖區溢出的問題存在。
 
  為了對付這些問題,人們開發了一些高級的查錯工具,如fault injection等。這些工具的目的在通過人為隨機地
產生一些緩沖區溢出來尋找代碼的安全漏洞。還有一些靜態分析工具用偵測緩沖區溢出的存在。
 
  雖然這些工具幫助程序員開發更安全的程序,但是由C語言的特點,這些工具不可能找出所有的緩沖區溢出漏洞。
所以,偵錯技術只能用來減少緩沖區溢出的可能,並不能完全地消除它的存在。除非程序員能保証他的程序萬無一失,
否則還是要用到以下3.2到3.4部分的內容來保証程序的可靠性能。
 
3.2 非執行的緩沖區
 
  通過使被攻擊程序的數據段地址空間不可執行,從而使得攻擊者不可能執行被殖入被攻擊程序輸入緩沖區的代碼,
這種技術被稱為非執行的緩沖區技術。事實上,很多老的Unix系統都是這樣設計的,但是近來的Unix和MS Windows系統
由實現更好的性能和功能,往往在在數據段中動態地放入可執行的代碼。所以為了保持程序的兼容性不可能使得所有
程序的數據段不可執行。
 
  但是我們可以設定堆棧數據段不可執行,這樣就可以最大限度地保証了程序的兼容性。Linux和Solaris都發布了有
關這方面的內核補丁。因為幾乎沒有任何合法的程序會在堆棧中存放代碼,這種做法幾乎不產生任何兼容性問題,除了
在Linux中的兩個特例,這時可執行的代碼必須被放入堆棧中:
 
信號傳遞:
  Linux通過向進程堆棧釋放代碼然引發中斷來執行在堆棧中的代碼來實現向進程發送Unix信號。非執行緩沖區的
補丁在發送信號的時候是允許緩沖區可執行的。
 
GCC的在線重用:
  研究發現gcc在堆棧區裡放置了可執行的代碼作為在線重用之用。然而,關閉這個功能並不產生任何問題,只有部
分功能似乎不能使用。
 
  非執行堆棧的保護可以有效地對付把代碼殖入自動變量的緩沖區溢出攻擊,而對其他形式的攻擊則沒有效果
(參見2.1)。通過引用一個駐留的程序的指針,就可以跳過這種保護措施。其他的攻擊可以採用把代碼殖入堆或者靜態
數據段中來跳過保護。
 
3.3 數組邊界檢查
 
  殖入代碼引起緩沖區溢出是一個方面,擾亂程序的執行流程是另一個方面。不象非執行緩沖區保護,數組邊界檢查
完全放置了緩沖區溢出的產生和攻擊。這樣,只要數組不能被溢出,溢出攻擊也就無從談起。為了實現數組邊界檢查,
則所有的對數組的讀寫操作都應當被檢查以確保對數組的操作在正確的范圍內。最直接的方法是檢查所有的數組操作,
但是通常可以採用一些優化的技術來減少檢查的次數。目前有以下的幾種檢查方法:
 
3.3.1 Compaq C 編譯器
 
  Compaq公司為Alpha CPU開發的C編譯器(在Tru64的Unix平台上是cc,在Alpha Linux平台上是ccc)支持有限度的
邊界檢查(使用-check_bounds參數)。這些限制是:
 
.只有顯示的數組引用才被檢查,比如“a[3]”會被檢查,而“*(a+3)”則不會。
.由所有的C數組在傳送的時候是指針傳遞的,所以傳遞給函數的的數組不會被檢查。
.帶有危險性的庫函數如strcpy不會在編譯的時候進行邊界檢查,即便是指定了邊界檢查。
 
  由在C語言中利用指針進行數組操作和傳遞是如此的頻繁,因此這種局限性是非常嚴重的。通常這種邊界檢查用
來程序的查錯,而且不能保証不發生緩沖區溢出的漏洞。
 
3.3.2 Jones & Kelly: C的數組邊界檢查
 
  Richard Jones和Paul Kelly開發了一個gcc的補丁,用來實現對C程序完全的數組邊界檢查。由沒有改變指針的
含義所以被編譯的程序和其他的gcc模塊具有很好的兼容性。更進一步的是,他們由此從沒有指針的表達式中導出了一
個“基”指針,然通過檢查這個基指針來偵測表達式的結果是否在容許的范圍之內。
 
  當然,這樣付出的性能上的代價是巨大的:對一個頻繁使用指針的程序如向量乘法,將由指針的頻繁使用而使
速度比本來慢30倍。
 
  這個編譯器目前還很不成熟;一些復雜的程序(如elm)還不能在這個上面編譯,執行通過。然而在它的一個更新
版本之下,它至少能編譯執行ssh軟件的加密軟件包。其實現的性能要下降12倍。
 
3.3.3 Purify:存儲器存取檢查
 
  Purify是C程序調試時查看存儲器使用的工具而不是專用的安全工具。Purify使用“目標代碼插入”技術來檢查所
有的存儲器存取。通過用Purify連接工具連接,可執行代碼在執行的時候數組的所有引用來保証其合法性。這樣帶來的
性能上的損失要下降3-5倍。
 
3.3.4 類型-安全語言
 
  所有的緩沖區溢出漏洞都源C語言缺乏類型安全。如果只有類型-安全的操作才可以被允許執行,這樣就不可能出
現對變量的強制操作。如果作為新手,可以推薦使用具有類型-安全的語言如Java和ML。
 
  但是作為Java執行平台的Java虛擬機是C程序,因此通過攻擊JVM的一條途徑是使JVM的緩沖區溢出。因此在系統中
採用緩沖區溢出防衛技術來使用強制類型-安全的語言可以收到意想不到的效果。
 
3.4 程序指針完整性檢查
 
  程序指針完整性檢查和邊界檢查由略微的不同。與防止程序指針被改變不同,程序指針完整性檢查在程序指針被引
用之前檢測到它的改變。因此,即便一個攻擊者成功地改變了程序的指針,由系統事先檢測到了指針的改變,因此這
個指針將不會被使用。
 
  與數組邊界檢查相比,這種方法不能解決所有的緩沖區溢出問題;採用其他的緩沖區溢出方法就可以避免這種檢測。
但是這種方法在性能上有很大的優勢,而且在兼容性也很好。
 
  程序完整性檢查大體上有三個研究方向。在3.4.1中會介紹Snarskii為FreeBSD開發了一套定制的能通過監測cpu堆
棧來確定緩沖區溢出的libc。在3.4.2中會介紹我們自己的堆棧保護方法所開發的一個編譯器,它能夠在函數調用的時
候自動生成完整性檢測代碼。最在3.4.3,我們介紹正在開發中的指針保護方法,這種方法類似堆棧保護,它提供
對所有程序指針的完整性的保護。
 
3.4.1 手寫的堆棧監測
 
  Snarskii為FreeBSD開發了一套定制的能通過監測cpu堆棧來確定緩沖區溢出的libc。這個應用完全用手工匯編寫的,
而且只保護libc中的當前有效紀錄函數。這個應用達到了設計要求,對基libc庫函數的攻擊具有很好的防衛,但是
不能防衛其它方式的攻擊。
 
3.4.2 堆棧保護:編譯器生成的有效紀錄完整性檢測
 
  堆棧保護是一種提供程序指針完整性檢查的編譯器技術,通過檢查函數活動紀錄中的返回地址來實現。堆棧保護作
為gcc的一個小的補丁,在每個函數中,加入了函數建立和銷毀的代碼。加入的函數建立代碼實際上在堆棧中函數返回
地址面加了一些附加的字節,如圖2示。而在函數返回時,首先檢查這個附加的字節是否被改動過。如果發生過緩沖區
溢出的攻擊,那這種攻擊很容易在函數返回前被檢測到。
 
(圖2)
  但是,如果攻擊者預見到這些附加字節的存在,並且能在溢出過程中同樣地制造他們,那他就能成功地跳過堆棧
保護的檢測。通常,我們有如下的兩種方案對付這種欺騙:
 
終止符號:
  利用在C語言中的終止符號如0(null),CR,LF,-1(EOF)等不能在常用的字符串函數中使用,因為這些函數一旦遇到
這些終止符號,就結束函數過程了。
 
隨機符號:
  利用一個在函數調用時產生的一個32位的隨機數來實現保密,使得攻擊者不可能猜測到附加字節的內容。而且,每
次調用,附加字節的內容都在改變,也無法預測。
 
  通過檢查堆棧的完整性的堆棧保護法是從Synthetix方法演變來的。Synthetix方法通過使用準不變量來確保特定變
量的正確性。這些特定的變量的改變是程序實現能預知的,而且只能在滿足一定的條件才能可以改變。這種變量我們稱
為準不變量。Synthetix開發了一些工具用來保護這些變量。
 
  攻擊者通過緩沖區溢出而產生的改變可以被系統當做非法的動作。在某些極端的情況下,這些準不變量有可能被非
法改變,這是就需要堆棧保護來提供更完善的保護了。
 
(表一)
  實驗的數據表明,堆棧保護對各種系統的緩沖區溢出攻擊都有很好的保護作用,並能保持較好的兼容性和系統性
能。早先我們報告的堆棧保護所能抑制的漏洞都在表一中列出。隨,我們用堆棧保護的方法重新構造了一個完整的
Linux系統(Red Hat 5.1)。然我們用XFree86-3.3.2-5和lsof的漏洞對此進行了攻擊,結果表明,這個系統有效地抵
御了這些攻擊。這些分析表明,堆棧保護能有效抵御現在的和將來的基堆棧的攻擊。
 
  堆棧保護版本的Red Hat Linux 5.1已經在各種系統上運行了多年,包括個人的筆記本電腦和工作組文件服務器。
從我們的Web服務器上可以得到這個版本,而且在我們的郵件列表裡已經有了55個成員。出了僅有的一次例外,這個系
統和本來的系統工作完全一樣,這表明堆棧保護並不對系統的兼容性構成很大的影響。
 
  我們已經用各種性能測試來評測堆棧保護的性能。Mircobenchmarks的結果表明在函數的調用,堆棧保護中增加了
系統的開銷。而在網絡的測試中(需要用到堆棧保護的地方),則表明這種開銷不是很大。
 
  我們的第一個測試對象是SSH,它提供了極強的加密和認証,用來替代Berkeley的r系列指令。SSH使用了軟件加密,
因此系統的佔用的帶寬不大,我們用網絡間復制一個大的文件來測試帶寬:
 
scp bigsource localhost:bigdest
 
測試結果表明:堆棧保護幾乎不影響SSH的網絡吞吐性能。
 
  第二個測試使用了Apache Web服務器。如果這種服務器存在基堆棧的攻擊,那攻擊者就可以輕易地取得Web服
務器的控制權,允許攻擊者閱讀隱秘的內容和肆意篡改主頁的內容。同時,Web服務器也是對性能和帶寬要求較高的一
個服務器部件。
 
我們用WebStone對帶有和不帶堆棧保護的Apache Web服務器進行了測試,測試的結果在表二中列出。
 
  和SSH一樣,他們的性能幾乎沒有區別。在客戶數目較少的情況下,帶有保護的服務器性能比不帶保護的略微好些,
在客戶端數目多的時候,不帶保護的性能好些。在最壞的情況下,帶保護的服務器比不帶保護的要差8%的連接性能,而
在平均延時上保持優勢。象以前一樣,我們把這些歸結為噪聲的影響。因此,我們的結論是:堆棧保護對Web服務器系
統性能沒有重大的影響。
 
3.4.3 指針保護:編譯器生成程序指針完整性檢查
 
  在堆棧保護設計的時候,沖擊堆棧構成了緩沖區溢出攻擊的常見的一種形式。有人推測存在一種模板來構成這些攻
擊(在1996年的時候)。從此,很多簡單的漏洞被發現,實施和補丁了,很多攻擊者開始用在第二部分中描述的更一般
的方法實施緩沖區溢出攻擊。
 
  指針保護是堆棧保護針對這種情況的一個推廣。通過在所有的代碼指針之放置附加字節來檢驗指針在被調用之前
的合法性。如果檢驗失敗,會發出報警信號和退出程序的執行,就如同在堆棧保護中的行為一樣。這種方案有兩點需要
注意:
 
附加字節的定位:
  附加字節的空間是在被保護的變量被分配的時候分配的,同時在被保護字節初始化過程中被初始化。這樣就帶來了
問題;為了保持兼容性,我們不想改變被保護變量的大小,因此我們不能簡單地在變量的結構定義中加入附加字。還有,
對各種類型也有不同附加字節數目。
 
檢查附加字節:
  每次程序指針被引用的時候都要檢查附加字節的完整性。這個也存在問題;因為“從存取器讀”在編譯器中沒有語
義;編譯器更關心指針的使用,而各種的優化算法傾向從存儲器中讀入變量。

 
還有隨著不同類型的變量,讀入的方法也各自不同。
 
  我們已經開發了指針保護的一個原型(還是基gcc的),通過附加字節來保護靜態分配的函數指針,但不適用
結構和數組類型。這個計劃還遠沒有完成。一旦這個項目完成了,那用它和堆棧保護構成的可執行代碼將不會受到緩
沖區溢出的攻擊了。
 
  目前為止,只有很少一部分使用非指針變量的攻擊能逃脫指針保護的檢測。但是,可以通過在編譯器上強制對某一
變量加入附加字節來實現檢測,這時需要程序員自己手工加入相應的保護了。
 
3.5 兼容性和性能的考慮
 
程序指針完整性檢查與邊界檢查相比,並不能防止所有的緩沖區溢出問題。然而在執行的性能和兼容性上具有相當的優
勢:
 
性能:
  邊界檢查必須在每個數組元素操作時完成一次檢查。相比之下,程序指針檢查只在被引用的時候實現檢查。無論在
C還是在C++中,這種花在程序指針引用上的開銷始終比數組的指針引用小。
 
應用效能:
  邊界檢查最難實現之處在在C語言中,很能確定數組的邊界。這是由在C中,數組的概念和通用指針的混用造成
的。由一個指針是一個獨立的對象,沒有與特定的邊界條件關聯,只有一個系統的機器字來存儲它,而標識邊界信息
的數據卻沒有存放。因此需要特殊的方法來恢復這些信息;數組的引用將不在是一個簡單的指針,而是一個對緩沖區描
述的指針組。
 
與現有代碼的兼容性:
  一些邊界檢查方法為了與現有的代碼保持兼容而在系統的性能上得到了損失。而另一些則用別的方法達到目的。這
樣就打破的傳統的C的轉換規則,轉而產生了一類新的C編譯器,只能編譯C的一個子集,有的還不能使用指針或者需要
別的改變。
 
4. 有效的組合
 
  在這裡我們研究、比較在第二部分描述的各種漏洞攻擊和在第三部分描述的防衛方法,以此來確定何種組合能完全
消除緩沖區溢出問題。我們把關緩沖區溢出的攻擊和防衛的方法都列在表3中,但是我們沒有把邊界檢查計算在內,
因為它能有效地防止所有的緩沖區溢出,但是所需的開銷也是驚人的。
 
  最普通的緩沖區溢出形式是攻擊活動紀錄然在堆棧中殖入代碼。這種類型的攻擊在1996年中有很多紀錄。而非執
行堆棧和堆棧保護的方法都可以有效防衛這種攻擊。非執行堆棧可以防衛所有把代碼殖入堆棧的攻擊方法,堆棧保護可
以防衛所有改變活動紀錄的方法。這兩種方法相互兼容,可以同時防衛多種可能的攻擊。
 
  剩下的攻擊基本上可以用指針保護的方法來防衛,但是在某些特殊的場合需要用手工來實現指針保護。全自動的指
針保護需要對每個變量加入附加字節,這樣使得指針邊界檢查在某些情況下具有優勢。
 
  最為有趣的是,第一個緩沖區溢出漏洞--Morris蠕虫使用了現今所有方法都無法有效防衛的方法,但是卻很少有人
用到,也許是這種方法過復雜的緣故吧。
 
5. 結論
 
  在本文中,我們詳細描述和分析了緩沖區溢出的攻擊和防衛方法。由這種攻擊是目前常見的攻擊手段,所以進行
這個方面的研究工作是有意義和成效的。研究的結果表明,堆棧保護方法和非執行緩沖區方法對當前絕大多數的攻擊
都能有效地防御,指針保護的方法可以對剩下的攻擊進行有效的防御。最聲明的是對Morris蠕虫的攻擊,迄今還沒
有有效的防御手段。
 
(http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
 

★  樊強制作 歡迎分享  ★