朱煒煒
【摘要】隨著Internet及相關信息技術的迅速發(fā)展,網上的電子商務呈現(xiàn)出極大的增長勢頭,但投入的增多意味著風險也隨之而來,網絡安全問題成為各種網上活動需要考慮的頭等大事。本文重點探討一下緩沖區(qū)溢出對計算機系統(tǒng)造成的危害。因為幾十年來,緩沖區(qū)溢出一直引起許多嚴重的安全性問題。近年由CERT/CC(Computer Emergency Response Term/Coodination Center)發(fā)布的忠告中關于緩沖區(qū)溢出漏洞占56.76%以上。本文首先解釋了緩沖區(qū)溢出的概念,從程序語言本身存在缺陷,不夠健壯的角度出發(fā),對緩沖區(qū)溢出的原理進行了詳細的闡述;之后,結合緩沖區(qū)溢出攻擊的類型,從系統(tǒng)管理和軟件開發(fā)兩個角度提出了緩沖區(qū)溢出攻擊的防范策略。
【關鍵詞】緩沖區(qū)溢出 攻擊
【Abstract】With the development of Internet and information technology, the great growth has appeared out in E-Commerce. But this trend lead to more venture, network security issue has become the cardinal task that various kinds of online activity need to consider.At present, the biggest problem on network is that computer software is usually not stalwart enough, sometimes such barrier will cause catastrophic result, especially when being utilized maliciously by the lawless person, the harm will hard to estimate.Buffer overflow attacking is a seriously problem in network security and cause serious security problems in recently years. Some program language have pestilent bug, for example, C program language doesnt check the border of the array of number is apt to cause the buffer overflow, and therefore possibly cause the failure of program processing and paralysis of computer.
This paper analysis deeply the principle and possibility of buffer overflow attacking, and point out buffer overflows potential dangers. At last, according to the kinds of buffer overflow attacking, I put forward my own opinion of precautionary measures on buffer overflow attacking.
【Key Words】buffer overflow attacking
第一章 緩沖區(qū)溢出簡介
1.1 什么是緩沖區(qū)溢出
緩沖區(qū)溢出開始于每個程序都需要的一些情況:放置位元的空間。多數(shù)計算機程序都在內存中創(chuàng)建多個地址用于信息存儲。C 編程語言允許程序員在運行時在內存的兩個不同部分(堆棧和堆)中創(chuàng)建存儲器。通常,分配到堆的數(shù)據是那些 malloc() 或新建時獲得的數(shù)據。而分配到堆棧的數(shù)據一般包括非靜態(tài)的局部變量和所有按值傳遞的參數(shù)。大部分其它信息存儲在全局靜態(tài)存儲器中。在分配同一數(shù)據類型的相鄰塊時,這塊內存區(qū)域稱為緩沖區(qū)。
在寫入緩沖區(qū)時,C 程序員必須注意存儲在緩沖區(qū)中的數(shù)據不能超過它所能容納的量。緩沖區(qū)只能容納一定數(shù)量的位,如果試圖放入緩沖區(qū)的數(shù)據比它能裝入的要多,額外的數(shù)據就會溢出到別處,并且您不希望它到其它地方!
當程序寫入超過緩沖區(qū)的邊界時,這就是所謂的“緩沖區(qū)溢出”。發(fā)生緩沖區(qū)溢出時,會覆蓋下一個相鄰的內存塊。由于 C 語言本質上的不安全性,所以它允許程序隨意(或者更準確地說是完全出于偶然)溢出緩沖區(qū)。沒有運行時檢查來防止寫入超過緩沖區(qū)末尾,所以程序員必須在其自己的代碼中執(zhí)行這一檢查,否則繼續(xù)下去會遇到問題。
讀取或寫入超過緩沖區(qū)的末尾時,會導致許多不同(并且通常是不可預料的)行為:1) 程序的執(zhí)行很奇怪,2) 程序完全失敗,或者 3) 程序可以繼續(xù),而且在執(zhí)行中沒有任何明顯不同。緩沖區(qū)溢出的副作用取決于:
寫入的數(shù)據中有多少超過緩沖區(qū)邊界
當緩沖區(qū)已滿并且溢出時,覆蓋了哪些數(shù)據(如果有的話)
程序是否試圖讀取溢出期間被覆蓋的數(shù)據
哪些數(shù)據最終替換被覆蓋的內存
存在緩沖區(qū)溢出的程序的不確定行為使得對它們的調試異常棘手。最壞的情況是:程序可能正發(fā)生緩沖區(qū)溢出,但根本沒有任何副作用的跡象。因此,緩沖區(qū)溢出問題常常在標準測試期間是發(fā)現(xiàn)不了的。認識緩沖區(qū)溢出的重要一點是:在發(fā)生溢出時,會潛在地修改碰巧分配在緩沖區(qū)附近的任何數(shù)據。
1.2 為什么緩沖區(qū)溢出是安全問題
當緩沖區(qū)溢出時,額外的數(shù)據會摧殘程序將來可能要訪問的其它有用的數(shù)據。有時,這些其它數(shù)據的更改會導致安全性問題。
最簡單的情況就是考慮直接在緩沖區(qū)后面的內存中分配一個布爾標志。這個標志決定運行程序的用戶是否可以訪問專用文件。如果有不懷好意的用戶覆蓋緩沖區(qū),則會更改標志的值,從而指出攻擊者是非法訪問專用文件。
緩沖區(qū)溢出導致安全性問題的另一個方法是通過摧毀堆棧。摧毀堆棧的目的是導致一個特定的編程故障:不仔細使用分配在程序運行時堆棧上的數(shù)據緩沖區(qū),即局部變量和函數(shù)自變量。有創(chuàng)造力的攻擊者會通過摧毀堆棧利用緩沖區(qū)溢出的弱點,然后運行任何代碼。這種想法是相當直接的:在某處插入一些攻擊代碼并以將控制傳遞給攻擊代碼的方式來覆蓋堆棧。
一般地,攻擊者利用緩沖區(qū)溢出得到機器上的交互式會話。如果被利用的程序以較高的優(yōu)先權在運行,則攻擊者就會在交互式會話中得到該優(yōu)先權。最驚人的緩沖區(qū)溢出是堆棧的摧毀,它會在超級用戶或 root、shell 中造成后果。
1.3 緩沖區(qū)溢出問題的現(xiàn)狀
據了解,大約80%的安全事件與緩沖區(qū)溢出有關。這個特別的安全問題引發(fā)的病毒感染可能比其它原因引發(fā)的病毒感染數(shù)量的總和還要多。市場上幾乎每個應用程序和操作系統(tǒng)都存在黑客可能利用的緩沖區(qū)溢出漏洞。這可能讓我們覺得很糟糕,但是最糟糕的是:這一問題不但沒有(至少到現(xiàn)在為止似乎沒有)得到很好的解決,反而有越變越糟的傾向。
第二章 緩沖區(qū)溢出的防范策略
緩沖區(qū)溢出攻擊的防范是和整個系統(tǒng)的安全性分不開的。如果整個網絡系統(tǒng)的安全設計很差,則遭受緩沖區(qū)溢出攻擊的機會也大大增加。針對緩沖區(qū)溢出,我們可以采取多種防范策略。
2.1 系統(tǒng)管理上的防范策略
(1)關閉不需要的特權程序
由于緩沖區(qū)溢出只有在獲得更高的特權時才有意義,所以帶有特權的Unix下的suid程序和Windows下由系統(tǒng)管理員啟動的服務進程都經常是緩沖區(qū)溢出攻擊的目標。這時候,關閉一些不必要的特權程序就可以降低被攻擊的風險。當有緩沖區(qū)溢出漏洞的程序還沒有補丁時,就可以用這種方法。
(2)及時給程序漏洞打補丁
這是漏洞出現(xiàn)后最迅速有效的補救措施。大部分的入侵是利用一些已被公布的漏洞達成的,如能及時補上這些漏洞,無疑極大的增強了系統(tǒng)抵抗攻擊的能力。
這兩種措施對管理員來說,代價都不是很高,但能很有效地防止住大部分的攻擊企圖。
2.2 軟件開發(fā)過程中的防范策略
發(fā)生緩沖區(qū)溢出的主要及各要素是:數(shù)組沒有邊界檢查而導致的緩沖區(qū)溢出;函數(shù)返回地址或函數(shù)指針被改變,使程序流程的改變成為可能;植入代碼被成功的執(zhí)行等等。所以針對這些要素,從技術上我們就可以采取一定的措施。
(1)編寫正確的代碼
只要我們在所有拷貝數(shù)據的地方進行數(shù)據長度和有效性的檢查,確保目標緩沖區(qū)中數(shù)據不越界并有效,則就可以避免緩沖區(qū)溢出,更不可能使程序跳轉到惡意代碼上。但是諸如C/C++自身是一種不進行強類型和長度檢查的一種程序設計語言,而程序員在編寫代碼時由于開發(fā)速度和代碼的簡潔性,往往忽視了程序的健壯性,從而導致緩沖區(qū)溢出,因此我們必須從程序語言和系統(tǒng)結構方面加強防范。
很多不安全程序的出現(xiàn)是由于調用了一些不安全的庫函數(shù),這些庫函數(shù)往往沒有對數(shù)組邊界進行檢查。所以一種簡單的方法是利用grep搜索源程序,找出對這些函數(shù)的調用,然后代以更安全的函數(shù)。進一步的查找可以是檢查更廣范圍的不安全操作,如在一個不定循環(huán)中對數(shù)組的賦值等。
可用的另一種措施是漏洞探測。利用一些工具,人為隨機地產生一些緩沖區(qū)溢出來尋找代碼的安全漏洞。已有這方面的一些高級的查錯工具,如fault injection等。
(2)緩沖區(qū)不可執(zhí)行
通過使被攻擊程序的數(shù)據段地址空間不可執(zhí)行,從而使得攻擊者不可能執(zhí)行已植入被攻擊程序輸入緩沖區(qū)的代碼,這種技術被稱為緩沖區(qū)不可執(zhí)行技術。事實上,很多老的Unix系統(tǒng)都是這樣設計的,但是近來的Unix和MS Windows系統(tǒng)為實現(xiàn)更好的性能和功能,往往在數(shù)據段中動態(tài)地放入可執(zhí)行的代碼。所以為了保持程序的兼容性不可能使得所有程序的數(shù)據段不可執(zhí)行。但是我們可以設定堆棧數(shù)據段不可執(zhí)行,這樣就可以最大限度地保證了程序的兼容性。Linux和Solaris都發(fā)布了有關這方面的內核補丁。因為幾乎沒有任何合法的程序會在堆棧中存放代碼,這種做法幾乎不產生任何兼容性問題。
(3)改進C語言函數(shù)庫
C語言中存在緩沖區(qū)溢出攻擊隱患的系統(tǒng)函數(shù)有很多。例如gets(),sprintf(),strcpy(),strcat()等??梢蚤_發(fā)出更安全的封裝了若干已知易受堆棧溢出攻擊的庫函數(shù)。修改后的庫函數(shù)實現(xiàn)了原有功能,但在某種程度上可以確保任一緩沖區(qū)溢出都被控制在現(xiàn)有堆棧幀之內。
(4)數(shù)組邊界檢查
可以說緩沖區(qū)溢出的根本原因是沒有數(shù)組邊界檢查,當數(shù)組被溢出的時候,一些關鍵的數(shù)據就有可能被修改。同時,攻擊代碼也可以被植入。
因此,對數(shù)組進行邊界檢查,使超長代碼不可能植入,這樣就完全沒有了緩沖區(qū)溢出攻擊產生的條件。只要數(shù)組不能被溢出,溢出攻擊就無從談起。
為了實現(xiàn)數(shù)組邊界檢查,則所有的對數(shù)組的讀寫操作都應當被檢查,以確保對數(shù)組的操作在正確的范圍內。最直接的方法是檢查所有的數(shù)組操作,但是會使性能下降很多,通??梢圆捎靡恍﹥?yōu)化的技術來減少檢查的次數(shù)。
(5)使堆棧向高地址方向增長
緩沖區(qū)溢出的一個重要要素是植入的代碼成功地被執(zhí)行。最常見的是被植入的代碼放在堆棧區(qū)中。通過修改操作系統(tǒng)核心,在核心層引入保護機制,限制代碼在堆棧區(qū)的執(zhí)行,這樣,緩沖區(qū)溢出攻擊就不可能成功。
到目前為止,我們討論利用函數(shù)返回地址控制程序轉移到攻擊代碼的攻擊方法時,有一個基本的前提,那就是當堆棧被壓入數(shù)據時,棧頂向低地址方向增長,只有這樣,緩沖區(qū)溢出時才可能覆蓋低地址處的函數(shù)返回地址指針,從而控制程序轉移到攻擊代碼。如果我們使用的機器堆棧壓入數(shù)據時向高地址方向前進,那么無論緩沖區(qū)如何溢出,都不可能覆蓋低地址處的函數(shù)返回地址指針,也就避免了緩沖區(qū)溢出攻擊。但是這種方法仍然無法防范利用堆和靜態(tài)數(shù)據段的緩沖區(qū)進行溢出的攻擊。
(6)程序指針完整性檢查
程序指針完整性檢查是針對上述緩沖區(qū)溢出的另一個要素——阻止由于函數(shù)返回地址或函數(shù)指針的改變而導致的程序執(zhí)行流程的改變。它的原理是在每次在程序指針被引用之前先檢測該指針是否已被惡意改動過,如果發(fā)現(xiàn)被改動,程序就拒絕執(zhí)行。
因此,即使一個攻擊者成功地改變程序的指針,由于系統(tǒng)事先檢測到了指針的改變,因此這個指針不會被使用。與數(shù)組邊界檢查相比,這種方法不能解決所有的緩沖區(qū)溢出問題。但這種方法在性能上有很大的優(yōu)勢,而且兼容性也很好。
程序指針完整性檢查大體上有三個研究方向:第一,手寫的堆棧檢測;第二,堆棧保護;第三,保護指針。
1)手寫的堆棧監(jiān)測
Snarskii為FreeBSD開發(fā)了一套定制的能通過監(jiān)測cpu堆棧來確定緩沖區(qū)溢出的libc。這個應用完全用手工匯編寫的,而且只保護libc中的當前有效紀錄函數(shù)。這個應用達到了設計要求,對于基于libc庫函數(shù)的攻擊具有很好的防衛(wèi),但是不能防衛(wèi)其它方式的攻擊。
2)堆棧保護:編譯器生成的有效紀錄完整性檢測
堆棧保護是一種提供程序指針完整性檢查的編譯器技術,通過檢查函數(shù)活動紀錄中的返回地址來實現(xiàn)。堆棧保護作為gcc的一個小的補丁,在每個函數(shù)中,加入了函數(shù)建立和銷毀的代碼。加入的函數(shù)建立代碼實際上在堆棧中函數(shù)返回地址后面加了一些附加的字節(jié)。而在函數(shù)返回時,首先檢查這個附加的字節(jié)是否被改動過。如果發(fā)生過緩沖區(qū)溢出的攻擊,那么這種攻擊很容易在函數(shù)返回前被檢測到。
3)指針保護:編譯器生成程序指針完整性檢查
在堆棧保護設計的時候,沖擊堆棧構成了緩沖區(qū)溢出攻擊的常見的一種形式。指針保護是堆棧保護針對這種情況的一個推廣。通過在所有的代碼指針之后放置附加字節(jié)來檢驗指針在被調用之前的合法性。如果檢驗失敗,會發(fā)出報警信號和退出程序的執(zhí)行,就如同在堆棧保護中的行為一樣。
(7)利用編譯器將靜態(tài)數(shù)據段中的函數(shù)地址指針存放地址和其他數(shù)據的存放地址分離
我們知道緩沖區(qū)溢出的一個基本條件是在緩沖區(qū)的高地址附近存放著可供溢出覆蓋的函數(shù)地址指針,如果我們破壞了這一條件,就會使緩沖區(qū)溢出不能覆蓋函數(shù)地址指針。比如,我們可以假定編譯器在編譯程序時會將靜態(tài)數(shù)據段中的函數(shù)地址指針存放地址和其他數(shù)據的存放地址隔開相當大的一段距離,例如數(shù)十兆,數(shù)百兆,這樣才會迫使攻擊者只有送入長的出乎想象數(shù)據才能抵達函數(shù)地址指針存放地址并覆蓋它,以這樣的不可操作性來制止攻擊者實現(xiàn)攻擊意圖。另外,我們還可以使這兩種數(shù)據段間的線形地址空間不分配物理地址并設置為不可讀寫,這些都可以通過硬件實現(xiàn),這樣每當緩沖區(qū)溢出進入這段區(qū)域,就會出現(xiàn)地址保護錯誤,從而阻止了緩沖區(qū)溢出攻擊。
另外一種較為簡潔的方法是始終保持使靜態(tài)數(shù)據段中的函數(shù)地址指針存放地址低于其他數(shù)據的存放地址。但是這個方法僅僅是防止了靜態(tài)數(shù)據段中的緩沖區(qū)溢出攻擊,而不能避免堆的緩沖區(qū)溢出攻擊,因為編譯器和操作系統(tǒng)并不知道用戶申請的內存是用來存放函數(shù)地址指針還是其他數(shù)據,從而無法為其隔離分配內存。表1是針對靜態(tài)數(shù)據段、堆棧和堆的緩沖區(qū)溢出的防范策略,其中沒有把邊界檢查包括在內,因為它能有效地防止所有的緩沖區(qū)溢出。
為了防止靜態(tài)數(shù)據段、堆棧和堆這三種數(shù)據段中的一個緩沖區(qū)溢出覆蓋另一個段中的函數(shù)地址指針,我們應該為這三種數(shù)據段隔離分配線形地址空間。
第三章 總結
緩沖區(qū)溢出是當今很流行的一種網絡攻擊方法,它易于攻擊而且危害嚴重,給系統(tǒng)的安全帶來了極大的隱患。因此,如何及時有效地檢測出計算機網絡系統(tǒng)入侵行為,已越來越成為網絡安全管理的一項重要內容。緩沖區(qū)溢出的漏洞一般有以下幾種情況:
(1)系統(tǒng)漏洞
如操作系統(tǒng)、服務器程序、數(shù)據庫程序等,這種漏洞可以通過升級軟件、打安全“補丁”等方法來解決。
(2)應用軟件
在軟件開發(fā)過程中,如果程序員沒有很強的安全意識和良好的編程習慣,也會產生很多安全漏洞。
本文從上面的系統(tǒng)環(huán)境及程序設計語言角度,對目前主要的網絡攻擊方式:緩沖區(qū)溢出攻擊的出現(xiàn)和原理進行了詳細的分析,并根據緩沖區(qū)溢出攻擊的類型提出了相應的防范策略。
然而,飛速發(fā)展的網絡技術還需要我們繼續(xù)對各種黑客攻擊系統(tǒng)的方法做更多的關注和應付措施的探索,為網絡安全做出更大的實踐意義的研究。
【參考文獻】
[1]Gary McGraw、John Viega:《使您的軟件運行起來:了解有關緩沖區(qū)溢出方面的基礎知識》
[2]劉欣、余兆力(公安部第三研究所):《fp30reg.dll動態(tài)庫存在緩存溢出》
[3]www.nsfocus.com(綠盟)