張婉瑩,曹曉梅,陳 偉
(南京郵電大學(xué) 計(jì)算機(jī)學(xué)院,南京 210023)
近年來,綜合了模糊測(cè)試和Concolic執(zhí)行的白盒模糊測(cè)試技術(shù)引起研究人員的廣泛關(guān)注,其是一種漏洞檢測(cè)技術(shù),可以自動(dòng)生成測(cè)試用例來盡量覆蓋程序中的可執(zhí)行路徑,進(jìn)而發(fā)現(xiàn)程序內(nèi)的漏洞[1]。研究人員基于白盒模糊測(cè)試技術(shù)設(shè)計(jì)了許多漏洞檢測(cè)工具,如KLEE[2]、SAGE[3]、Angr[4]和Driller[5]等。實(shí)驗(yàn)結(jié)果表明,這些工具能夠有效提高漏洞檢測(cè)的效率。
從理論上而言,白盒模糊測(cè)試可以實(shí)現(xiàn)對(duì)目標(biāo)程序中所有可執(zhí)行路徑的覆蓋,但在實(shí)際的漏洞檢測(cè)過程中,無法達(dá)到100%的路徑覆蓋率,這主要是由于白盒模糊測(cè)試無法提供被測(cè)程序運(yùn)行所需的實(shí)際環(huán)境以及約束求解器難以求解復(fù)雜約束等問題。目前,大量應(yīng)用軟件與環(huán)境密切相關(guān),即在運(yùn)行過程中需要與操作系統(tǒng)、網(wǎng)絡(luò)以及設(shè)備之間進(jìn)行頻繁的交互,從而導(dǎo)致白盒模糊測(cè)試的漏洞檢測(cè)結(jié)果不僅取決于用戶輸入,還依賴于其運(yùn)行的環(huán)境[6]。如果在白盒模糊測(cè)試中不能提供某些路徑執(zhí)行所需要的環(huán)境,則與之相關(guān)的路徑可能無法被探索到,從而導(dǎo)致某些漏洞被遺漏,降低了檢測(cè)結(jié)果的準(zhǔn)確性,這就是環(huán)境交互問題。例如,CH4[7]等著名病毒都是在指定的時(shí)間發(fā)作,即只有滿足了漏洞觸發(fā)的時(shí)間條件,才能檢測(cè)到該漏洞,而這對(duì)于白盒模糊測(cè)試而言是一個(gè)難度較高的挑戰(zhàn)。
針對(duì)環(huán)境交互問題,比較成熟的解決方案是斯坦福大學(xué)CADAR等人開發(fā)的KLEE和瑞士洛桑聯(lián)邦理工學(xué)院CHIPOUNOV等人開發(fā)的S2E[8]。在漏洞檢測(cè)之前,KLEE先對(duì)被測(cè)程序中調(diào)用的庫函數(shù)進(jìn)行建模,在對(duì)程序進(jìn)行漏洞檢測(cè)的過程中,如果遇到調(diào)用庫函數(shù)的路徑,則將其重定向到對(duì)應(yīng)的模型,獲得所有合法的輸入值,從而驅(qū)動(dòng)相關(guān)路徑的執(zhí)行[9]。由于建模需要耗費(fèi)大量的人力和物力,因此KLEE只對(duì)庫函數(shù)進(jìn)行建模,當(dāng)遇到其他類型的外部函數(shù)時(shí),無法驅(qū)動(dòng)路徑的執(zhí)行,因此,其路徑覆蓋率偏低。S2E是基于虛擬機(jī)插樁的漏洞檢測(cè)工具,被檢測(cè)的目標(biāo)程序和整個(gè)運(yùn)行環(huán)境都運(yùn)行在S2E上。S2E采用2種漏洞檢測(cè)模式,即SC-UE(Strictly Consistent Unit-level Execution)模式和SC-SE(Strictly Consistent System-level Execution)[10]模式。如果在漏洞檢測(cè)的過程中采用SC-UE模式,則需要與外部環(huán)境進(jìn)行交互的函數(shù)不會(huì)被插樁,與之相關(guān)的路徑將無法被執(zhí)行,導(dǎo)致路徑覆蓋率偏低,部分漏洞可能被遺漏。如果采用SC-SE模式,需要與外部環(huán)境進(jìn)行交互的函數(shù)將會(huì)被插樁,并且可以根據(jù)真實(shí)的運(yùn)行環(huán)境獲得正確的測(cè)試用例,以驅(qū)動(dòng)相關(guān)路徑的執(zhí)行,獲得較高的路徑覆蓋率并檢測(cè)到更多的漏洞,但是這會(huì)帶來比較嚴(yán)重的路徑爆炸問題。
近年來,國內(nèi)外學(xué)者針對(duì)上述問題進(jìn)行了較多研究。文獻(xiàn)[11]提出了一種基于抽象內(nèi)存的針對(duì)外部函數(shù)調(diào)用的建模方法,該方法對(duì)每個(gè)外部函數(shù)建立抽象內(nèi)存模型,以保存其路徑約束條件并模擬外部函數(shù)的語義信息,從而獲取相應(yīng)的測(cè)試用例,以保證待測(cè)程序能夠按照目標(biāo)路徑執(zhí)行,最終提高路徑覆蓋率。但是,該技術(shù)難以對(duì)需要精確理解上下文的外部函數(shù)調(diào)用進(jìn)行建模。
本文提出一種基于外部函數(shù)探測(cè)和校正的隱藏路徑搜索(Hidden Path Search Based on External Function,HPSBEF)方案。該方案利用約束求解和最弱前置條件推理獲得外部函數(shù)的輸出值,并將其記錄在已經(jīng)建立好的鏈表中,在執(zhí)行新路徑的過程中根據(jù)鏈表信息對(duì)外部函數(shù)的輸出進(jìn)行動(dòng)態(tài)修正,以驅(qū)動(dòng)新路徑的執(zhí)行并提高路徑覆蓋率。為驗(yàn)證HPSBEF方案的有效性和執(zhí)行效率,將該方案與KLEE、S2E以及文獻(xiàn)[11]提出的FMM方案作對(duì)比,從路徑覆蓋率、漏洞檢測(cè)能力和時(shí)間開銷3個(gè)方面進(jìn)行分析。
HPSBEF方案在白盒模糊測(cè)試的基礎(chǔ)上實(shí)現(xiàn)了外部函數(shù)探測(cè)與校正,其框架如圖1所示,主要由外部函數(shù)預(yù)處理器、外部函數(shù)分析器和外部函數(shù)更新器三部分組成。
圖1 HPSBEF方案框架
外部函數(shù)預(yù)處理器針對(duì)每個(gè)被檢測(cè)的目標(biāo)程序,創(chuàng)建與外部函數(shù)相關(guān)的鏈表結(jié)構(gòu),以記錄目標(biāo)程序中所有調(diào)用的外部函數(shù)及其參數(shù)信息,包括位置信息、輸出參數(shù)類型和長度等。預(yù)處理器實(shí)現(xiàn)了外部函數(shù)的預(yù)處理,是檢測(cè)外部函數(shù)的前提和基礎(chǔ)。外部函數(shù)分析器檢測(cè)函數(shù)調(diào)用指令,并與外部函數(shù)預(yù)處理器建立的外部函數(shù)鏈表進(jìn)行匹配,若發(fā)現(xiàn)外部函數(shù),則根據(jù)鏈表中記錄的詳細(xì)參數(shù)信息進(jìn)行外部函數(shù)輸出值的修正,以達(dá)到訪問隱藏路徑的目的。分析器實(shí)現(xiàn)外部函數(shù)的探測(cè)、標(biāo)記與校正,是檢測(cè)外部函數(shù)的關(guān)鍵階段。外部函數(shù)更新器負(fù)責(zé)更新鏈表中的信息,即外部函數(shù)的參數(shù)在下次路徑執(zhí)行時(shí)是否需要修正以及修正為何值。白盒模糊測(cè)試在每次路徑執(zhí)行結(jié)束后,都會(huì)按照一定的規(guī)則對(duì)約束條件進(jìn)行取反,并由約束求解器求解產(chǎn)生新的測(cè)試用例[12],外部函數(shù)更新器將新的測(cè)試用例中與外部函數(shù)相關(guān)的信息更新到已有的鏈表中,以作為下次路徑執(zhí)行時(shí)外部函數(shù)進(jìn)行修正的參考。
1.2.1 外部函數(shù)預(yù)處理
外部函數(shù)預(yù)處理器的主要作用是外部函數(shù)及其參數(shù)信息的收集與整理,這是進(jìn)行后續(xù)探測(cè)與修正的前提和基礎(chǔ)。如果在預(yù)處理階段有外部函數(shù)被遺漏,或者其參數(shù)信息的收集存在誤差,則某些隱藏路徑將不能被訪問,從而導(dǎo)致某些漏洞被遺漏。
外部函數(shù)預(yù)處理器的執(zhí)行主要包含2個(gè)步驟:針對(duì)每個(gè)被檢測(cè)的目標(biāo)程序建立外部函數(shù)鏈表結(jié)構(gòu),包含函數(shù)地址、函數(shù)名、輸出參數(shù)個(gè)數(shù)、類型長度、校驗(yàn)標(biāo)識(shí)以及校驗(yàn)值,如圖2所示;找出目標(biāo)程序中包含的所有外部函數(shù)及其輸出屬性的參數(shù)信息,并記錄在鏈表中。
AddressFunction NameParameter NameParameter SizeFlagReplacement
圖2 外部函數(shù)鏈表結(jié)構(gòu)
Fig.2 Structure of external function chain
本文以Windows系統(tǒng)下的二進(jìn)制程序?yàn)槔龑?duì)外部函數(shù)的預(yù)處理過程進(jìn)行說明。Windows SDK中對(duì)于每個(gè)API函數(shù)參數(shù)的輸入輸出特性都有明確的定義,一般包括5種情況:[in],[out],[in,out],[in,optional],[out,optional]。對(duì)于可執(zhí)行PE文件而言,所有調(diào)用的外部函數(shù)信息都存儲(chǔ)在輸入地址表(Import Address Table,IAT)中[13],多數(shù)Windows下的常見外部函數(shù)都由Kernel32.dll導(dǎo)出,每一個(gè)從dll中被引入的外部函數(shù)在PE文件的IAT中都有相應(yīng)的位置。PE文件在裝載過程中先搜索數(shù)據(jù)結(jié)構(gòu)IMAGE_IMPORT_DESCRIPTOR中的OriginalFristThunk,若存在,則迭代搜索輸入名稱表(Import Name Table,INT)中的每個(gè)指針,這些指針指向了IMAGE_IMPORT_BY_NAME中的每個(gè)被載入函數(shù)的地址,然后裝載器將值填充到FristThunk指向的IAT表中,整個(gè)過程如圖3所示。因此,在PE文件被系統(tǒng)加載之后,提取外部函數(shù)及其在IAT表中的地址并且參照SDK中關(guān)于函數(shù)參數(shù)輸入輸出特性的定義,便可建立相應(yīng)的外部函數(shù)鏈表結(jié)構(gòu)。
圖3 PE文件加載后的IAT表
1.2.2 外部函數(shù)的探測(cè)、標(biāo)記與校正
執(zhí)行外部函數(shù)分析器是檢測(cè)外部函數(shù)的關(guān)鍵階段,其主要作用是在漏洞檢測(cè)的過程中根據(jù)外部函數(shù)的鏈表結(jié)構(gòu)對(duì)路徑中是否存在外部函數(shù)進(jìn)行探測(cè),若存在外部函數(shù),則對(duì)其輸出參數(shù)所在的內(nèi)存區(qū)域進(jìn)行標(biāo)記,并根據(jù)外部函數(shù)鏈表中的校驗(yàn)標(biāo)識(shí)以及校驗(yàn)值選擇性地更改輸出參數(shù)的具體數(shù)值,以驅(qū)動(dòng)隱藏路徑的執(zhí)行。
首先,外部函數(shù)分析器探測(cè)路徑中是否存在外部函數(shù)。Intel手冊(cè)定義了x86平臺(tái)下的3種調(diào)用指令[14],分別對(duì)應(yīng)機(jī)器碼E8、9A和FF。在程序執(zhí)行過程中,外部函數(shù)分析器獲取指令指針寄存器EIP中存儲(chǔ)的下一指令的機(jī)器碼,通過與E8、9A和FF 3種調(diào)用指令機(jī)器碼進(jìn)行比較,判斷是否為函數(shù)調(diào)用指令。如果下一條指令為函數(shù)調(diào)用指令,則進(jìn)一步獲取調(diào)用函數(shù)中的地址,并通過與外部函數(shù)鏈表中記載的地址進(jìn)行比較,判斷是否為外部函數(shù),如果是外部函數(shù),則進(jìn)行下一步,否則程序繼續(xù)執(zhí)行。
其次,在確定了外部函數(shù)之后,外部函數(shù)分析器即對(duì)其輸出參數(shù)所在內(nèi)存區(qū)域進(jìn)行標(biāo)記。由于Windows系統(tǒng)常采用cdecl和stdcall 2種調(diào)用約定,因此參數(shù)按照從右往左的順序進(jìn)行傳遞[15],所以最后一個(gè)入棧的參數(shù)就是函數(shù)的第一個(gè)參數(shù)。如果指令指針寄存器EIP指向的call指令調(diào)用的函數(shù)被判定為外部函數(shù),則根據(jù)當(dāng)前的指令地址可以獲得該外部函數(shù)每個(gè)參數(shù)的入棧地址,然后根據(jù)外部函數(shù)鏈表中存儲(chǔ)的該外部函數(shù)的輸出參數(shù)序號(hào)和參數(shù)類型大小這2個(gè)參數(shù),逆序推導(dǎo)出該函數(shù)中所有輸出參數(shù)所在的內(nèi)存區(qū)域。
最后,當(dāng)外部函數(shù)輸出參數(shù)被標(biāo)記之后,還需要根據(jù)鏈表中存儲(chǔ)的校驗(yàn)標(biāo)識(shí)Flag判定該外部函數(shù)的輸出是否需要被更改,如果需要更改,則將其更改為Replacement中存儲(chǔ)的數(shù)據(jù)。如果該外部函數(shù)的輸出參數(shù)是結(jié)構(gòu)體變量,則輸出參數(shù)值修正需要具體到結(jié)構(gòu)體中的每一個(gè)成員變量。
本文外部函數(shù)探測(cè)、標(biāo)記與校正的過程如算法1所示。語句1將指令指針寄存器EIP指向的指令機(jī)器碼轉(zhuǎn)換成匯編代碼,語句2判斷當(dāng)前指令是否為函數(shù)調(diào)用call指令,如果不是call指令,調(diào)用語句13,將控制權(quán)交回目標(biāo)程序,正常執(zhí)行該指令;反之,則調(diào)用語句3查詢外部函數(shù)鏈表,并調(diào)用語句4判定該函數(shù)是否為外部函數(shù)。如果鏈表中該外部函數(shù)存在,則調(diào)用語句5循環(huán)查找其輸出參數(shù),直到所有輸出參數(shù)查詢完畢,即IEF→PN=end時(shí)查詢結(jié)束,其中,PN代表輸出參數(shù)的名稱。然后,算法利用語句6計(jì)算輸出參數(shù)的內(nèi)存區(qū)域,可由函數(shù)參數(shù)的入棧地址和參數(shù)大小相加得出,即APN+IEF→PS,其中,APN代表參數(shù)的入棧地址,PS代表參數(shù)的大小。算法在獲得參數(shù)的內(nèi)存區(qū)域后則利用語句7將語句6的計(jì)算結(jié)果進(jìn)行標(biāo)記;反之,則調(diào)用語句9,將控制權(quán)交回目標(biāo)程序,執(zhí)行函數(shù)調(diào)用。語句10根據(jù)鏈表中記載的該外部函數(shù)的校驗(yàn)標(biāo)識(shí),判斷其輸出值是否需要校正,如果需要,則調(diào)用語句11將輸出參數(shù)值修改為鏈表中存儲(chǔ)的數(shù)據(jù),即ModifyOutput(Memory,IEF→Replacement)。
算法1外部函數(shù)探測(cè)、標(biāo)記與校正算法
輸入MEIP
輸出校正后的外部函數(shù)
MEIP:machine code recorded in the register EIP
1.Iop←HextoAsm(MEIP)
2.if Iop∈Icallthen
3.IEF←Looktable(Iop,TEF);
4.if IEF≠? then
5.while (IEF→PN≠end) do
6.Memory←APN+IEF→PS;
7.MarkOutput(Memory);
8.else
9.Execue(Iop);
10.if IEF≠?∩IEF→Flag==1 then
11.ModifyOutput(Memory,IEF→Replacement);
12.end if
13.Execue(Iop);
14.end if
由上述過程可知,該算法的時(shí)間復(fù)雜度由外部函數(shù)及其輸出參數(shù)的數(shù)量決定,因此,若外部函數(shù)的數(shù)量為nEF,每個(gè)外部函數(shù)的輸出參數(shù)數(shù)量最大為k,則該算法在最壞情況下的時(shí)間復(fù)雜度可表示為O(knEF)。算法的空間復(fù)雜度由存儲(chǔ)外部函數(shù)的鏈表結(jié)構(gòu)決定,可表示為O(6knEF)。
1.2.3 外部函數(shù)的更新
在白盒模糊測(cè)試中每條路徑執(zhí)行完成之后,會(huì)按照一定的路徑搜索策略對(duì)約束條件取反,并由約束求解器翻譯成最弱前置條件[16]進(jìn)行求解,產(chǎn)生新的輸入用例集合,以在下次漏洞檢測(cè)時(shí)驅(qū)動(dòng)新的路徑執(zhí)行。因此,外部函數(shù)更新器需要根據(jù)約束求解器的求解結(jié)果更新鏈表中的信息,以便在下次程序執(zhí)行時(shí)作為外部函數(shù)校正的參考和依據(jù)。
由于實(shí)驗(yàn)部分是在KLEE、S2E的基礎(chǔ)上實(shí)現(xiàn)本文方案,因此路徑搜索策略采用KLEE、S2E提供的方法。KLEE和S2E均提供4種搜索方法:深度優(yōu)先搜索,隨機(jī)狀態(tài)搜索,隨機(jī)路徑搜索以及NURS搜索,搜索方法的選擇取決于參數(shù)的設(shè)定[17],本文采用深度優(yōu)先搜索策略。
外部函數(shù)更新器需要將新生成的輸入集合中與外部函數(shù)相關(guān)的信息更新到相應(yīng)的鏈表項(xiàng)中,即該外部函數(shù)在下次執(zhí)行時(shí),輸出參數(shù)值是否需要校正以及需要校正的具體數(shù)值為多少。
為驗(yàn)證HPSBEF方案的實(shí)際效果并降低路徑搜索策略與約束求解能力等因素對(duì)實(shí)驗(yàn)結(jié)果的影響,本文分別在KLEE和S2E的基礎(chǔ)上實(shí)現(xiàn)HPSBEF方案以及文獻(xiàn)[11]提出的FMM方案,即在處理外部函數(shù)調(diào)用時(shí),將KLEE、S2E原有的方案替換為HPSBEF以及FMM方案,其余都不變。其中,HPSBEF方案以H-KLEE和H-S2E作為標(biāo)識(shí),FMM方案以M-KLEE和M-S2E作為標(biāo)識(shí)。
實(shí)驗(yàn)選用開源軟件庫[18]中包含較多外部函數(shù)的10個(gè)應(yīng)用程序作為漏洞檢測(cè)對(duì)象,程序的名稱、路徑數(shù)量和外部函數(shù)數(shù)量如表1所示。本次實(shí)驗(yàn)分別使用H-KLEE、M-KLEE、KLEE、H-S2E、M-S2E和S2E這6種工具對(duì)表2中的被測(cè)程序進(jìn)行檢測(cè),并從路徑覆蓋率、漏洞發(fā)現(xiàn)能力以及時(shí)間開銷3個(gè)方面進(jìn)行對(duì)比分析。
表1 目標(biāo)程序的路徑數(shù)量與外部函數(shù)數(shù)量
Table 1 Number of target program paths and external functions
程序名稱路徑數(shù)量外部函數(shù)數(shù)量doublecmd882123metafile2eps70184processcecker1 125168pdftotext72790miniweb53568ipsacn974111kkplayer1 385104hardseed81572mpush1 09688vnote78693
實(shí)驗(yàn)分別使用6種工具對(duì)被測(cè)程序進(jìn)行檢測(cè),統(tǒng)計(jì)各自的路徑覆蓋率,對(duì)比結(jié)果如圖4所示。
圖4 路徑覆蓋率結(jié)果對(duì)比
由圖4可以看出,H-KLEE和M-KLEE、KLEE以及H-S2E和M-S2E、S2E相比,路徑覆蓋率均有所提升。其中,H-KLEE比M-KLEE平均增加了4.2%,H-KLEE比KLEE平均增加了8.1%,H-S2E比M-S2E平均增加了5.3%,H-S2E比S2E平均增加了5.9%,結(jié)果表明,本文方案可以探測(cè)到更多路徑。此外,實(shí)驗(yàn)過程中的路徑覆蓋率沒有達(dá)到白盒模糊測(cè)試在理論上的100%覆蓋率,分析發(fā)現(xiàn)主要原因如下:約束求解器不支持浮點(diǎn)類型和指針運(yùn)算[19],不能理解某些包含浮點(diǎn)類型或指針運(yùn)算的復(fù)雜函數(shù)的運(yùn)算規(guī)則,在實(shí)驗(yàn)過程中,當(dāng)STP求解耗盡內(nèi)存或者求解時(shí)間超過5 min時(shí),將主動(dòng)終止求解過程,這也是眾多測(cè)試過程中部分路徑無法訪問的主要原因之一。
實(shí)驗(yàn)過程中對(duì)6種工具所檢測(cè)出的漏洞數(shù)量進(jìn)行統(tǒng)計(jì),結(jié)果如表2、表3 所示。
表2 H-KLEE、M-KLEE和KLEE檢測(cè)出的漏洞數(shù)量
Table 2 Number of vulnerabilities detected by H-KLEE,M-KLEE and KLEE
被測(cè)程序H-KLEEM-KLEEKLEEdoublecmd212019metafile2eps111010processcecker151413pdftotext191716miniweb131211ipsacn1098kkplayer121010hardseed987mpush1098vnote887
表3 H-S2E、M-S2E和S2E檢測(cè)出的漏洞數(shù)量
Table 3 Number of vulnerabilities detected by H-S2E,M-S2E and S2E
被測(cè)程序H-S2EM-S2ES2Edoublecmd212020metafile2eps111010processcecker151314pdftotext191816miniweb131313ipsacn1099kkplayer121111hardseed987mpush1099vnote888
由表2可知,H-KLEE和M-KLEE、KLEE相比,檢測(cè)出的漏洞數(shù)量有所增加,其中,H-KLEE比M-KLEE平均增加了9.4%,比KLEE平均增加了17.4%;由表3可知,H-S2E與M-S2E 、S2E相比,漏洞數(shù)量也有所增加,H-S2E比M-S2E平均增加了7.6%,比S2E平均增加了16.4%。因此,本文方案的漏洞檢測(cè)能力較高。
實(shí)驗(yàn)過程中對(duì)6種工具的平均漏洞檢測(cè)消耗時(shí)間進(jìn)行統(tǒng)計(jì),結(jié)果如圖5所示。其中,H-KLEE的平均時(shí)間為45 028 s,M-KLEE的平均時(shí)間為45 343 s,KLEE的平均時(shí)間為45 811 s,H-KLEE所用時(shí)間最少;H-S2E的平均時(shí)間為45 078 s,M-S2E的平均時(shí)間為45 879 s,S2E的平均時(shí)間為46 526 s,H-S2E所用時(shí)間最少。因此,本文方案的時(shí)間開銷明顯降低。
圖5 各方案平均消耗時(shí)間對(duì)比
Fig.5 Comparison of average consumption time of each scheme
本文針對(duì)白盒模糊測(cè)試中環(huán)境交互問題引起的路徑覆蓋率偏低、某些潛在漏洞可能被遺漏的問題,提出一種基于外部函數(shù)探測(cè)和校正的隱藏路徑搜索方案HPSBEF。該方案闡述了外部函數(shù)探測(cè)和校正的實(shí)現(xiàn)過程,并針對(duì)虛擬機(jī)級(jí)別插樁和用戶態(tài)級(jí)別插樁2種方式分別進(jìn)行了驗(yàn)證。實(shí)驗(yàn)結(jié)果表明,HPSBEF方案能有效提升路徑覆蓋率和漏洞檢測(cè)能力,同時(shí)降低時(shí)間開銷。目前的白盒模糊測(cè)試技術(shù)經(jīng)常遭遇如路徑爆炸、復(fù)雜約束求解等問題,下一步將針對(duì)這些問題進(jìn)行研究,以使該技術(shù)更好地應(yīng)用于漏洞檢測(cè)領(lǐng)域。