張晨輝,周安民,賈 鵬
(四川大學網(wǎng)絡空間安全學院,成都 610041)
模糊測試是現(xiàn)代漏洞挖掘最有效的技術(shù)之一,其為被測程序提供大量輸入,并監(jiān)視其出現(xiàn)的異常行為(例如堆棧溢出、越界讀寫、內(nèi)存泄漏等)。自從模糊測試方法問世以來,其在業(yè)界和學界受到廣泛關(guān)注并不斷發(fā)展,研究人員開發(fā)了各種工具應用于不同的測試場景。近年來,隨著AFL(American Fuzzing Loop)家族的出現(xiàn),灰盒模糊測試的發(fā)展不斷完善,并取得了優(yōu)秀的成果。定向灰盒模糊測試的概念提出于2017年發(fā)表于CCS 的《Directed Greybox Fuzzing》,定向模糊測試需要事先指定目標點,例如,在有源碼的情況下可以指定代碼行數(shù),定向模糊測試的目的就是為了使輸入到達目標點,以探測該代碼段是否存在安全問題。定向模糊測試主要應用在補丁檢測、漏洞PoC復現(xiàn)以及靜態(tài)分析驗證等場景。但目前的定向模糊測試存在種子能量分配不均的問題,由于能量分配采用模擬退火算法,距離目標點近的種子分配的能量過多,而距離遠的種子可能會被“餓死”;又或者設(shè)置種子能量與時間不相關(guān),可以使每個種子得到對應的能量但同時忽視了時間有限這一因素。
基于此,本文在定向模糊測試中加入了時間分片的思想,將運行時間分為四個階段,分別為探索階段、短距離優(yōu)先階段、長距離探索階段和長距離優(yōu)先階段。每個階段采用不同的能量調(diào)度算法,使得每一個種子會在不同的階段發(fā)揮其本身的優(yōu)勢;并且,在保證短距離種子分配到更多能量的同時,長距離種子在某些階段也會分配到更多的能量。實驗中,我們在binutils 測試集共7 個真實程序上進行實驗,結(jié)果遠優(yōu)于AFLGo和Hawkeye。
模糊測試是指向待測程序提供大量畸形數(shù)據(jù)作為輸入,監(jiān)視程序的異常情況,基于導致異常的輸入進行分析發(fā)現(xiàn)漏洞的一種方法。根據(jù)測試用例生成的方法,可以分為基于生成的模糊測試和基于變異的模糊測試。前者需要已知的數(shù)據(jù)格式,在不破壞格式的前提下生成測試用例;后者是將初始數(shù)據(jù)進行大量變異生成測試用例。按照對待測程序的分析程度,可以分為白盒模糊測試、灰盒模糊測試和黑盒模糊測試。白盒模糊測需要全部源代碼,黑盒則不需要任何待測程序的信息,灰盒模糊測試介于二者之間,通過運行時的反饋來指導模糊測試。模糊測試已在漏洞挖掘領(lǐng)域發(fā)揮重要作用,但其仍然面臨著許多問題:如代碼覆蓋率不高、不能完全探索程序空間等。目前主流的模糊測試工具有AFL、Peach、AFLGo、Hawkeye等。
定向模糊測試主要應用在補丁檢測、漏洞PoC復現(xiàn)以及靜態(tài)分析驗證等場景。對于補丁測試,在程序出現(xiàn)漏洞時通常會打補丁,對打補丁后的版本可以針對補丁代碼段進行測試,查看補丁的有效性;對于漏洞重現(xiàn),因為部分CVE由于隱私問題不會提供PoC,只會在報告中展示漏洞代碼出現(xiàn)的位置,因此可以利用定向模糊測試進行CVE 復現(xiàn);在靜態(tài)分析驗證中,通過靜態(tài)分析得到的可能存在漏洞的代碼,需要通過動態(tài)測試來驗證。
定向模糊測試的基本原理如下:定向模糊測試實現(xiàn)給定目標代碼段,通過靜態(tài)分析提取函數(shù)調(diào)用圖(Call Graph,CG)和控制流圖(Control Flow Graph,CFG),計算所有基本塊到達目標點的最小距離,如Dijkstra 距離,這些距離用于在模糊測試時計算種子的優(yōu)先度、能量分配等,使定向模糊測試趨向于目標點。在靜態(tài)分析中,由于LLVM 可跨平臺、編譯速度顯著優(yōu)于gcc,并且可以設(shè)計插件提取CFG 和CG,因此在定向模糊測試中,通過LLVM 插樁的方式將距離和覆蓋率信息插入目標程序。
符號執(zhí)行是指將程序的約束條件轉(zhuǎn)化為抽象的符號,則一個程序的輸出即可轉(zhuǎn)化為一個關(guān)于輸入的函數(shù),符號執(zhí)行可以得出到達目標代碼段所需要的輸入條件。符號執(zhí)行分為靜態(tài)符號執(zhí)行和動態(tài)符號執(zhí)行,其中靜態(tài)符號執(zhí)行是通過符號值模擬程序執(zhí)行,而動態(tài)符號執(zhí)行是在程序運行時進行約束求解。雖然符號執(zhí)行可以達到較高的代碼覆蓋率,但是其狀態(tài)空間爆炸、復雜約束無法求解、資源開銷過大等問題限制了符號執(zhí)行的實際使用。目前,主流的符號執(zhí)行工具有KLEE、CUTE等。
如圖1所示,SliceAFL 分為兩個部分,靜態(tài)分析階段基于AFLGo,通過構(gòu)建CG(call graph)和CFG(control flow graph),計算每一個基本塊距離目標點的最短距離,距離基于Dijkstra 算法,基本塊級別距離和函數(shù)級別距離基于AFLGo 實現(xiàn)。將每一個基本塊的距離編譯時插樁,插樁基于LLVM-Clang。
圖1 SliceAFL整體框架示意圖
在Fuzzing Loop 中,SliceAFL 設(shè)置1h 為一輪探索時間,每一輪分為四個階段:前20 分鐘為無差別探索階段,接下來的20 分鐘為短距離優(yōu)先階段,第40-50 分鐘為長距離探索階段,第50-60 分鐘為長距離優(yōu)先階段。除了探索階段,其余階段按照需求進行基于模擬退火的能量調(diào)度。
2.1.1 無差別探索階段
本階段旨在為Fuzzer 探索更多狀態(tài)的初始種子?;诰嚯x引導的定向模糊測試中,距離越短的種子越可能到達目標點,但是從模糊測試早期一直選擇距離最短的種子很容易使Fuzzer陷入某個局部路徑。所以,無差別探索階段的目的就是盡可能地探索早期程序空間,得到各種狀態(tài)的種子,為接下來的幾個階段提供種子基礎(chǔ)。該階段按照種子隊列順序選擇種子,對每一個種子不進行基于模擬退火的能量調(diào)度,每一個種子的能量都取決于種子本身的性質(zhì)而不是時間。因此,經(jīng)過一段時間的探索后,種子隊列里應當存在各種狀態(tài)下的種子。
2.1.2 短距離優(yōu)先階段
在定向模糊測試中,時間是一個寶貴的資源,所以應當盡早到達目標點。在該階段Fuzzer將全部能量投入到探索短距離的種子,距離越短的種子能量越大,越優(yōu)先運行,意圖在該階段以最快的速度逼近目標點。但是該階段的問題是一直選擇短距離種子,會忽略長距離種子,而長距離種子也有可能觸發(fā)crash,因此需要后續(xù)的階段解決這個問題。
2.1.3 長路徑探索階段
該階段是為了彌補第二階段趨向于短路徑的問題,該階段將能量投入到基本塊數(shù)量更多的種子。通過插樁時定義bb_passed 標志,以記錄當前種子經(jīng)過的基本塊數(shù)量。本文認為,經(jīng)過的基本塊數(shù)量越多,該種子就探索了程序中更復雜的狀態(tài),這樣的種子具有更大的探索價值。本文在該階段沒有選擇距離最遠的種子,理由如下:距離最遠的種子可能位于程序的初始階段,離目標點過于遠,探索該類種子需要的時間消耗過大;其次,該類種子可以在無差別探索階段被執(zhí)行,所以長路徑探索階段不追求一味地探索距離最遠的種子,而是探索基本塊數(shù)量更多的種子,更復雜的程序狀態(tài)意味著更多的可能性,會給目標函數(shù)帶來更多觸發(fā)crash的可能。
2.1.4 長距離優(yōu)先階段
該階段作為長路徑探索階段的輔助階段,優(yōu)先選取上一階段中產(chǎn)生的距離最近的種子,并給予較高的能量。特殊情況下,如果上一階段沒有產(chǎn)生新種子或者所有新種子都已經(jīng)過一輪變異且沒有產(chǎn)生新路徑,則轉(zhuǎn)入短距離優(yōu)先階段。這種情況意味著當前種子隊列中的長路徑探索效果不明顯,所以將當前模糊測試的目標重新變?yōu)樽非缶嚯x更近的種子以快速到達目標點。
在定向模糊測試中,我們通常只有有限的時間,因此AFLGo 采用了模擬退火的能量調(diào)度算法。模擬退火是指在隨機游走過程中,該算法總是接受更好的解決方案,但偶爾也會接受較差的方案。溫度是模擬退火算法的一個參數(shù),用來調(diào)節(jié)接受較差解的概率,并隨退火過程逐漸降低。初始時當=0=1 時,模擬退火算法總是能夠接受較差解,當接近0 時,退化為經(jīng)典的梯度下降算法,只接受更好的解。
換句話說,當=1 時,F(xiàn)uzzer 剛開始運行,對于距離長和距離短的種子,都能夠獲得一定的能量,當接近0 時,距離長的種子的能量逐漸變少,距離越近的種子能量越高。然而,AFLGo 的模擬退火算法會導致長路徑“餓死”。由于距離遠的種子可能探索了更多的基本塊數(shù)量,基本塊數(shù)量越多可能代表著越復雜的程序狀態(tài),因此,在SliceAFL 中認為,程序空間復雜度和經(jīng)過的基本塊數(shù)量正相關(guān),本文保留AFLGo 原有的基于距離的模擬退火算法的同時,增加一個基于基本塊數(shù)量的退火算法:
定義annealing-based power schedule(APS),對于給定的seeds 和目標基本塊,APS 將能量定義為:
其中,() =/,表示當前種子經(jīng)過的基本塊數(shù)量和所有種子經(jīng)過的最大基本塊數(shù)量的比值,保證了能量∈[0,1];,表示探索的時間。在長路徑探索階段,剛開始運行時,APS 將相同的能量分配給經(jīng)過不同基本塊數(shù)量的種子,隨著時間的推移,經(jīng)過基本塊數(shù)量越多的種子獲得越來越多的能量,而經(jīng)過基本塊數(shù)量較少的種子獲得的能量越來越少。SliceAFL在長距離探索階段和長距離優(yōu)先階段不采用原有的基于距離退火,而是采用上述的基于基本塊數(shù)量退火,保證了在短路徑優(yōu)先的前提下,同時探索了長路徑的可能性。
注意,即使在第四階段,即長距離優(yōu)先階段,雖然優(yōu)先選擇距離最近的種子,但仍然采用基于基本塊數(shù)量的退火算法,因為該階段的種子距離可能離目標點仍然較遠,如果采用基于距離的退火算法可能會造成大部分種子分配的能量過少,詳情參考AFLGo的模擬退火算法。
為了驗證SliceAFL 的有效性,本文選取AFLGo 和Hawkeye 為對比對象。由于本文關(guān)注復現(xiàn)漏洞時間快慢的對比,以及長路徑的探索能力,所以使用Binutils測試集以及AFLGo 曾經(jīng)復現(xiàn)過的部分漏洞程序進行實驗對比。由于Hawkeye 并沒有公開源碼,所以本文中關(guān)于Hawkeye 的對比參考Hawkeye 文章中的數(shù)據(jù)結(jié)果。本文的實驗運行在Inter Xeon CPU E5-2697 v3@ 2.60 GHz,包括14 個核心處理器,實驗中使用10 個核心處理器,另外4 個留給其他程序。系統(tǒng)版本為Ubuntu 16.04 LTS。本文在Binutils上進行了測試,并與AFLGo,Hawkeye 進行對比。同樣地,本文將每個實驗運行20 次,時間預算設(shè)置為8個小時,初始種子輸入文件只包含一個換行符(由echo“”>in/file)生成,結(jié)果見表1。
表1 SliceAFL與AFLGo和Hawkeye的crash速度對比
其中Runs 代表復現(xiàn)該CVE 的次數(shù),μTTE(s)表示平均復現(xiàn)該CVE 需要的時間,F(xiàn)actors 表示與SliceAFL 的μTTE(s)的倍數(shù)關(guān)系。在這些漏洞中,除了CVE-2016-4491 和CVE-2016-6131,其他CVE 漏洞的復現(xiàn)時間都很短。AFLGo 在文章中同時對比了AFL 的復現(xiàn)能力,AFL 也僅僅比AFLGo 慢了幾分鐘,因此在這些漏洞上對比定向模糊測試的能力并不準確。而對于CVE-2016-4491 和CVE-2016-6131,AFLGo 與Hawkeye 發(fā)現(xiàn)探測到這兩個漏洞的時間都需要5 個小時以上,這種探索時間較長的CVE 才更能體現(xiàn)出定向Fuzz 的能力。SliceAFL 對于CVE-2016-4491 和CVE-2016-6131 都取得了更好的成果,擊中次數(shù)略高于Hawkeye(分別為9 次和10 次),TTE遠短于Hawkeye(15006 s和15872 s)。這種基于時間分片的思想取得了更好的效果。
本文提出了一種新的定向模糊測試工具SliceAFL。SliceAFL 在時間有限的前提下將時間分段,并在不同的時間片段采取不同的模擬退火策略,從而更加快速地到達目標點。通過對比實驗可以看出,SliceAFL 在探索長距離crash方面更有優(yōu)勢,并且在探索目標更多狀態(tài)上取得了很好的效果。在未來的工作中,將會進一步完善種子選擇策略,并在提高命中率方面作更多的研究工作。