靳憲龍,徐世偉,黃雅娟
(1.四川大學(xué)計算機(jī)學(xué)院,成都610065;2.中國人民解放軍78156 部隊,蘭州730030;3.國防科技大學(xué)國際關(guān)系學(xué)院,南京210012)
在網(wǎng)絡(luò)空間斗爭日益激烈的形式下,安全漏洞始終是博弈雙方關(guān)注的核心問題之一。安全漏洞的研究主要分為漏洞挖掘、漏洞分析及利用、漏洞評估、漏洞修復(fù)等。近年來,隨著模糊測試、機(jī)器學(xué)習(xí)等技術(shù)在漏洞挖掘領(lǐng)域的應(yīng)用,顯著提升了漏洞挖掘的自動化水平。由于漏洞分析的復(fù)雜性及編寫利用程序的靈活性,傳統(tǒng)的漏洞分析與利用依賴具備專業(yè)知識的安全專家進(jìn)行。隨著漏洞挖掘自動化程度的提高,有限的人力資源已不足以有效應(yīng)對漏洞的快速增長,為了能夠?qū)崿F(xiàn)對新披露漏洞的快速響應(yīng),進(jìn)一步提升漏洞利用的自動化水平已迫在眉睫。
與此同時,美國國防部高等研究計劃署(DARPA)通過研究得出,自動化攻防在當(dāng)前技術(shù)體系下已可實現(xiàn),并于2013 年發(fā)起網(wǎng)絡(luò)超級挑戰(zhàn)賽(Cyber Grand Challenge,CGC)[1]。經(jīng)過三年的預(yù)決賽,最終于2016的DEFCON CTF[2]中舉辦了自動化攻防領(lǐng)域中的首次人機(jī)對戰(zhàn),體現(xiàn)出自動化攻防對自動化漏洞利用的迫切需求與廣闊前景。
漏洞自動利用是指通過給定的數(shù)據(jù),如可執(zhí)行程序、源代碼、補丁程序等,生成可以利用該漏洞達(dá)到某特定目的的數(shù)據(jù)或者代碼的過程的自動化實現(xiàn)[3]。該過程非常復(fù)雜,包括準(zhǔn)確定位漏洞點、通過符號執(zhí)行技術(shù)生成能夠觸發(fā)漏洞的程序輸入、獲取運行時信息及崩潰現(xiàn)場數(shù)據(jù)、通過SMT 對約束集合求解并最終生成漏洞利用樣本。
自2008 年D. Brumley 首次提出基于補丁比對的漏洞利用自動生成方法APEG[4]以來,研究人員陸續(xù)提出AEG[5]、AXGEN[6]、MAYHEM[7]等方案。依據(jù)所需輸入數(shù)據(jù)的不同,可將現(xiàn)有方案分為四類:基于可執(zhí)行文件、基于源代碼、基于補丁文件、基于異常輸入的解決方案。本文通過分析CRAX[8]、FUZE[9]、Revery[10]、Poly-AEG[11]等基于異常輸入的解決方案,發(fā)現(xiàn)基于異常輸入的方案存在以下問題:①初始異常輸入無法保證漏洞復(fù)現(xiàn)的成功率;②在成功復(fù)現(xiàn)漏洞的情況下,無法保證漏洞利用的成功率。
為了緩解以上問題,我們提出基于Crash 的漏洞利用自動生成系統(tǒng)C-Rex。系統(tǒng)遵循以下設(shè)計原則:①采用混合符號執(zhí)行技術(shù)復(fù)現(xiàn)崩潰路徑;②復(fù)現(xiàn)失敗時搜索相鄰路徑,嘗試獲取新崩潰點;③分析崩潰現(xiàn)場并判定其可利用性;④生成劫持控制流的漏洞利用樣本。
本文設(shè)計并實現(xiàn)了基于Crash 的漏洞利用自動生成系統(tǒng)C-Rex,系統(tǒng)采用動態(tài)分析、符號執(zhí)行[12]等技術(shù),結(jié)合異常輸入對目標(biāo)程序中所存在漏洞進(jìn)行復(fù)現(xiàn)、判定其可利用性并自動生成實現(xiàn)控制流劫持的漏洞利用樣本。系統(tǒng)架構(gòu)如圖1 所示。
圖1 C-Rex 架構(gòu)圖
基礎(chǔ)層中CLE、archinfo 負(fù)責(zé)裝載二進(jìn)制對象及其所依賴的庫并生成地址空間;PyVEX 將匯編代碼轉(zhuǎn)換為中間語言VEX,以實現(xiàn)對不同架構(gòu)的支持;Claripy為符號求解引擎,完成變量符號化、約束生成、約束求解等。平臺層實現(xiàn)了符號執(zhí)行引擎及多種二進(jìn)制程序分析方法?;A(chǔ)層與平臺層共同構(gòu)成了二進(jìn)制分析平臺angr?;谠撈脚_,C-Rex 實現(xiàn)了路徑搜索、可利用性判定、利用樣本生成。
路徑搜索通過動態(tài)分析與混合符號執(zhí)行技術(shù)復(fù)現(xiàn)程序崩潰,當(dāng)復(fù)現(xiàn)失敗時搜索臨近路徑并探索新崩潰點。由于真實環(huán)境及漏洞分析的復(fù)雜性,使得無法保證漏洞復(fù)現(xiàn)及生成漏洞利用樣本的成功率。當(dāng)復(fù)現(xiàn)失敗時,雖然該崩潰路徑無法利用,但一定程度上反應(yīng)出該路徑或周邊路徑在軟件測試階段并未被充分測試,通過對周邊路徑的深入探索,挖掘出新崩潰點的概率較高。因此,當(dāng)復(fù)現(xiàn)失敗時,路徑搜索模塊將采用動態(tài)符號執(zhí)行技術(shù),對崩潰點臨近路徑進(jìn)行搜索,以獲取新崩潰點。
可利用性判定通過收集崩潰現(xiàn)場的運行時信息,分析寄存器中的符號化狀態(tài)、符號化指令指針、符號寫等行為,對劫持程序控制流的行為進(jìn)行監(jiān)控,以實現(xiàn)對漏洞可利用性的判定。
漏洞利用生成負(fù)責(zé)生成多樣性漏洞利用樣本,利用方式可分為代碼注入與代碼復(fù)用兩類。對于代碼注入類利用,首先檢查被用戶輸入數(shù)據(jù)控制的內(nèi)存區(qū)域,搜索滿足條件的連續(xù)內(nèi)存區(qū)域以存放Shellcode。對于代碼復(fù)用類利用,主要采用ret2libc[15]、ROP[16]技術(shù),生成漏洞利用樣本。
C-Rex 在執(zhí)行過程中,首先加載目標(biāo)程序及異常輸入,結(jié)合具體執(zhí)行與動態(tài)符號執(zhí)行復(fù)現(xiàn)崩潰;復(fù)現(xiàn)失敗時,重新探索程序狀態(tài)空間,搜索臨近路徑,挖掘新崩潰點;其次,在獲取到有效Crash 的基礎(chǔ)上,采集崩潰現(xiàn)場數(shù)據(jù),分析EIP、EBP 寄存器及內(nèi)存中符號變量的布局,對Crash 的可利用性作出判定;最后,選取利用方式并生成漏洞約束,對約束集合求解生成漏洞利用樣本。執(zhí)行流程如圖2 所示。
圖2 C-Rex 流程圖
系統(tǒng)實現(xiàn)過程中,使用開源模擬器QEMU[13]獲取程序執(zhí)行路徑,通過該路徑指引動態(tài)符號執(zhí)行路徑;使用angr[12]作為符號執(zhí)行引擎,實現(xiàn)Crash 復(fù)現(xiàn)與新路徑搜索;使用Z3[14]作為約束求解器,以生成漏洞利用樣本。系統(tǒng)由Crash 路徑搜索、可利用性判定、利用生成三個模塊構(gòu)成。
Crash 路徑搜索模塊負(fù)責(zé)復(fù)現(xiàn)崩潰并搜索臨近崩潰點,由Concolic Tracing、Path Explore 兩部分構(gòu)成。其中,Concolic Tracing 負(fù)責(zé)對崩潰進(jìn)行復(fù)現(xiàn),Path Explore負(fù)責(zé)復(fù)現(xiàn)失敗時對臨近路徑的搜索,如圖3 所示。
(1)Concolic Tracing
通過QEMU 加載待分析的二進(jìn)制程序及導(dǎo)致程序崩潰的異常輸入,設(shè)置調(diào)試參數(shù)為“-nochain”、“-exec”、“-page”以獲取程序執(zhí)行路徑,并將執(zhí)行結(jié)果以日志的形式保存。設(shè)置符號執(zhí)行引擎angr 的路徑搜索方式為“Tracer”、“Oppologist”?!癟racer”使得在采用動態(tài)符號執(zhí)行技術(shù)分析程序時,能夠以QEMU 日志中所記錄的執(zhí)行路徑為導(dǎo)向,指引程序沿同一路徑執(zhí)行?!癘ppologist”參數(shù)使得遇到不支持的指令時,將其具體化并使用unicorn 引擎進(jìn)行模擬,從而允許繼續(xù)執(zhí)行。隨后,通過動態(tài)符號執(zhí)行復(fù)現(xiàn)執(zhí)行路徑,若復(fù)現(xiàn)成功,將崩潰時的狀態(tài)保存至Crashed Stash 中;若復(fù)現(xiàn)失敗,將程序執(zhí)行結(jié)束前的最后兩個狀態(tài)保存至Traced Stash 中,以供后續(xù)探索新崩潰點時使用。Stashes 為angr 中的核心概念之一,用以對程序執(zhí)行過程中的狀態(tài)進(jìn)行管理,通過Stashes 可以根據(jù)需要對程序狀態(tài)進(jìn)行過濾、合并、移動等操作。
圖3 Crash路徑搜索
(2)Path Explore
當(dāng)完成Concolic Tracing 且未能成功復(fù)現(xiàn)崩潰時,C-Rex 執(zhí)行Path Explore 以探索臨近路徑,挖掘新崩潰點。首先,獲取Traced Stashes 中存儲的Basic Block 地址;隨后,依據(jù)異常輸入,初始化initial_state 及Simulation Manager;將獲取到的Basic Block 地址作為約束條件,依托angr 進(jìn)行動態(tài)符號執(zhí)行,通過監(jiān)測執(zhí)行過程中是否出現(xiàn)Unconstrained 狀態(tài),以判斷是否成功挖掘出新崩潰點。
(3)參數(shù)優(yōu)化
C-Rex 在實現(xiàn)過程中,通過優(yōu)化以提高執(zhí)行效率,首先對分析平臺angr 進(jìn)行訂制,通過冗余路徑剪枝、狀態(tài)合并等方式提高效率;其次通過增加前置約束,以緩解動態(tài)符號執(zhí)行過程中出現(xiàn)的狀態(tài)空間爆炸、路徑選擇等問題。優(yōu)化內(nèi)容如表1 所示,Content 表示優(yōu)化項目、Options 表示優(yōu)化內(nèi)容。
表1 參數(shù)優(yōu)化
表2 崩潰類型
State 是angr 中用以存儲程序狀態(tài)的對象,其中包含當(dāng)前狀態(tài)中的內(nèi)存、寄存器、文件系統(tǒng)及任何會在執(zhí)行中改變的數(shù)據(jù)。C-Rex 在判定崩潰的可利用性時,首先獲取發(fā)生異常時的state,通過state.regs.ip、state.regs.bp、state.mem 訪問此刻的寄存器及內(nèi)存狀態(tài),判斷其中符號變量的分布,針對IP_OVERWRITE、BP_OVERWRITE、 PARTIAL_IP_OVERWRITE、 PARTIAL_BP_OVERWRITE、 WRITE_WHAT_WHERE、 WRITE_X_WHERE 六類異常,能夠生成劫持控制流的漏洞利用樣本。
(1)代碼注入
C-Rex 使用shellcode 作為Payload,將其注入具有執(zhí)行權(quán)限且可控的內(nèi)存空間,通過覆蓋程序返回地址以劫持控制流,完成漏洞利用。在實現(xiàn)過程中,C-Rex通過state 中的memory 接口獲取崩潰時的內(nèi)存布局,查找其中連續(xù)且具有執(zhí)行權(quán)限的地址空間,隨后選取shellcode 并計算其長度。在劫持程序控制流時,首先采取以shellcode 起始地址覆蓋函數(shù)返回地址的方式,通過函數(shù)返回地址、shellcode 地址、shellcode 長度構(gòu)造約束條件并求解,若求解成功則生成以shellcode 起始地址覆蓋函數(shù)返回地址的漏洞利用樣本。若求解失敗,則搜索內(nèi)存中存在的“jmp esp”指令,使用該指令的地址覆蓋函數(shù)返回地址實現(xiàn)對程序控制流的劫持。通過已獲取的“jmp esp”指令地址、崩潰時的內(nèi)存布局、shellcode 長度,構(gòu)造約束條件并求解,生成使用“jmp esp”作為跳板的漏洞利用樣本。
(2)代碼復(fù)用
代碼復(fù)用攻擊是指通過存在漏洞的二進(jìn)制程序地址空間中已存在的代碼片段構(gòu)造惡意代碼,主要包括:ret2libc、ROP、JOP 等技術(shù)。C-Rex 在實現(xiàn)過程中,主要針對ret2libc 與ROP 兩種方式。
ret2libc 技術(shù)不以Shellcode 為Payload,而是將控制流導(dǎo)向庫函數(shù)入口,通過執(zhí)行庫函數(shù)以實現(xiàn)惡意功能。由于庫函數(shù)具有可執(zhí)行權(quán)限,因此ret2libc 可以繞過DEP 的保護(hù)。在實現(xiàn)過程中程序依賴共享庫libc.so.6,其中包含大量可利用函數(shù),在不考慮ASLR 的情況下,共享庫的加載基址不會改變,C-Rex 首先獲取system()函數(shù)、“/bin/sh”字符串在共享庫中的偏移,結(jié)合基址計算出內(nèi)存中的真實地址,劫持控制至system()函數(shù),通過執(zhí)行system(“/bin/sh”)獲取本地shell。
ret2libc 以函數(shù)為單位進(jìn)行代碼復(fù)用,在實際應(yīng)用中缺乏靈活性,因此C-Rex 實現(xiàn)了第二種復(fù)用方式ROP(Return-Oriented Programming)。ROP 技術(shù)通過串接以ret 指令為結(jié)尾的代碼片段(gadgets)實現(xiàn)惡意功能。C-Rex 調(diào)用angrop 查找所需gadgets 并自動構(gòu)建ROP 鏈,最終實現(xiàn)ROP 攻擊。
運用Epidata 3.1對數(shù)據(jù)進(jìn)行雙錄入,采用SPSS 20.0對數(shù)據(jù)進(jìn)行整理與分析。符合正態(tài)分布的計量資料以(±s)表示,采用t檢驗進(jìn)行組間比較;計數(shù)資料以例數(shù)(%)表示,采用x2檢驗進(jìn)行組件比較。P<0.05為差異有統(tǒng)計學(xué)意義。
為了驗證C-Rex 自動生成漏洞利用的效果,我們設(shè)計了兩類實驗。首先,通過存在漏洞的CTF 題目,以驗證C-Rex 的有效性;其次,以AEG 所使用的測試集為基礎(chǔ),從中選取10 款包含漏洞的開源應(yīng)用,評估生成效果。
(1)實驗環(huán)境
本文中所使用的實驗環(huán)境如下:處理器采用Intel Core i7 2.5 GHz,內(nèi)存為DDR3 1600MHz 16GB,操作系統(tǒng)為Ubuntu 18.04 x86_64,編譯器為GCC 7.3.0[17],編譯時使用-O2、-z execstack、-fno-stack-protector、-nopie、-z norelro 選項,禁用FORTIFY、NX、Canary、PIE、RELRO。
(2)有效性驗證
使用Insomni Hack CTF 2016[18]中的題目作為測試樣例。存在漏洞的源碼如圖4 所示,代碼中為字符數(shù)組component_name 分配的空間為128 字節(jié),為結(jié)構(gòu)體component 中的成員name 分配的空間為32 字節(jié)。溢出點位于第十行,將cmp_name 中的數(shù)據(jù)復(fù)制至cmp->name 時,未對緩沖區(qū)邊界進(jìn)行檢查,導(dǎo)致緩沖區(qū)溢出進(jìn)而對程序控制流進(jìn)行劫持。
圖4 漏洞源碼
使用GCC 對源碼進(jìn)行編譯,生成二進(jìn)制程序Demo_Vul,構(gòu)造異常輸入36 個“A”。通過C-Rex 加載Demo_Vul 及異常輸入,最終成功生成漏洞利用樣本,劫持Demo_Vul 控制流并獲得本地shell,驗證了CRex 的有效性。
(3)對比測試
以AEG 的測試集為基礎(chǔ),從中選取10 款開源應(yīng)用,通過C-Rex 以及Rex 自動生成漏洞利用樣本,表4總結(jié)了實驗結(jié)果。其中,“Program”為開源應(yīng)用名稱、“Version”為所對應(yīng)版本、“Input Src”為輸入數(shù)據(jù)的類型、“Vul Type”為漏洞類型、“C-Rex”為C-Rex 生成結(jié)果、“Rex”為Rex 生成結(jié)果、“Advisory ID”為漏洞所對應(yīng)CVE/OSVDB 編號。
表4 實驗結(jié)果
對比C-Rex 與Rex 的實驗結(jié)果可以看出,由Shellphish[19]開發(fā)的漏洞自動利用系統(tǒng)Rex,其設(shè)計初衷在于參加CGC 競賽,因此對真實應(yīng)用程序的支持并不完善,對于選取的10 款開源應(yīng)用均無法生成漏洞利用樣本。本文所提出的漏洞利用自動生成系統(tǒng)C-Rex 在實驗當(dāng)中,針對10 款開源應(yīng)用,均能夠成功生成漏洞利用樣本,有效驗證了C-Rex 的實用性。
2008 年D. Brumley 等人在IEEE S&P 會議上,首次提出了基于補丁比對的漏洞利用自動生成方法APEG。由于該方法操作性強,因此在實際測試過程中取得了良好的效果,并得到了安全研究者的普遍認(rèn)可。其不足主要表現(xiàn)在:首先,對補丁程序的依賴;其次,隨著軟件復(fù)雜度的提升,簡單的指令比對難以快速定位漏洞位置,與漏洞無關(guān)的補丁也對分析漏洞機(jī)理造成了一定的影響;再次,APEG 所生成的利用程序以DoS 為主,對漏洞的利用程度有限。
2011 年CMU 的T.Avgerinos 等人在NDSS 會議上首次提出了基于源碼的漏洞利用自動生成方法AEG。該方案能夠針對棧溢出、格式化字符串漏洞生成具備控制流劫持能力的利用樣本,是首個完整實現(xiàn)從漏洞挖掘到漏洞利用生成全流程的自動化解決方案。該方法的局限性主要體現(xiàn)在:首先,依賴源代碼;其次,所針對的漏洞類型限于棧溢出與格式化字符串,無法處理整型溢出、堆溢出等類型的漏洞;最后,生成的利用程序?qū)ο到y(tǒng)環(huán)境依賴嚴(yán)重。
2012 年Shih-Kun Huang 等人提出了基于異常輸入的漏洞利用自動生成系統(tǒng)CRAX。相較于AEG 采用動態(tài)分析技術(shù)獲取崩潰點的動態(tài)信息,CRAX 采用回溯分析獲取漏洞點的動態(tài)信息,提高了所生成的漏洞利用程序的成功率。該方法的局限性主要體現(xiàn)在,對導(dǎo)致程序崩潰的異常輸入的強依賴,能否成功生成利用程序與異常輸入數(shù)據(jù)密切相關(guān)。
2018 年Wei Wu 等人在USENIX 安全會議上首次提出了基于內(nèi)核UAF 漏洞的漏洞利用自動生成系統(tǒng)FUZE。該方案綜合運用模糊測試、符號執(zhí)行、動態(tài)追蹤等技術(shù),針對內(nèi)核UAF 漏洞自動生成利用程序。通過對15 個內(nèi)核UAF 漏洞進(jìn)行測試,F(xiàn)UZE 成功生成利用程序并一定程度上繞過保護(hù)機(jī)制,證明了該方法的有效性。
2018 年Yan Wang 等人在CCS 安全會議上提出了針對堆漏洞的解決方案Revery。該方案在實現(xiàn)過程中,首先,分析漏洞位置和相關(guān)內(nèi)存布局,建立異常對象內(nèi)存布局圖、內(nèi)存布局貢獻(xiàn)者圖;其次,以異常對象的內(nèi)存布局為導(dǎo)向,采用定向Fuzzing 探索替代路徑,并結(jié)合污點分析技術(shù),在替代路徑中探索可利用狀態(tài);最后,確定拼接點、拼接路徑,組合生成漏洞利用路徑。求解約束集合并生成漏洞利用樣本。在測試過程中,Revery 以19 個CTF 賽題為樣本,對其中9 個程序自動生成漏洞利用,5 個可以自動化轉(zhuǎn)化為可利用狀態(tài),證明了該方法的有效性。
本文提出基于Crash 的漏洞利用自動生成方法CRex,該方法包含Crash 路徑搜索、可利用性判定、利用生成三個環(huán)節(jié)。在實驗中,能夠?qū)TF 題目及10 款開源應(yīng)用成功生成劫持控制流的漏洞利用樣本,證明了C-Rex 的有效性。C-Rex 采用angr 作為符號執(zhí)行引擎,但目前angr 缺少必要的系統(tǒng)調(diào)用支持,使得C-Rex對大型應(yīng)用的支持并不完善,同時C-Rex 所能解決的漏洞限于經(jīng)典的棧溢出,并不適用于更復(fù)雜的漏洞類型,以上問題的解決有待于更進(jìn)一步的研究。