?

緩沖區溢出安全編程教與學

2017-07-10 07:32劉浩賀文華彭智朝賀勁松
電腦知識與技術 2017年14期
關鍵詞:堆棧

劉浩+賀文華+彭智朝+賀勁松

摘要:緩沖區溢出是一種非常普遍、非常危險的漏洞,常被黑客和病毒利用,是信息安全的重要隱患之一。因此,在“信息安全理論與技術”課程教學中,緩沖區溢出安全編程的教與學一直受師生們的重視?;诰彌_區溢出的工作原理與攻擊技術,通過師生共同探討,給出了一些關于C語言程序編寫過程中防御緩沖區溢出的方法,以提高安全編程能力。

關鍵詞:緩沖區溢出;堆棧;安全編程;Bss;heap

中圖分類號:TP309 文獻標識碼:A 文章編號:1009-3044(2017)14-0102-04

1概述

自從二十世紀末以來,由于其破壞性大與廣泛性,緩沖區溢出漏洞得到了信息安全領域學者們的普遍關注。當前,相關研究統計表明,全球每年發生的安全威脅事件以指數增長。由于緩沖區溢出漏洞不受操作系統不同的限制、能作用于不同的應用程序之上,作為網絡攻擊一種主要形式,緩沖區溢出攻擊次數超過了所有網絡系統攻擊總數的五分之四。

在程序設計中,緩沖區就是應用程序用來保存用戶輸入數據和代碼的臨時數據的內存空間。作為一種系統攻擊的手段,緩沖區溢出(Buffer Overflow),就是在程序中的緩沖區內寫入超出正常長度的內容,使緩沖區產生溢出,破壞程序的堆棧,讓程序跳轉去執行別的指令,從而達到系統攻擊的目標。

正常情況,利用緩沖區溢出漏洞攻擊者并不只是想讓程序本身崩潰,而是想通過這種攻擊來達到提升權限,獲得對系統更多的訪問和控制權。一般而言,緩沖區溢出本身并不會導致系統安全問題,但如果該溢出能夠跳轉到以超級權限(如root權限)運行命令的區域,使程序去運行一個shell或執行某些特權代碼,那么該程序將以超級用戶的權限控制了計算機系統。顯然,緩沖區溢出漏洞是計算機系統的重大安全隱患。緩沖區溢出的根本原因就是程序設計時沒有考慮用戶輸入參數與運行邊界的相關檢查。

當應用程序運行時,其內存中的映像被分為數據段、代碼段以及堆棧段三個部分。數據段包括運行文件中的BSS Sec-tion與Data Section,其用于存放程序運行的靜態變量與各種數據。代碼段就是運行文件中的Text Section(圖1),其中包括只讀數據與運行代碼。一般該段在內存中被標記為只讀,所有企圖修改該數據的指令都將引發一個Segmentation Violation錯誤。

具體到C程序中,如圖1所示,.stack、.heap、.bss以及.data區都被分配在緩沖區,并且和程序執行流相關的函數返回地址、函數指針等數據結構也會被分配在區域,因此,一旦發生到緩沖區溢出攻擊時,控制程序執行流的敏感數據結構則有可能發生改變,將導致正在執行的程序發生轉向,從而去執行非法代碼。

依據程序數據在內存中增長方式的不同,緩沖區溢出可分堆溢出和棧溢出兩種情況。所謂堆溢出,就是數據分配從低地址向高地址方向增長,溢出點可能發生在.bss、.daat、.heap區,基于堆溢出的攻擊有覆蓋分配在該區域的函數指針等。反之,棧溢出就是數據分配從高地址向低地址方向增長,溢出點發生在.stack區,基于棧溢出的攻擊有覆蓋函數返回地址等。

在模塊化程序設計中,各種函數調用會經常出現,如調用Win32 API、C運行庫等。并且編譯器幾乎都會將這些調用編譯為Call語句,執行該指令時,IP被設為調用函數的入口地此,調用后的返回地址會被壓入堆棧,而且針對函數調用帶有的局部變量與入口參數,這些數據也會被編譯器生成為一些指令存入堆棧(也有通過寄存器傳遞的)。通常稱因一個函數調用所導致必需在堆棧中存放的返回地址與相關數據等構成一個堆棧幀(Stack Frame)。

2緩沖區溢出基本原理

緩沖區溢出攻擊的基本原理就是向程序中輸入超出正常長度的內容,由于越過緩沖區長度界限造成緩沖區的溢出,程序的堆棧會被破壞而出現特殊的問題,使程序運行跳轉去執行其它指令。

下面我們舉一個緩沖區溢出例子來說明其基本原理:

首先我們看一下未執行strcpy時(已經調用函數funcl)堆棧中的情況(如圖2所示)。

該程序是一個典型的緩沖區溢出編碼錯誤。并沒有經過邊界檢查,函數將一個字符串拷貝至另一內存區域。在執行strcpy時,256字節的‘A(ox41)被程序拷入buffer中,但是buffer的長度只有16字節,那么buffer后面的240字節內容將被覆蓋掉,這些字節包括RET地址、EBP、large_string地址。字符‘A的十六進制為0×41,因此函數的返回地址被變為了0×41414141,明顯超出了程序的地址空間,所以系統將報“Segmentation Vio-lation”錯誤。這就是所謂的緩沖區溢出。

3緩沖區溢出攻擊方式

當非法用戶操作程序時,若所進行的操作超出了程序的運行范圍,程序所用的數據會被添加到分配給該緩沖區內存塊之外,將導致緩沖區溢出,這時候就會出現數據泄漏或侵占其它的數據空間。

1)向緩沖區寫人超出正常長度的字符。

如上例通過向緩沖區中寫入超出正常長度的字符來產生緩沖區溢出,導致程序崩潰。

2)攻擊者可用任意數據覆蓋堆棧中變量的內容。

安全漏洞的一個經典例子是基于口令的認證,首先從本地數據庫中讀取口令并存儲在本地變量中,然后用戶輸入口令,程序比較這兩個字符串,從而比較結果為二者相等。

3)覆蓋堆棧中保存的寄存器。

通過輸入超長的字符從而覆蓋指令指針IP,攻擊者可以利用函數結尾的RET來執行程序中的任意程序代碼。一般而言,不是利用程序本身的代碼,而是植入攻擊者自己的機器代碼(一般稱之為Shellcode,即外殼代碼)。為此把機器代碼寫到變量中并復制到堆棧中,把保存的IP地址改變為攻擊代碼的開始地址。當函數執行完畢返回時,RET從堆棧中獲得IP的值并寫入CPU的IP寄存器,于是運行攻擊代碼。

4)覆蓋函數指針以執行第三方代碼。

攻擊者把機器代碼Shellcode放在一全局或本地變量或編程環境中,并使函數指針指向這段程序代碼。當用函數指針調用函數時,執行的將不是函數代碼而是攻擊代碼。

4安全編程

1)編寫正確的代碼

前面提到過,解決緩沖區溢出問題的第一步是,人們必須更加小心地進行計算機的編程。程序員只要增加能夠處理過長字符串的指令,就能夠防止對自己產品的攻擊。下面我們共同探討容易導致緩沖區溢出的系統調用,并給出正確的、安全的使用方法。

①gets(char*s)

本函數的功能是從標準輸入來讀入數據到靜態緩沖區中,有名的bug是Morris Internet Worm在fingerd中開發的,利用此漏洞可通過網絡在計算機上執行命令。正確的fgets(char *s,im size,FILE*stream)使用方式是通過嚴格規定輸入數據長度從而安全的讀取數據。如本例中通過使用sizeof(Array Buff)等指定數據長度,如12字節,fgets()將讀入1~12個字節并在最后加一個NULL字符。

然而,實際編程中程序員容易把整個if語句直接寫成了i++的錯誤編程方式。

如前所述,還有很多函數不進行邊界檢查,包括scanf(3)、strcpy(3)/strcat(3)、getwd(3)等等,在此不再一一敘述,請同學們自行探索研究。

所謂靜態發現技術,就是為了降低程序被攻擊的可能性,在程序設計過程中,根據一定的約束規則來發現源碼里潛在的漏洞之處,便于程序員發現并改進。顯然使用靜態發現技術,系統需要維護一個不斷更新的與漏洞有關的規則庫。靜態發現技術常用的工具有BOON、Flawfinder、ITS4、RAST等。

2)使用Libsafe

朗訊技術公司的Arash Baratloo、Timothy Tsai和Navjot Singh等針對這些易受緩沖區溢出攻擊的Libc函數進行二次開發,開發出了封裝這些庫函數的動態載入庫Libsafe[4],來解析那些不安全的Libc庫函數,并用Libsafe中實現的安全函數替代,讓Libsafe實現邊界檢查,以達到確保任一緩沖區溢出都被控制在堆棧幀之內,從而保證了代碼的安全,解決了緩沖區溢出攻擊問題。

3)不可執行的緩沖區技術

根據緩沖區溢出的基本原理,所謂不可執行的緩沖區技術,就是使可能被攻擊程序的數據段地址空間不可執行,植入到被攻擊程序輸入緩沖區中的代碼不可能被非法用戶執行。

合法程序并不需要在堆棧中存放可執行代碼,因此完全可以讓操作系統使程序的堆棧段不可執行。目前,Solaris與Linux為此發布了安全補丁。正常情況下,合法程序幾乎都不會在堆棧中存放代碼,那么這種做法也就不會產生有關兼容性方面的問題。然而Linux系統中有特例的情況,其可執行的代碼必須被存放在堆棧中,在此不再一一敘述,請同學們自行探索研究。

不可執行緩沖區技術能夠有效地抑制把代碼植入自動變量的緩沖區溢出攻擊,但是對于其它形式的攻擊卻無效果。

4)數組邊界檢查

根據緩沖區溢出的基本原理可知,要實現緩沖區溢出攻擊則需要改變程序的執行流程,使程序代碼不按約定的流程執行。如果給局部變量分配的內存空間沒被溢出,改變程序運行狀態也就無從談起。為此,我們可以利用一些編譯器或工具對程序進行數組邊界檢查,就是在對數組進行讀寫操作時,必須將對數組的操作控制在正確的內存范圍內。最簡單的方法就是檢查所有對數組的操作。當前,Paul Kelly與Richard Jones聯合開發的GCC補丁、Purify以及Compaq C編譯器等都能實現對數組邊界的檢查功能。

5)程序指針完整性檢查

相對于邊界檢查,所謂程序指針完整性檢查,就是在程序指針被引用之前檢測它是否有改變。若非法用戶改變了程序的指針,并且系統事先檢測到了指針的改變,那么該指針將不會再使用。目前有以下三個研究方向。

FreeBSD系統有一套能通過監測CPU堆棧來確定緩沖區溢出的libc,可有效地保護libc中當前有效的記錄函數,有效地防衛了基于libc庫函數的攻擊,然而不能抑制其它方式的攻擊。

StackGuard通過不允許改動活動函數的返回地址RET來防止某些類型的緩沖區溢出攻擊。實現方式有函數返回前檢測返回地址RET的改動和禁止對返回地址RET寫。分析與實驗數據表明,對于各種系統的緩沖區溢出攻擊,StackGuard都有很好的保護作用,并具有較好的系統性能與兼容性。并且,StackGuard能有效抵御各類不同基于堆棧的攻擊。

PointGuard通過在所有的代碼指針之后放置附加字節來檢驗指針在被調用之前的合法性,實質上是StackGuard的推廣。此外動態防御技術還有ProPolice、StackShield、PaX等。

5結束語

作為一種危害性大、應用廣的安全漏洞,緩沖區溢出攻擊被非法用戶廣泛應用于不同的操作系統與應用軟件中。通過緩沖區溢出攻擊,能導致程序運行失敗、重新啟動以及系統當機等后果。尤其是若利用它執行非授權指令,非法用戶甚至能夠取得系統特權,進而執行一些非法操作。由于這種攻擊能使得非法用戶完全控制某一臺主機,因此構成了對計算機系統很大的安全威脅與隱患。

在“信息安全理論與技術”課程教學中,我們十分重視緩沖區溢出安全編程的教與學。通過分析緩沖區溢出的基本原理和攻擊技術,師生共同探討,舉一反三,理論與上機操作相結合,提出了一些在C語言程序編寫過程中防御緩沖區溢出的方法,以提高學生安全編程能力和軟件開發水平。

猜你喜歡
堆棧
基于行為監測的嵌入式操作系統堆棧溢出測試*
基于SpringBoot結果集序列化過濾插件的研究與實現
Stacking算法在醫療健康數據中的應用研究
應用EDAC容錯技術的星載軟件堆棧溢出實時檢測方法
嵌入式軟件堆棧溢出的動態檢測方案設計*
基于堆棧自編碼降維的武器裝備體系效能預測
一種航天器軟件進程堆棧使用深度的動態檢測方法
多邊形圖形的環狀掃描線種子填充算法
一種用于分析MCS-51目標碼堆棧深度的方法
Cx51程序設計的堆??臻g計算方法
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合