周鵬 倪昀澤
【摘 要】隨著網(wǎng)絡(luò)安全技術(shù)的快速發(fā)展,越來(lái)越多的漏洞掃描、源碼檢測(cè)、代碼審計(jì)相關(guān)軟件被開(kāi)發(fā)出來(lái)。很多工具號(hào)稱(chēng)運(yùn)用符號(hào)執(zhí)行、污點(diǎn)跟蹤、機(jī)器學(xué)習(xí)等多種技術(shù)提升效率并改善性能。然而,由于缺乏大量已分類(lèi)的標(biāo)準(zhǔn)化漏洞測(cè)試樣本,采購(gòu)人員和研究人員無(wú)法準(zhǔn)確評(píng)估各工具掃描結(jié)果的有效性。因此,本文提出了一種基于源碼的漏洞測(cè)試樣本自動(dòng)化生成技術(shù)。通過(guò)分析源碼代碼結(jié)構(gòu)特征,結(jié)合已知漏洞類(lèi)型,自動(dòng)化將漏洞代碼注入到源碼中來(lái)生成大量含有漏洞的軟件測(cè)試用例。本文選取了一些開(kāi)源軟件作為測(cè)試目標(biāo),并成功在源代碼中插入多個(gè)可利用的漏洞。通過(guò)提供標(biāo)準(zhǔn)化、多樣化的漏洞程序樣本,為漏洞掃描工具提供統(tǒng)一的評(píng)判基礎(chǔ)。
【關(guān)鍵詞】漏洞掃描;評(píng)估測(cè)試;測(cè)試用例
中圖分類(lèi)號(hào): TP309 文獻(xiàn)標(biāo)識(shí)碼: A 文章編號(hào): 2095-2457(2018)18-0174-003
DOI:10.19694/j.cnki.issn2095-2457.2018.18.078
【Abstract】With the rapid development of network security technology,more and more related softwares such as vulnerability scanning,source code detection and code auditing have been developed.Many tools claim to improve efficiency and performance by using symbolic execution,stain tracking,machine learning and many other technologies. However,due to the lack of a large number of classified standardized test samples,buyers and researchers can not accurately evaluate the effectiveness of the tool scanning results.Therefore,this paper proposes an automatic generation technology of vulnerability test samples based on source code.By analyzing the structure features of the source code and combining the known vulnerability types,the vulnerability code is automatically injected into the source code to generate a large number of software test cases containing vulnerabilities.This article selects some open source software as the test target,and successfully inserts some exploitable vulnerabilities into the source code.By providing standardized and diversified vulnerability program samples,it provides a unified evaluation basis for vulnerability scanning tools.
【Key words】Vulnerability Scanning;Evaluation and Test;Test Samples
0 引言
漏洞檢測(cè)技術(shù)一直以來(lái)都是軟件安全研究的一個(gè)重要領(lǐng)域。隨著多年的研究,經(jīng)過(guò)了黑盒測(cè)試、白盒測(cè)試以及當(dāng)今主流的灰盒測(cè)試三個(gè)階段,引入了符號(hào)執(zhí)行、污點(diǎn)跟蹤、代碼插樁等智能化技術(shù),也有的研究人員引入了機(jī)器學(xué)習(xí)這一門(mén)全新的技術(shù)。為了提升性能和速度,研究者不斷引入新的技術(shù),產(chǎn)生了大量的不同技術(shù)結(jié)合的工具框架。然而,對(duì)于一款工具框架的性能評(píng)估始終缺乏一個(gè)統(tǒng)一的標(biāo)準(zhǔn)。就Fuzzing工具而言,從已有的論文來(lái)[1][2]看,許多Fuzzing框架采用的測(cè)試集通常來(lái)自于兩個(gè)部分:一是歷史上存在漏洞的軟件,二是網(wǎng)絡(luò)上公開(kāi)可供下載的最新軟件。此外,不同F(xiàn)uzzing技術(shù)之間的側(cè)重點(diǎn)不一樣,例如TaintScope[3]側(cè)重于解決軟件的校驗(yàn)問(wèn)題,AFLFast[4]側(cè)重于加快發(fā)現(xiàn)漏洞的過(guò)程,因此采用統(tǒng)一的、標(biāo)準(zhǔn)化的測(cè)試集有助于分析不同框架的優(yōu)勢(shì)和劣勢(shì),從而為下一步的研究提供參考。本文旨在通過(guò)自動(dòng)化在源碼中注入不同類(lèi)型及深度的漏洞來(lái)生成一個(gè)標(biāo)準(zhǔn)化的漏洞測(cè)試樣例。通過(guò)智能分析給定開(kāi)源軟件代碼模塊,在滿足條件的代碼點(diǎn)注入漏洞,同時(shí)保證漏洞滿足:數(shù)量多、類(lèi)型豐富;覆蓋整個(gè)程序運(yùn)行周期;盡可能與輸入相關(guān);可觸發(fā)并且有觸發(fā)樣例;不改變程序正常功能;盡可能貼近真實(shí)。此外,我們實(shí)現(xiàn)了一套原型工具,可以注入常見(jiàn)漏洞,如緩沖區(qū)溢出、循環(huán)邊界溢出,并可以注入到不同的代碼深度。最終,可以提供注入漏洞數(shù)量、漏洞類(lèi)型以及對(duì)應(yīng)漏洞的觸發(fā)樣例,用于分析漏洞掃描工具實(shí)際運(yùn)行效果。
1 總覽
在本節(jié)中,我們將會(huì)給出本文的目標(biāo),并解釋自動(dòng)化漏洞注入的設(shè)計(jì)方法及原理。
1.1 目標(biāo)與范圍
總的來(lái)說(shuō),我們希望能夠做到自動(dòng)化地應(yīng)用程序中注入能夠影響程序安全性的漏洞。如上所述,我們專(zhuān)注于給漏洞挖掘程序制造測(cè)試樣例。論文中涉及的軟件設(shè)計(jì)方法并不僅限于源代碼,也可以面向二進(jìn)制程序,但在本論文中所涉及的技術(shù)將主要面向能夠提供源代碼的程序。
1.2 路徑搜索
這一部分實(shí)際上是求解觸發(fā)一條代碼分支需要的輸入,我們把這些輸入叫做INPUTS。INPUTS將會(huì)作為整個(gè)程序分析的基礎(chǔ)數(shù)據(jù),好的INPUTS數(shù)據(jù)集應(yīng)當(dāng)做到盡可能高的覆蓋率,因此本小節(jié)主要討論的內(nèi)容是如何快速有效地生成大量不同的INPUTS,不同意味著能夠形成不一樣的代碼路徑。遍歷程序所有可能的路徑事實(shí)上是一件很困難的事情,理論上窮舉所有可能的輸入才能夠達(dá)到這個(gè)目標(biāo)的。在本論文中,我們采用符號(hào)執(zhí)行的方法獲取初始的INPUTS集。如圖所示,在state等于1000的條件下可以觸發(fā)帶漏洞的函數(shù)。但是,理論上可以觸發(fā)漏洞的路徑理論上是無(wú)窮多的,比如我們可以構(gòu)造類(lèi)似1-1+{重復(fù)一萬(wàn)次}+1{重復(fù)一千次}的表達(dá)式。在這一類(lèi)問(wèn)題的處理上目前來(lái)看沒(méi)有太好的辦法,只能通過(guò)大量的測(cè)試來(lái)確定一個(gè)輸入是否有效。
1.3 潛在漏洞
這在真實(shí)軟件中存在各種各樣的漏洞,從簡(jiǎn)單的緩沖區(qū)溢出[5]、整數(shù)溢出[6],到偶然的錯(cuò)誤如條件競(jìng)爭(zhēng)引起的死鎖,或者是在編譯時(shí)由于存在未定義行為而引入的Bug[7]。本文中討論的漏洞主要分為緩沖區(qū)溢出、整數(shù)溢出、數(shù)組邊界溢出。我們簡(jiǎn)單介紹一下常見(jiàn)的緩沖區(qū)溢出和數(shù)組邊界溢出的原理及成因。
1.緩沖區(qū)溢出:這一類(lèi)的形成原因通常有幾種情況:一、調(diào)用了gets,fgets等可以無(wú)限制輸入的函數(shù)。二、調(diào)用read、scanf函數(shù)的時(shí)候沒(méi)有對(duì)讀入數(shù)據(jù)的大小進(jìn)行校驗(yàn),當(dāng)讀入長(zhǎng)度可控成為一個(gè)較大值的時(shí)候,就會(huì)造成緩沖區(qū)溢出。三、調(diào)用了strncpy、memcpy等內(nèi)存拷貝函數(shù)時(shí)沒(méi)有對(duì)拷貝數(shù)據(jù)的長(zhǎng)度進(jìn)行有效校驗(yàn)。
2.數(shù)組邊界溢出:這一類(lèi)漏洞比較容易出現(xiàn)在循環(huán)中,通常會(huì)造成數(shù)組越界讀或越界寫(xiě)。造成這一類(lèi)漏洞的原因主要可以分為兩種情況:1.在計(jì)算循環(huán)邊界時(shí)沒(méi)有對(duì)計(jì)算出的結(jié)果進(jìn)行校驗(yàn);2.計(jì)算訪問(wèn)數(shù)組的下標(biāo)時(shí)出現(xiàn)了溢出等錯(cuò)誤使得實(shí)際的數(shù)組下標(biāo)超過(guò)數(shù)組空間實(shí)際大小。
產(chǎn)生這些漏洞的原因包括大致可以歸為三點(diǎn):
●沒(méi)有檢查參數(shù)或者檢查不夠嚴(yán)格
●循環(huán)邊界檢查錯(cuò)誤或不嚴(yán)
●錯(cuò)誤使用API,導(dǎo)致程序存在未定義行為
●基于以上產(chǎn)生漏洞的原因,潛在的漏洞點(diǎn)可以具備以下幾個(gè)特征:
●調(diào)用容易產(chǎn)生漏洞的函數(shù),比如read、memcpy、malloc、free等
●擁有數(shù)據(jù)校驗(yàn),比如檢查輸入的長(zhǎng)度是否超過(guò)了緩沖區(qū)的大小
●循環(huán)邊界與輸入相關(guān),比如基于循環(huán)的數(shù)據(jù)讀寫(xiě)操作
以上特征將會(huì)作為尋在潛在漏洞注入點(diǎn)的重要依據(jù)。
2 實(shí)現(xiàn)
在本章節(jié)中,我們將詳細(xì)介紹測(cè)試集生成軟件的框架結(jié)構(gòu)以及設(shè)計(jì)細(xì)節(jié),以及使用的相關(guān)工具和技術(shù)。
2.1 系統(tǒng)流程
總本文把整個(gè)系統(tǒng)的工作流程分為5個(gè)部分,依次為生成遍歷樣本、標(biāo)記注入點(diǎn)、搜集運(yùn)行數(shù)據(jù)、注入漏洞、POC驗(yàn)證。
首先使用符號(hào)執(zhí)行工具KLEE來(lái)生成初始的樣本集INPUTS。KLEE是一款基于源碼的符號(hào)執(zhí)行分析工具[8],通過(guò)KLEE我們可以構(gòu)造面向特定程序的測(cè)試樣例。標(biāo)記注入點(diǎn)的目標(biāo)主要是尋在潛在漏洞注入點(diǎn),并插入信息收集函數(shù),最終編譯出程序P。接下來(lái)是將INPUTS作為輸入交給P來(lái)解析,由于已經(jīng)在源碼中插入了信息收集函數(shù),所以我們可以在程序運(yùn)行結(jié)束后獲取程序運(yùn)行時(shí)信息。根據(jù)運(yùn)行時(shí)信息,結(jié)合具體的代碼特征就可以構(gòu)造對(duì)應(yīng)的漏洞及POC樣本。構(gòu)造完漏洞之后的一個(gè)步驟是測(cè)試POC樣本能否使得應(yīng)用程序出現(xiàn)錯(cuò)誤,包括程序崩潰及內(nèi)存越界讀寫(xiě)。
2.2 標(biāo)記注入點(diǎn)
根據(jù)小節(jié)1.3中對(duì)于三種不同漏洞類(lèi)型產(chǎn)生原因的分析,注入點(diǎn)選取按照如下幾個(gè)步驟進(jìn)行。
2.2.1 定位潛在注入點(diǎn)
根據(jù)實(shí)際分析經(jīng)驗(yàn),我們?cè)谙到y(tǒng)中預(yù)置了一個(gè)函數(shù)集,該函數(shù)集包含了常見(jiàn)的可能導(dǎo)致漏洞的函數(shù),例如memcpy、malloc、strcpy等,通過(guò)搜索這一類(lèi)函數(shù)在程序中的調(diào)用點(diǎn),我們可以獲取第一類(lèi)注入點(diǎn)。Ⅱ.定位用于判斷輸入數(shù)據(jù)是否符合條件的if語(yǔ)句。If語(yǔ)句通常用于對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),例如判斷需要讀入的數(shù)據(jù)長(zhǎng)度是否超過(guò)緩沖區(qū)大小、是否滿足magic校驗(yàn)等,這是第二類(lèi)注入點(diǎn)。Ⅲ.第三類(lèi)注入點(diǎn)主要針對(duì)循環(huán)中進(jìn)行的數(shù)據(jù)讀寫(xiě)操作。
2.2.2 插入信息收集函數(shù).
主要用來(lái)收集程序運(yùn)行時(shí)在所有潛在注入點(diǎn)產(chǎn)生的數(shù)據(jù)。收集的數(shù)據(jù)包括函數(shù)參數(shù)、if條件表達(dá)式涉及的變量、循環(huán)邊界、完整輸入數(shù)據(jù)及相關(guān)源代碼信息。
2.3 注入漏洞
在收集到程序運(yùn)行時(shí)數(shù)據(jù)之后,我們需要做到是判斷能否將一個(gè)潛在注入點(diǎn)轉(zhuǎn)換成漏洞。構(gòu)造漏洞的方式主要有三種:一、修改malloc、strncpy等函數(shù)調(diào)用參數(shù),構(gòu)造緩沖區(qū)溢出漏洞;二、刪除或弱化if判斷條件;三、修改循環(huán)邊界。在圖示代碼中,我們通過(guò)弱化if判斷條件,將輸入長(zhǎng)度增加到了1000字節(jié),從而在這里構(gòu)造了一個(gè)緩沖區(qū)溢出漏洞。當(dāng)然,我們還可以做一些其他的變化,例如對(duì)len進(jìn)行乘法操作,使其值變?yōu)樵瓉?lái)的2倍的方式來(lái)構(gòu)造漏洞。
2.4 PoC驗(yàn)證
事實(shí)上并不是每一個(gè)漏洞都會(huì)導(dǎo)致程序崩潰,一部分內(nèi)存破壞問(wèn)題并不會(huì)影響程序的繼續(xù)運(yùn)行,在檢測(cè)這一類(lèi)漏洞時(shí)需要用到內(nèi)存破壞檢測(cè)工具ASAN(AddressSanitizer)。ASAN是廣泛在開(kāi)源軟件(如Chrome和Firefox)中廣泛使用的內(nèi)存破壞檢測(cè)工具。ASAN可以檢測(cè)的內(nèi)存破壞漏洞包括緩沖區(qū)溢出、由UAF導(dǎo)致的懸掛指針引用等[9]。ASAN編譯時(shí)會(huì)在代碼中加入檢測(cè)代碼,通過(guò)在程序初始化時(shí)申請(qǐng)的一塊內(nèi)存來(lái)記錄某一塊內(nèi)存所處的狀態(tài),ASAN可以實(shí)現(xiàn)對(duì)每一個(gè)字節(jié)的訪問(wèn)檢測(cè)。如果程序在運(yùn)行過(guò)程中出現(xiàn)了崩潰或者ASAN檢測(cè)到了內(nèi)存溢出,則說(shuō)明POC樣本為有效樣本,當(dāng)然對(duì)應(yīng)的漏洞也是可觸發(fā)的。
在上述示例程序中,雖然程序中存在堆溢出漏洞,但是這個(gè)漏洞并不會(huì)導(dǎo)致程序崩潰,因此檢測(cè)這種這種問(wèn)題借助ASAN工具來(lái)完成。
3 評(píng)估
我們從性能、漏洞質(zhì)量以及注入漏洞可利用性等方面對(duì)原型系統(tǒng)進(jìn)行評(píng)估測(cè)試。
本文從GITHUB選取了三個(gè)開(kāi)源項(xiàng)目進(jìn)行測(cè)試。在實(shí)驗(yàn)當(dāng)中,我們?cè)诖a中插入了多個(gè)漏洞,并且漏洞的數(shù)量跟隨代碼增加而增加。經(jīng)過(guò)評(píng)估,插入的漏洞并非全部為可攻擊的漏洞,例如我們?cè)贑-Crawler中插入了3個(gè)漏洞,但只有1個(gè)是能夠使用POC樣本觸發(fā)的。
3.1 系統(tǒng)配置
實(shí)驗(yàn)環(huán)境 Ubuntu 16.04, with an Intel Core i7-6500 @ 2.59GHz, 8GB DDR3-RAM @ 1600MHz and a 512GB SSD。
3.2 系統(tǒng)性能
在實(shí)驗(yàn)中,我們嘗試在三個(gè)開(kāi)源代碼中注入漏洞,我們選擇了C-interpreter(一個(gè)簡(jiǎn)易版C語(yǔ)言解釋器)、linux-coreutils(linux下基本命令的實(shí)現(xiàn)代碼,從中選取了base64、ls等部分命令進(jìn)行測(cè)試)、C-Crawler(一個(gè)自己開(kāi)發(fā)的C語(yǔ)言爬蟲(chóng)項(xiàng)目)。
正如我們?cè)赥able 2中能夠看到的,由于采用了符號(hào)執(zhí)行的方法來(lái)生成測(cè)試樣例,整個(gè)系統(tǒng)在路徑搜索階段花費(fèi)了大量的時(shí)間。需要注意的是,運(yùn)行所需的時(shí)間并不一定和代碼量相關(guān)。例如,C-interpreter代碼量最少,但是由于其中涉及大量重復(fù)性的解析工作,所以生成測(cè)試樣例的時(shí)間反而最長(zhǎng)。
4 結(jié)論
本文提出并設(shè)計(jì)了一種基于符號(hào)執(zhí)行的漏洞自動(dòng)注入方案,并且該原型系統(tǒng)在選擇的開(kāi)源工程中成功插入了多個(gè)漏洞,其中包含多個(gè)可以用漏洞。當(dāng)然,該原型系統(tǒng)依然存在較大局限性,例如符號(hào)執(zhí)行在路徑搜索時(shí)普遍面臨的路徑爆炸問(wèn)題,并且符號(hào)執(zhí)行本身也需要對(duì)特殊運(yùn)行環(huán)境進(jìn)行適配。
目前,我們僅實(shí)現(xiàn)了在源碼層面的簡(jiǎn)單漏洞注入,后續(xù)希望能夠?qū)崿F(xiàn)在二進(jìn)制層面的漏洞注入,同時(shí)也希望本文能夠促進(jìn)基于源碼的軟件漏洞自動(dòng)化挖掘工具的研究工作。
【參考文獻(xiàn)】
[1]Stephens N,Grosen J,Salls C,et al.Driller:Augmenting Fuzzing Through Selective Symbolic Execution[C]//Network and Distributed System Security Symposium.2016.
[2]Rawat S,Jain V,Kumar A,et al.VUzzer:Application-aware Evolutionary Fuzzing[C]// NDSS.2017.
[3]Bhme M,Pham V T,Roychoudhury A.Coverage-based Greybox Fuzzing as Markov Chain[J].IEEE Transactions on Software Engineering,2017,PP(99):1-1.
[4]Wang T,Wei T,Gu G,et al.TaintScope:A Checksum-Aware Directed Fuzzing Tool for Automatic Software Vulnerability Detection[C]// IEEE Symposium on Security and Privacy.IEEE Computer Society,2010:497-512.
[5]Aleph O.Smashing the stack for fun and profit[J].http://www.shmoo.com/phrack/Phrack49/p49-14,1996.
[6]Dietz W,Li P,Regehr J,et al.Understanding integer overflow in C/C++[J].ACM Transactions on Software Engineering and Methodology (TOSEM),2015,25(1):2.
[7]Wang X,Chen H,Cheung A,et al.Undefined behavior:what happened to my code?[C]//Proceedings of the Asia-Pacific Workshop on Systems.ACM,2012:9.
[8]Cadar C,Dunbar D,Engler D.KLEE:unassisted and automatic generation of high-coverage tests for complex systems programs[C]// Usenix Conference on Operating Systems Design and Implementation.USENIX Association,2009:209-224.
[9]Serebryany K,Bruening D,Potapenko A,et al.AddressSanitizer:A Fast Address Sanity Checker[C]//USENIX Annual Technical Conference.2012:309-318.