趙暉
(山東理工大學(xué),山東 淄博255000)
隨著Internet 網(wǎng)絡(luò)規(guī)模的不斷擴大,各種軟件硬件的應(yīng)用不斷加入,隨著互聯(lián)網(wǎng)深入政治、經(jīng)濟、民生乃至軍事的各個方面,安全漏洞不開避免,安全更是不能忽視的。安全漏洞是指程序代碼、協(xié)議、硬件在功能實現(xiàn)上的一種缺陷。漏洞一旦被攻擊者發(fā)現(xiàn),就可以使目標(biāo)機器拒絕服務(wù)(宕機)、在未授權(quán)的情況下執(zhí)行任意代碼、從一個比較低的權(quán)限獲取更高的權(quán)限,用戶的信息安全不能夠得到保障。
近些年以來,軟件數(shù)量和種類在不斷的增加,軟件的代碼量也在不斷地增加,漏洞挖掘就比較重要了。當(dāng)前,軟件漏洞挖掘技術(shù)正在不斷朝著高度自動化、智能化的方向進(jìn)行發(fā)展,以模糊測試為代表的軟件漏洞挖掘技術(shù)更是成為研究的熱點。
程序在運行的時候,每個函數(shù)都有一個函數(shù)運行棧,在棧中保存了函數(shù)運行時所使用的臨時變量、緩沖區(qū)等信息,函數(shù)運行棧的范圍通過基地址寄存器(EBP/RBP)跟棧頂寄存器(ESP/RSP)框定。棧上除了臨時變量外還有函數(shù)運行時緩沖區(qū)、函數(shù)運行時參數(shù),在他們中間還有一個值是返回地址,這個地址一般表示為該函數(shù)執(zhí)行完以后要執(zhí)行的匯編指令的地址,如果這個值被攻擊者惡意覆蓋以后,就可以控制指令指令指針寄存器(EIP/RIP),就可以控制代碼流,就可以做到執(zhí)行任意代碼。在使用一些輸入函數(shù),比如gets()、read()、scanf()等函數(shù)時,如果沒有對輸入字符串長度進(jìn)行驗證,就會發(fā)生溢出。
在計算機中,堆與棧雖然都是用來保存數(shù)據(jù)的內(nèi)存區(qū)域,但是這兩個內(nèi)存區(qū)域區(qū)別很大而且棧空間的生命周期是在函數(shù)運行時,但是堆內(nèi)存空間可以貫穿在整個程序運行周期內(nèi)。假設(shè)程序申請了0x10 的堆內(nèi)存空間,但是輸入0x50 長度的字符串,因此可以導(dǎo)致溢出。但是堆內(nèi)存空間中沒有相關(guān)數(shù)據(jù)、函數(shù)指針,因此該例子并不能劫持程序流,也就意味著程序可能會正常退出,一般方法無法捕獲到該漏洞。
單獨的整數(shù)溢出漏洞,但是整數(shù)溢出漏洞,往往會產(chǎn)生堆棧溢出漏洞,整數(shù)溢出漏洞的產(chǎn)生往往是對變量定義不嚴(yán)格導(dǎo)致。
漏洞挖掘技術(shù)主要有以下幾種方法:(1)靜態(tài)審計,這種方法十分依賴經(jīng)驗,而且需要耗費大量的精力;(2)靜態(tài)分析,這種技術(shù)不用運行目標(biāo)程序就可以發(fā)現(xiàn)漏洞,但是存在較高的誤報率;(3)污點分析跟符號執(zhí)行,這兩項技術(shù)需要較大的性能開銷,而且程序越大,對性能的開銷越大,因此在工業(yè)中的應(yīng)用存在較大的局限性;(4)模糊測試,通過傳入畸形數(shù)據(jù),檢測程序行為,從而發(fā)現(xiàn)漏洞。
因為模糊測試對系統(tǒng)性能開銷低效率高,因此在工業(yè)界應(yīng)用廣泛。
Fuzzing 技術(shù)是一種自動或者半自動化的軟件漏洞挖掘技術(shù),通過向目標(biāo)程序(文件處理、協(xié)議處理、API)注入畸形數(shù)據(jù)或者其他非預(yù)期輸入,程序在解析這些文件或者數(shù)據(jù)時,因為預(yù)定義類型的問題,可能會導(dǎo)致解析結(jié)果與預(yù)期不一致,但是仍能通過一些程序的條件判斷,因此就會出現(xiàn)異常的行為、輸出,因此可以發(fā)現(xiàn)漏洞,與手工分析的區(qū)別是,fuzz 技術(shù)是一種半自動化技術(shù),只需要用戶指定被測程序,并提供輸入樣本就可以自動化的執(zhí)行目標(biāo)程序,并將樣本輸入到程序中,效率非常高。
主流fuzz 平臺設(shè)計一般有以下幾種類型:
基于變異:根據(jù)已知數(shù)據(jù)樣本通過隨機數(shù)據(jù)變異的方法進(jìn)行fuzz。例如AFL。
基于生成:根據(jù)已知協(xié)議接口或規(guī)范進(jìn)行建模生成測試用例。例如Syzkaller。
基于機器學(xué)習(xí):神經(jīng)網(wǎng)絡(luò)輸入的隨機突變由覆蓋度量指導(dǎo)。
基于符號執(zhí)行:將輸入進(jìn)行符號化,對于所有可能的路徑進(jìn)行約束求解,從而達(dá)到更好的代碼覆蓋率,增大發(fā)現(xiàn)漏洞的概率。但是符號執(zhí)行雖然在理論上可行,但是在實際系統(tǒng)中存在大量的路徑分支,路徑爆炸的問題很難解決。
插樁模塊:依據(jù)編譯原理,在編譯時,對目標(biāo)程序基本塊進(jìn)行插裝,以便目標(biāo)程序向fuzz 系統(tǒng)反饋樣本能夠觸發(fā)的路徑信息,程序運行狀態(tài)信息,以及程序退出信息。
監(jiān)控模塊:fuzz 程序根據(jù)目標(biāo)程序反饋的路徑信息判斷被測樣本是否有效,以及可以出發(fā)的路徑數(shù)量;根據(jù)反饋的程序退出信息,判斷程序是正常退出還是因為觸發(fā)了內(nèi)存破壞漏洞等原因?qū)е峦顺觥?/p>
變異模塊:fuzz 程序結(jié)合目標(biāo)程序反饋的路徑信息,對文件的關(guān)鍵字段進(jìn)行變異,以增加代碼覆蓋率。
forkserver 模塊:該模塊主要是為了啟動被fuzz 程序的子進(jìn)程,通過forkserver 模型,可以減少系統(tǒng)性能與內(nèi)存開銷。
插樁模塊,將實現(xiàn)特定功能的匯編指令插入到程序的每一個基本塊中;路徑信息反饋模塊通過插樁模塊插入到被fuzz 程序中,并通過共享內(nèi)存與主fuzz 進(jìn)程通信;變異模塊主要是通過啟發(fā)式算法檢測出文件token,其余的策略基于效率考慮的數(shù)據(jù)變異,主要是為了讓程序在解析相關(guān)字段的時候出現(xiàn)非預(yù)期的值導(dǎo)致崩潰。
其工作流程是首先將樣本讀入進(jìn)內(nèi)存,通過forkserver 框架通過fork 系統(tǒng)調(diào)用產(chǎn)生一個被fuzz 的子進(jìn)程,并將測試樣本讀入程序,fuzzer 記錄下程序運行時相關(guān)信息,比如代碼覆蓋率等。然后捕獲程序退出時發(fā)出的信號,并根據(jù)此信號判斷程序是否異常退出,然后根據(jù)程序運行時相關(guān)信息對測試樣本進(jìn)行變異,然后繼續(xù)讀入內(nèi)存?zhèn)鬟f給被fuzz 程序。如果產(chǎn)生crash,則將可以導(dǎo)致crash 的樣本放入crash 文件夾,供crash 監(jiān)控進(jìn)程讀取。
首先下載開源軟件,并編譯生成可執(zhí)行文件。然后運行軟件查看功能。
本次選取的軟件名為pdfcrack,是一款linux 下開源的pdf文件密碼破解工具。
第一步:首先將建立fuzz 所需要的輸入輸出目錄,并將種子文件放入輸入文件夾中。
第二步:編寫配置文件,主要參數(shù)如下:
(1)輸入目錄
(2)輸出目錄
(3)Crashes 目錄
(4)文件輸入方式
(5)被fuzz 程序路徑
第三步:執(zhí)行fuzz 框架主程序,并讀入配置文件
幾分鐘之后,便發(fā)現(xiàn)了crash,如下圖1 所示。
圖1 fuzz 運行
并且崩潰日志通過云端推送到了微信上面。
圖2 崩潰位置
結(jié)合軟件崩潰位置,使用gdb 調(diào)試器可以發(fā)現(xiàn)崩潰位置,如圖2 所示。
通過調(diào)試起可以發(fā)現(xiàn)這個地方s_handler 的值為0,程序試圖往一個0 地址進(jìn)行寫入,但是操作系統(tǒng)是禁止這一行為的,所以存在一個0 地址解引用漏洞。
通過gdb 調(diào)試器進(jìn)行函數(shù)調(diào)用回溯,發(fā)現(xiàn)該漏洞存在于函數(shù)loadstate 中,如圖3 所示。
圖3 調(diào)用回溯
通過對該函數(shù)代碼進(jìn)行分析,對e->s_handler 的復(fù)制存在于下面的代碼中,如圖4 所示。
圖4 漏洞代碼
函數(shù)對判斷l(xiāng)en 的大小,只要len 大于0 并且len 小于256就會通過malloc 分配一段內(nèi)存,并將堆內(nèi)存指針賦給e->s_handler,但是這里沒有考慮len 等于0 的情況,當(dāng)len 等于0,就會直接跳過申請內(nèi)存,然后直接對e->s_handler 進(jìn)行寫操作,并沒有判斷是否等于0 的情況,因此造成空指針解引用,如圖5 所示。
圖5 崩潰位置
因為len 等于0,因此不會進(jìn)入for 循環(huán),所以崩潰發(fā)生在最后一行。
本文以設(shè)計基于反饋驅(qū)動的fuzz 工具設(shè)計為目的,通過一系列的變異策略,可以在軟件中發(fā)現(xiàn)更多的漏洞,并且通過實際的開源軟件進(jìn)行測試,證實該fuzz 工具確實有發(fā)現(xiàn)軟件漏洞的能力。該fuzz 工具可以融合進(jìn)devsecops 中,開發(fā)者自己提供軟件編譯,然后進(jìn)行測試,這樣做的好處是開發(fā)者更懂自己的程序功能,因此可以提供更好的測試樣本,而且這樣可以減少軟件中潛在的漏洞。