李云飛 陳洪相
摘 要:計算機網(wǎng)絡安全漏洞和網(wǎng)絡攻擊伴隨著網(wǎng)絡的存在會隨時發(fā)生,棧緩沖區(qū)溢出漏洞攻擊是網(wǎng)絡攻擊中最常見的一種攻擊技術。文章剖析了Windows棧工作原理,以及棧溢出漏洞攻擊技術方法,針對常見的棧溢出漏洞攻擊提出了幾種防御措施,能預防大部分針對棧溢出漏洞的攻擊。
關鍵詞:網(wǎng)絡安全;內存;安全漏洞;堆棧;緩沖區(qū)溢出
中圖分類號:TP309.1 文獻標識碼:A
Abstract:Computer network security vulnerabilities and cyber attacks may occur at any time on the Internet,and the stack buffer overflow attack is the most common network attack technology.This paper analyzes the operating principle of the stack in Windows and the techniques of stack overflow attacks.Then,several prevention measures are proposed for common stack buffer overflow attacks,which can prevent most stack overflow attacks.
Keywords:network security;memory;security vulnerabilities;stack,buffer overflow
1 引言(Introduction)
緩沖區(qū)是已分配的一段大小確定的用于臨時存放數(shù)據(jù)的內存存儲區(qū)。當向一個已經分配了確定內存空間的緩沖區(qū)內寫入超出該緩沖區(qū)處理能力的數(shù)據(jù)時,將發(fā)生緩沖區(qū)溢出[1]。
近十年,以緩沖區(qū)溢出為類型的安全漏洞攻擊是最為常見的一種形式,在網(wǎng)絡與分布式系統(tǒng)安全中,50%以上的漏洞攻擊都是基于緩沖區(qū)溢出技術的,尤其在不進行邊界檢查的C/C++程序中仍然是軟件可靠性和安全性的主要威脅之一[2]。
利用緩沖區(qū)溢出攻擊,可以導致程序運行失敗、重新啟動、執(zhí)行惡意代碼等后果。緩沖區(qū)溢出中最危險的是棧溢出,因為入侵者可以利用堆棧溢出,在函數(shù)返回時改變返回程序的地址,讓其跳轉到任意地址,更為嚴重的是,它可被利用來執(zhí)行非授權指令,甚至可以取得系統(tǒng)特權,進而進行各種非法操作[3]。
2 Windows棧緩沖區(qū)溢出原理(The principle of
stack buffer overflow in Windows)
2.1 Windows內存程序結構
計算機運行時,必須首先把程序從外存裝載到內存,然后由CPU從內存中依次讀取執(zhí)行指令。正在運行的程序叫進程,每個進程都有自己的獨立內存空間,它被分成幾個段(Segment),分別是代碼段(text)、數(shù)據(jù)段(data,bss)、堆(heap)、棧(stack)等,如圖1所示。用戶進程的內存空間,也是系統(tǒng)內核分配給該進程的虛擬內存。內存總是被進程占用,但并不表示這個進程占用了這么多的物理內存,Windows將虛擬內存地址映射到各進程的物理內存地址上,進程內存空間隨著程序的執(zhí)行會增大或者縮小[4]。
堆和棧都是一種數(shù)據(jù)項按序排列的數(shù)據(jù)結構。
棧是一種先進后出的數(shù)據(jù)結構,是自動開辟空間,用來分配局部變量、類的引用(指向堆空間段),棧使用的是一級緩存,通常在被調用時處于存儲空間中,調用完畢立即釋放。
堆是一種經過排序的數(shù)據(jù)結構,每個結點都有一個值,可以被看成是一棵樹,堆的存取是隨意的,堆是存放在二級緩存中,生命周期由虛擬機的垃圾回收算法來決定。堆的特點是根結點的值最?。ɑ蜃畲螅?,且根結點的兩個子樹也是一個堆。由于堆的這個特性,常用來實現(xiàn)優(yōu)先隊列。
bss段(Block Started by Symbol segment)通常是指用來存放程序中未初始化的全局變量的一塊內存區(qū)域,屬于靜態(tài)內存分配,程序一開始就將其清零了。
對于一個進程的內存空間而言,可以在邏輯上分成三個部分:代碼區(qū)、靜態(tài)數(shù)據(jù)區(qū)和動態(tài)數(shù)據(jù)區(qū)。動態(tài)數(shù)據(jù)區(qū)一般就是堆棧。進程的每個線程都有私有的棧,所以每個線程雖然代碼一樣,但本地變量的數(shù)據(jù)都是互不干擾。全局變量和靜態(tài)變量分配在靜態(tài)數(shù)據(jù)區(qū),本地變量分配在動態(tài)數(shù)據(jù)區(qū),即堆棧中。程序通過堆棧的基地址和偏移量來訪問本地變量[5]。
32位系統(tǒng)中經典的內存布局是:程序起始1GB地址為內核空間,接下來是向下增長的??臻g和由0×40000000向上增長的內存映射地址。而堆地址是從底部開始,去除ELF(Executable and Linking Format)、代碼段、數(shù)據(jù)段、常量段之后的地址并向上增長,這種布局導致了緩沖區(qū)容易遭受溢出攻擊[6]。
2.2 Windows棧緩沖區(qū)溢出原理
Windows程序的執(zhí)行流程由代碼段ECS和指令指針EIP控制,EIP始終指向下一條要執(zhí)行指令的地址。當發(fā)生中斷或要調用子程序時,需要將當前斷點信息入棧保存,然后轉去執(zhí)行中斷子程序,執(zhí)行完中斷子程序后返回指令將棧頂內容出?;謴蛿帱cECS和EIP。
這種控制流程看似簡單,只需將指令地址按序給ECS和EIP即可,但就是因為這簡單的控制而不容許有任何地址計算差錯。如果其他緩沖區(qū)溢出會導致多余的數(shù)據(jù)覆蓋其他有用內存空間,其中如果將棧內數(shù)據(jù)覆蓋就可能導致修改入棧保存的ECS和EIP,從而使得程序返回時跑飛。
當一個函數(shù)被調用時,函數(shù)參數(shù)、EIP、ECS(段間調用時)、EBP和函數(shù)局部變量會依次壓棧保存,如圖2所示。endprint
定義變量和正常調用時如圖3(a)和圖3(b)所示,但當把遠大于10個字符的內容(如字符"B")拷貝到為緩沖區(qū)分配的10個字符空間時,多于10個字符的內容就會覆蓋掉EBP和ECS:EIP,如圖3(c),函數(shù)執(zhí)行完畢后返回的地址就已經不是原來保存的正確地址了。
如果溢出部分的數(shù)據(jù)量足夠大或經過攻擊者的精心設計,就可能覆蓋返回地址,從而改變程序的執(zhí)行流程,將程序的返回地址修改成其想執(zhí)行的代碼地址,達到攻擊目的。
出現(xiàn)緩沖區(qū)溢出的情況主要包括三種:
(1)使用非類型安全的語言。緩沖區(qū)溢出主要出現(xiàn)在C和C++語言中,雖然C/C++語言可以允許程序員直接訪問內存和CPU的寄存器,從而創(chuàng)建非常接近硬件運行的性能優(yōu)異、運行速度快程序,但C/C++語言不執(zhí)行數(shù)組邊界檢測和類型安全檢查,所以在進行數(shù)組、字符串操作時容易造成緩沖區(qū)溢出[7]。
(2)以不安全的方式訪問或操作緩沖區(qū)。如果應用程序需要獲得數(shù)據(jù),當用戶將數(shù)據(jù)復制到應用程序所指定的緩沖區(qū)而未考慮目標緩沖區(qū)的大小時,就可能造成緩沖區(qū)溢出。
(3)編譯器將緩沖區(qū)放在內存中關鍵數(shù)據(jù)結構旁邊或鄰近的位置。
3 Windows棧緩沖區(qū)溢出攻擊防范(The prevention
methods of stack buffer overflow attacks
Windows)
在棧溢出的檢查與防范方面,許多軟硬件廠商已經做了大量工作,如微軟在Visual Studio中增加編譯選項來檢測棧的溢出,在Windows系列操作系統(tǒng)中增加了SEHOP (Structured Exception Handling Overwrite Protection),阻止修改SEH增強系統(tǒng)的安全性,硬件方面,64位CPU引入了NX(No-eXecute)機制,在內存中區(qū)分數(shù)據(jù)區(qū)與代碼區(qū),當攻擊者利用溢出使CPU跳轉到數(shù)據(jù)區(qū)去執(zhí)行時,就會異常終止等[8]。
但對大量現(xiàn)有軟硬件資源,若要都升級或更新到最新的軟硬系統(tǒng)是一件很困難的事,而且不斷有繞過防御機制的新漏洞產生,攻擊方法也在不斷地發(fā)展變化。所以日常工作中的防御措施相當必要,針對不同的攻擊原理和方法,也可以靈活采用各種技術進行針對性的防御。
緩沖區(qū)溢出攻擊防范是和整個系統(tǒng)的安全性分不開的。除了系統(tǒng)管理上采用諸如關閉危險的特權程序,及時下載系統(tǒng)或軟件的最新補丁,使用安全產品等措施之外,軟件開發(fā)過程中的防范才是從根源上解決問題的渠道,常用的方法主要有幾種[9]。
3.1 GS編譯選項
Windows在Visual Studio 7.0(Visual Studio 2003)及以后版本中添加了一個針對函數(shù)的棧緩存溢出安全編譯選項——GS,來增加棧溢出的難度。
GS編譯選項的原理就是在堆棧上插入一個安全cookie,以測試堆棧上的返回地址是否被修改過。安全cookie為四個字節(jié),在堆棧上的位置如圖4和圖2的傳統(tǒng)內存結構相比,GS編譯選項會增加四個字節(jié)的堆棧空間。
如果是堆棧的局部變量發(fā)生緩存溢出的錯誤而導致返回地址被覆蓋的話,由于安全cookie所在的位置,它也一定會被覆蓋。GS編譯選項在函數(shù)的入口和出口添加了針對安全cookie操作的指令,如果發(fā)現(xiàn)安全cookie的值被改動就會轉入異常處理終止程序運行。
如果堆棧上的安全cookie的值和security_cookie的值一致的話,那么函數(shù)正常退出,否則就會執(zhí)行錯誤處理程序。
3.2 軟件開發(fā)過程防范
發(fā)生棧緩沖區(qū)溢出的主要原因是軟件程序中使用了不規(guī)范的數(shù)據(jù)操作或惡意代碼攻擊,所以在軟件的編寫過程中注意規(guī)范的代碼審查,是杜絕緩沖區(qū)溢出的最直接因素。
(1)規(guī)范代碼編寫規(guī)則
C和C++開發(fā)工具不是為安全而設計的,屬于非類型安全語言,為了保證編程的靈活性,C/C++的一些庫函數(shù)(如strcpy(、gets()等))缺乏邊界檢測,如果調用時輸入的參數(shù)過長,就會導致緩沖區(qū)溢出。所以在使用C/C++開發(fā)工具編程時,都應該有針對性地進行安全性測試和代碼審查。
①數(shù)組邊界檢測。C語言不進行數(shù)組邊界檢測,容易產生超長數(shù)據(jù)操作植入代碼,導致緩沖區(qū)溢出。當在編譯時檢查所有的數(shù)組讀寫操作,確保對數(shù)組的操作都在有效范圍內。
目前的C程序編譯調試檢測提供了許多檢測工具,主要對存儲器存取檢測、數(shù)組邊界檢查。譬如Purify使用目標插入代碼技術檢查可執(zhí)行代碼在執(zhí)行時數(shù)組的所有應用來保障數(shù)組的合法使用,但程序的性能不可避免地要受到影響。
但由于所有的C數(shù)組在傳送時是按指針傳送的,所以傳遞給調用函數(shù)的數(shù)組不會被檢查。例如庫函數(shù)strcpy()、strcat()、gets()等函數(shù),在編譯時不會進行邊界檢查。
②指針完整性檢查。程序的指針完整性檢查在程序指針被引用之前檢查其是否被改變,即使攻擊者成功改變了程序指針,由于系統(tǒng)提前檢測到了該改變而不執(zhí)行該指針,所以該方法在防范緩沖區(qū)溢出方面性能比較好。
程序指針完整性檢查是在函數(shù)返回地址或者其他的關鍵數(shù)據(jù)、指針之前插入防范值,或者存儲一個返回地址、關鍵數(shù)據(jù)或指針的備份,在函數(shù)返回時進行比較。
③改進C庫函數(shù)。C語言產生緩沖區(qū)溢出的根本是調用一些庫函數(shù)時不對數(shù)據(jù)進行邊界檢測,比如strcpy()gets()、strcat()、scanf()、printf()等,所以在用到該類型的庫函數(shù)時,可以開發(fā)更安全的替代函數(shù)實現(xiàn)該部分功能,并對其進行安全檢查調用,防范緩沖區(qū)溢出。
(2)棧的不可執(zhí)行技術
Windows系統(tǒng)為了實現(xiàn)更好的性能和功能,往往在數(shù)據(jù)段中動態(tài)地插入可執(zhí)行的代碼,這樣當緩沖區(qū)發(fā)生數(shù)據(jù)溢出時就會覆蓋數(shù)據(jù)段,從而可能導致數(shù)據(jù)段中的可執(zhí)行代碼被修改。所以為了防止這種緩沖區(qū)溢出產生攻擊,可以使被攻擊程序的數(shù)據(jù)段地址空間不可執(zhí)行,從而使得攻擊者不可能執(zhí)行被植入攻擊程序的緩沖區(qū)代碼。endprint
為了保持程序的兼容性不可能將所有程序的數(shù)據(jù)段設為不可執(zhí)行,但可以在必要的時候將堆棧數(shù)據(jù)段設為不可執(zhí)行,因為幾乎沒有程序會在堆棧中存放代碼,所以這樣既可以最大限度地保證程序的兼容性,也可以有效地保證棧緩沖區(qū)溢出攻擊。
(3)備份關鍵控制信息
棧溢出攻擊程序最致命的攻擊就是將程序流程的EIP和ECS內容修改,導致原程序流程不能正常執(zhí)行。如果在調用程序或入棧時,將斷點的EIP和ECS自動入棧的同時,用另外申請的靜態(tài)或動態(tài)數(shù)組將程序流的關鍵信息如EIP和ECS備份保存,當出棧返回程序斷點時,用備份的信息和棧中的信息進行比對,如果發(fā)現(xiàn)不一致則認為棧內容被修改,這時可以做出中斷檢測處理,防止進入攻擊代碼。
3.3 棧溢出檢測防范技術
(1)漏洞特征檢測
漏洞都有一定的觸發(fā)條件,其攻擊過程就是構造外部輸入使之滿足觸發(fā)條件,針對棧溢出漏洞的攻擊觸發(fā)條件就是要注入超過系統(tǒng)邏輯計劃存儲的數(shù)據(jù)長度。根據(jù)漏洞的攻擊特性系統(tǒng)會建立一個特征信息庫并動態(tài)更新,當程序執(zhí)行過程中系統(tǒng)會針對該信息庫進行網(wǎng)絡流量檢測,當發(fā)現(xiàn)有類似特征代碼就會及時采取有效措施或阻止,避免發(fā)生棧溢出漏洞攻擊。
(2)攻擊特征檢測
漏洞需要被攻擊者發(fā)現(xiàn)并利用才能被安全機構通過特征進行檢測,這需要觸發(fā)條件或可能經過很長時間才能被發(fā)現(xiàn)。為了及時防御該類溢出攻擊,可以根據(jù)攻擊的特點進行有針對性的防御。
棧溢出注入數(shù)據(jù)的長度與內容隨著漏洞的不同而有所差異,但攻擊者攻擊時所使用的跳轉地址卻是常用或者比較固定易用的一些地址。由于不同平臺下的shellcode一般都會重復利用。所以棧溢出攻擊手法會具有一定的特征,通過提取這些頻繁出現(xiàn)的特征對防御設備的攻擊特征庫及時更新,可以有效阻止棧溢出攻擊發(fā)生。
(3)虛擬檢測技術
防御設備最理想的情況是可以虛擬出一個除了數(shù)據(jù)不同其他均相同的虛擬機,通過在虛擬系統(tǒng)中插入檢測點,檢測系統(tǒng)某一進程完成后的現(xiàn)場跟蹤進程的運行狀態(tài)。如果進程的操作沒有異常,后臺再把操作重定向到真實的進程去處理,把真實數(shù)據(jù)返回給用戶,否則可以阻止其對真實系統(tǒng)的訪問。
4 結論(Conclusion)
計算機網(wǎng)絡攻擊幾乎每時每刻都會發(fā)生,攻擊的方式變化多樣且會隨著防御技術的變化而不斷變化,所以對網(wǎng)絡攻擊的防御是個長期的持久戰(zhàn)。本文提出的攻擊原理和防御技術能有效地阻止大部分棧溢出攻擊,但攻擊技術在不斷地發(fā)展,我們還需要根據(jù)新的攻擊技術研究設計更有效的防御技術。
參考文獻(References)
[1] Nashimoto S,et al.Buffer overflow attack with multiple fault injection and a proven countermeasure[J].Journal of Cryptographic Engineering,2016,7(1):1-12.
[2] Sui Y,et al.Eliminating Redundant Bounds Checks in Dynamic Buffer Overflow Detection Using Weakest Preconditions[J].IEEE Transactions on Reliability,2016,65(4):1682-1699.
[3] Wang X,et al.A Differential Approach to Undefined Behavior Detection[J].Acm Transactions on Computer Systems,2015,
33(1):1.
[4] 肖蕾,劉克江.一種微型嵌入式系統(tǒng)動態(tài)內存分區(qū)管理機制的研究[J].軟件工程,2016,19(4):59-60.
[5] 崔寶江,等.基于污點信息的函數(shù)內存模糊測試技術研究[J].清華大學學報(自然科學版),2016(1):7-13.
[6] 彭建山,等.基于指針時空分析的軟件異??衫眯耘卸╗J].計算機應用研究,2016,33(5):1504-1508.
[7] 謝汶兵,等.基于備份控制流信息的緩沖區(qū)溢出監(jiān)測技術[J].計算機工程與應用,2016,52(11):101-107.
[8] Jaiswal S,Gupta D.Security engineering methods-in-depth analysis[J].International Journal of Information & Computer Security,2017,9(3):180.
[9] Howard M,Lipner S.The security development lifecycle:SDL,a process for developing demonstrably more secure software[J].Datenschutz und Datensicherheit-DuD,2015,34(3):135-137.
作者簡介:
李云飛(1974-),男,博士,副教授.研究領域:信息安全,嵌入式系統(tǒng),模式識別.
陳洪相(1974-),男,本科,高級教師.研究領域:計算機應用,軟件開發(fā).endprint