模糊測(cè)試
基本概念
模糊測(cè)試是一種軟件測(cè)試技術(shù),其核心思想是自動(dòng)或半自動(dòng)的生成隨機(jī)數(shù)據(jù)輸入到一個(gè)程序中,并監(jiān)視程序異常,如崩潰,斷言(assertion)失敗,以發(fā)現(xiàn)可能的程序錯(cuò)誤,比如內(nèi)存泄漏。
假如該程序在應(yīng)對(duì)任一輸入值時(shí)失效,開(kāi)始出現(xiàn)沖突、鎖住、消耗大量?jī)?nèi)存或者產(chǎn)生不可控制的程序錯(cuò)誤,開(kāi)發(fā)者就知道代碼中某處出現(xiàn)了bug。
比較有效的模糊測(cè)試,并不是用大量純隨機(jī)數(shù)據(jù)直接來(lái)測(cè)試,而是對(duì)已知有效數(shù)據(jù)、故意錯(cuò)誤數(shù)據(jù)和隨機(jī)數(shù)據(jù)的聯(lián)合調(diào)試。使用已知有效數(shù)據(jù)的目的是跳過(guò)不感興趣的代碼片段,或者說(shuō)是為了防止程序在抵達(dá)一個(gè)欠缺的代碼塊前出現(xiàn)拒絕信息。使用故意錯(cuò)誤數(shù)據(jù)的目的是利用已知或我懷疑將成為代碼中缺陷的情況。最后,使用隨機(jī)數(shù)據(jù)的目的就是看看會(huì)發(fā)生什么。
模糊測(cè)試流程
確定測(cè)試目標(biāo)
-
確定輸入向量
幾乎漏洞的形成原因大都是對(duì)于客戶端傳輸?shù)臄?shù)據(jù)沒(méi)有經(jīng)過(guò)過(guò)濾等,在服務(wù)端造成了惡意的影響。
例如WEB端進(jìn)行fuzz:從客戶端向服務(wù)端傳輸數(shù)據(jù)包{ 能傳輸?shù)娜魏螖?shù)據(jù)(例如header,useragent等)},這些傳輸?shù)臄?shù)據(jù)大多數(shù)都可能為模糊測(cè)試變量。
-
生成模糊測(cè)試數(shù)據(jù)
基于測(cè)試中,如何選擇自動(dòng)化輸入的數(shù)據(jù),是使用字典,還是用隨機(jī)數(shù),還是特定生成的字典呢。
-
執(zhí)行模糊測(cè)試數(shù)據(jù)
在這個(gè)步驟中,就要向你的服務(wù)端發(fā)送數(shù)據(jù)包(WEB端),發(fā)送在上一步驟中生成的數(shù)據(jù)包。當(dāng)然web端還是要小心waf,如果一次性發(fā)10k個(gè)數(shù)據(jù)包,那么只會(huì)引起反效果。
-
監(jiān)視回顯
在這一步,根據(jù)測(cè)試目標(biāo)的不同自然監(jiān)視方式也不同,要根據(jù)測(cè)試的類型來(lái)設(shè)置各樣的監(jiān)視
-
判斷漏洞是否能被利用
根據(jù)測(cè)試的類型不同,那么前幾個(gè)階段的權(quán)重,順序或許可以進(jìn)行調(diào)整,但是仍不能保證可百分百發(fā)現(xiàn)所有安全相關(guān)的缺陷。
WinAFL
從原理上來(lái)說(shuō) AFL 通過(guò)變異軟件輸入的數(shù)據(jù)來(lái)進(jìn)行軟件 Bug 挖掘,與一些模糊測(cè)試器不同的是 AFL 變異數(shù)據(jù)的方法是通過(guò)覆蓋率算法來(lái)實(shí)現(xiàn)的,而不是通過(guò)格式。AFL通過(guò)對(duì)源碼進(jìn)行重新編譯時(shí)進(jìn)行插樁(簡(jiǎn)稱編譯時(shí)插樁)的方式自動(dòng)產(chǎn)生測(cè)試用例來(lái)探索二進(jìn)制程序內(nèi)部新的執(zhí)行路徑。由于需要在相關(guān)代碼處插樁,因此AFL主要用于對(duì)開(kāi)源軟件進(jìn)行測(cè)試。

WinAFL 的原理和其他的模糊測(cè)試工具類似,通過(guò)對(duì)程序輸入的數(shù)據(jù)進(jìn)行變異處理,觀察程序在處理這些變異數(shù)據(jù)是否會(huì)產(chǎn)生 Crash,以此來(lái)驗(yàn)證程序是否有 Bug。但是相對(duì)于其它模糊測(cè)試工具來(lái)說(shuō)則更為智能,因?yàn)樗鼤?huì)通過(guò)進(jìn)化算法不停的改變程序輸入的數(shù)據(jù),并且結(jié)合程序的覆蓋率以進(jìn)行下一步操作。運(yùn)行的速度越快,效果越明顯。
最開(kāi)始給afl初始種子,然后經(jīng)過(guò)變異得到輸入,將輸入給到待測(cè)試程序,并通過(guò)插樁技術(shù)對(duì)程序跟蹤,或者覆蓋率。然后覆蓋率指導(dǎo)之前的流程,周而復(fù)始,直到遇到崩潰情況,便將其保存。這種覆蓋率的想法使得輸入不再是隨機(jī)盲目的。
插樁編譯——fuzzing——分析crashes
(將testcase作為程序的輸入執(zhí)行程序,afl會(huì)在這個(gè)testcase的基礎(chǔ)上進(jìn)行自動(dòng)變異輸入)
安裝過(guò)程見(jiàn)下面的兩篇博客: VisualStudio2017+Windows10
https://www.giantbranch.cn/2020/12/25/winafl%E7%BC%96%E8%AF%91%E4%B8%8E%E6%B5%8B%E8%AF%95/
https://www.anquanke.com/post/id/210457
WinAFL 項(xiàng)目地址:https://github.com/ivanfratric/winafl
DynamoRIO 項(xiàng)目地址:https://github.com/DynamoRIO/dynamorio/wiki/Downloads
實(shí)例分析
使用winafl下的test_gdiplus.exe進(jìn)行測(cè)試

1. DynamoRIO
winafl 動(dòng)態(tài)插樁是調(diào)用DynamoRIO 下的 “drrun.exe” 進(jìn)行的。動(dòng)態(tài)二進(jìn)制插樁框架DynamoRIO通過(guò)將程序代碼進(jìn)行反復(fù)插樁(Instrumentation)執(zhí)行構(gòu)建了源程序代碼與操縱代碼之間的橋梁。我們可以簡(jiǎn)單使用”drrun.exe”來(lái)獲取目標(biāo)程序執(zhí)行過(guò)程中所加載的模塊,從而推斷DynamoRIO編譯是成功并可用的,這也是官方教程里的做法。
任意找一個(gè)bmp格式的圖片放到上面我們編譯后的winafl\b32\bin\Release目錄下。然后運(yùn)行下面命令:
D:\WinAFL\my_winafl_fuzz\DynamoRIO-Windows-8.0.0-1\bin64\drrun.exe -c winafl.dll -debug -target_module test_gdiplus.exe -target_offset 0x10e0 -fuzz_iterations 5 -nargs 2 -- test_gdiplus.exe 1.bmp

這里的偏移量0x10e0是通過(guò)ida查看main函數(shù)是sub_1400010E0,基址是0x140000000,偏移是0x10e0。

drrun的參數(shù)說(shuō)明:
-c <client> [client options] — <app and args to run>
// winafl.dll 參數(shù)說(shuō)明。這也是插樁參數(shù)的使用[instrumentation options]
-debug # debug模式, 它會(huì)生成一個(gè)log文件
-target_module # 目標(biāo)程序(只能有一個(gè)), 也是target_offset所在的模塊
-target_offset # 目標(biāo)程序偏移,相對(duì)于target_module的偏移,在method無(wú)法導(dǎo)出的時(shí)候使用
-fuzz_iterations # 在重新啟動(dòng)目標(biāo)進(jìn)程之前,目標(biāo)函數(shù)要運(yùn)行的最大迭代次數(shù)
-nargs # 目標(biāo)程序執(zhí)行所需要的參數(shù)個(gè)數(shù)(包括目標(biāo)程序本身)
-target_module # 目標(biāo)函數(shù),需要export或者調(diào)試符號(hào)(pdb)
-coverage_module # 計(jì)算覆蓋率的模塊,也就是目標(biāo)程序會(huì)調(diào)用的模塊(dll); (可以有多個(gè))
執(zhí)行之后產(chǎn)生一個(gè)log文件,打開(kāi)是目標(biāo)程序執(zhí)行過(guò)程中所所調(diào)用的dll

2.WinAFL
在winafl\build64\bin\Release目錄下,分別新建 in、out 文件夾;然后把bmp格式圖片放到 in 文件夾下。然后運(yùn)行下面命令。
afl-fuzz.exe -i in -o out -D D:\WinAFL\my_winafl_fuzz\DynamoRIO-Windows-8.0.0-1\bin64\ -t 20000 -- -coverage_module gdiplus.dll -target_module test_gdiplus.exe -target_offset 0x10e0 -fuzz_iterations 20 -nargs 2 -- test_gdiplus.exe @@

參數(shù)說(shuō)明:
-i # 存放樣本的目錄
-o # 保存輸出數(shù)據(jù),包括 crash文件、測(cè)試用例等
-D # DynamoRIO的路徑 (drrun, drconfig)
-t msec # 每一次樣本執(zhí)行的超時(shí)時(shí)間
-- # 分割符
****************************
第一個(gè)"--"分割符: 后面跟的是插樁的參數(shù)
-coverage_module gdiplus.dll 為fuzzing對(duì)象程序會(huì)調(diào)用的模塊,也就是說(shuō)你fuzzing的偏移地址的函數(shù)會(huì)調(diào)用到這些模塊里面的函數(shù),通過(guò)插樁時(shí)winafl.dll的-debug模式獲得,然后根據(jù)反匯編代碼判斷調(diào)用了那些模塊,
在無(wú)法自行判斷的情況下我們寫的跟-target_module一樣即可。
****************************
第二個(gè)"--"分割符: 后面跟的是目標(biāo)程序的參數(shù)
在執(zhí)行過(guò)程中,afl-fuzz會(huì)把@@替代測(cè)試樣本,第一個(gè)參數(shù)可以之前拷貝到in目錄下的1.bmp,用@@來(lái)代替,@@所代表傳入的是變異后的輸入。最后實(shí)際執(zhí)行的命令為test_gdiplus.exe 1.bmp/變異輸入
查看fuzzing狀態(tài),主要看右上角的“uniq crashes”:

process timing:包括當(dāng)前fuzzer的運(yùn)行時(shí)間、最近一次發(fā)現(xiàn)新執(zhí)行路徑的時(shí)間、最近一次崩潰的時(shí)間、最近一次超時(shí)的時(shí)間。
-
overall results:包括運(yùn)行的總周期數(shù)、總路徑數(shù)、崩潰次數(shù)、超時(shí)次數(shù)。
總周期數(shù)可以用來(lái)作為何時(shí)停止fuzzing的參考。隨著不斷地fuzzing,周期數(shù)會(huì)不斷增大,其顏色也會(huì)由洋紅色,逐步變?yōu)辄S色、藍(lán)色、綠色。一般來(lái)說(shuō),當(dāng)其變?yōu)榫G色時(shí),代表可執(zhí)行的內(nèi)容已經(jīng)很少了,繼續(xù)fuzzing下去也不會(huì)有什么新的發(fā)現(xiàn)了。此時(shí),我們便可以通過(guò)Ctrl-C,中止當(dāng)前的fuzzing
-
stage progress:包括正在測(cè)試的fuzzing策略、進(jìn)度、目標(biāo)的執(zhí)行總次數(shù)、目標(biāo)的執(zhí)行速度
執(zhí)行速度可以直觀地反映當(dāng)前跑的快不快,如果速度過(guò)慢,比如低于500次每秒,那么測(cè)試時(shí)間就會(huì)變得非常漫長(zhǎng)。如果發(fā)生了這種情況,那么我們需要進(jìn)一步調(diào)整優(yōu)化我們的fuzzing
3. BugID
等所有測(cè)試結(jié)束之后,打開(kāi)out文件夾,crashes文件夾里面是我們產(chǎn)生crash的樣例,hangs里面是產(chǎn)生超時(shí)的樣例,queue里面是每個(gè)不同執(zhí)行路徑的測(cè)試用例。

整理被模糊測(cè)試找出的 Bug,調(diào)試一下出現(xiàn) Crash 的原因,以及是否可以被利用。當(dāng)然這個(gè)過(guò)程比較繁瑣,利用 BugID(https://github.com/SkyLined/BugId) 可以幫助你進(jìn)行 Bug 分類,或者編寫 Windbg 腳本。
winafl的局限性體現(xiàn)在如果fuzzing的目標(biāo)程序,沒(méi)有函數(shù)導(dǎo)出表(dll)、不接受命令行參數(shù)、源代碼也沒(méi)有、環(huán)境變量也不調(diào)用的話,就很難fuzzing。解決的辦法就只有hook和逆向。
參考資料:
https://zhuanlan.zhihu.com/p/89039547
https://www.cnblogs.com/studyskill/p/7115913.html
https://blog.csdn.net/lei_saint/article/details/49158943