国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于懸空指針追蹤的UAF 漏洞檢測(cè)方法研究

2024-08-23 00:00:00許敏胡勇李新建

摘要: 隨著UAF 漏洞的關(guān)注度上升,其利用方式更加多樣,對(duì)計(jì)算機(jī)系統(tǒng)造成的威脅愈發(fā)嚴(yán)重. 因此,本文提出一個(gè)輕量級(jí)的UAF 漏洞檢測(cè)方案. 該方案在LLVM IR 的基礎(chǔ)上收集被測(cè)試程序中所有可能的懸空指針;然后,對(duì)它們進(jìn)行精準(zhǔn)的數(shù)據(jù)流分析和控制流分析后,可以排除再次定義的指針,得到所有懸空指針;最后,對(duì)懸空指針進(jìn)行可達(dá)性分析和數(shù)據(jù)流分析即可得到UAF 漏洞的操作序列. 該方案還通過2 種方式減少系統(tǒng)開銷:將過程間分析簡(jiǎn)化為過程內(nèi)分析和結(jié)合數(shù)據(jù)流分析的別名分析算法. 在開源的測(cè)試用例和真實(shí)程序上測(cè)試的實(shí)驗(yàn)結(jié)果表明,該方案可以快速、準(zhǔn)確地識(shí)別出代碼中的UAF 漏洞,并報(bào)告危險(xiǎn)的操作序列.

關(guān)鍵詞: 懸空指針; LLVM; UAF; 漏洞檢測(cè)

中圖分類號(hào): TP391. 1 文獻(xiàn)標(biāo)志碼: A DOI: 10. 19907/j. 0490-6756. 2024. 043001

1 引言

根據(jù)NIST 的統(tǒng)計(jì)數(shù)據(jù)[1]顯示,2021 年公布的新增漏洞數(shù)量再創(chuàng)新高,達(dá)到20 158 個(gè). 如圖1 所示,釋放后重用(Use-After-Free,UAF)漏洞自2015 年開始逐漸增多. 這主要是由于開發(fā)人員的安全意識(shí)提高和眾多堆棧保護(hù)機(jī)制的廣泛應(yīng)用,使得溢出漏洞發(fā)現(xiàn)和利用的難度加大,研究人員逐漸轉(zhuǎn)向發(fā)現(xiàn)和利用堆運(yùn)行機(jī)制漏洞. Yan 等[2]的研究表明,NVD 數(shù)據(jù)庫中有80. 14% 的UAF 漏洞被評(píng)為高?;驀?yán)重等級(jí). 相比之下,大約只有50%的堆緩沖區(qū)溢出漏洞被視為高危等級(jí)的漏洞[3].UAF 漏洞作為堆內(nèi)存分配機(jī)制的基本漏洞,可以通過它對(duì)計(jì)算機(jī)系統(tǒng)進(jìn)行更復(fù)雜且危害性更大的攻擊. 如HeapFengShui[4]等,可能導(dǎo)致拒絕服務(wù),信息泄漏,甚至是任意代碼執(zhí)行攻擊.

UAF 漏洞由2 個(gè)條件組成:(1) 產(chǎn)生懸空指針;(2) 使用懸空指針. 其中懸空指針是指指向的內(nèi)存對(duì)象被釋放后沒有被正確處理的指針. 因此若要檢測(cè)UAF 漏洞或緩解UAF 漏洞帶來的危害,檢測(cè)懸空指針就顯得尤為重要.

目前針對(duì)懸空指針的檢測(cè)也有一些成熟的技術(shù). DangSan[5]以LLVM[6]編譯框架插件的形式工作,通過指針追蹤器和內(nèi)存對(duì)象追蹤器分別追蹤內(nèi)存對(duì)象指針和內(nèi)存對(duì)象,并使用映射器將其關(guān)聯(lián). 最后在內(nèi)存對(duì)象被釋放時(shí)得到相應(yīng)的懸空指針,并使其失效,從而達(dá)到防止UAF 漏洞的目的.不過由于指針追蹤的復(fù)雜性導(dǎo)致存在誤報(bào),并且指針追蹤器追蹤所有指針導(dǎo)致開銷較大. 為了解決開銷問題,HeapExpo[7]在DangSan 的基礎(chǔ)上進(jìn)行改進(jìn),對(duì)每個(gè)函數(shù)的局部指針和指針參數(shù)進(jìn)行活躍分析,配合LLVM 的mem2reg 優(yōu)化,從而減少需要跟蹤的指針變量數(shù)量,減小了系統(tǒng)開銷. DangNULL[8]和FreeSentry[9]也是追蹤指針傳播,并記錄指針與對(duì)象之間的關(guān)系. 不過二者用于記錄的數(shù)據(jù)結(jié)構(gòu)不同,前者采用紅黑樹進(jìn)行元數(shù)據(jù)存儲(chǔ),其中每個(gè)節(jié)點(diǎn)對(duì)應(yīng)1 個(gè)內(nèi)存對(duì)象和所有指向該內(nèi)存對(duì)象的指針,而后者使用2 個(gè)查找表作為其元數(shù)據(jù)存儲(chǔ):一個(gè)表記錄從指針到其引用的內(nèi)存對(duì)象的所有映射,另一個(gè)表記錄從內(nèi)存對(duì)象到引用它的指針的所有映射. 在跟蹤指針傳播方面,Dang?Null 只跟蹤數(shù)據(jù)段和堆中的指針,不跟蹤堆?;蚣拇嫫髦械闹羔? 而FreeSentry 跟蹤堆棧上的指針,但不跟蹤寄存器中的指針. 因此,這會(huì)導(dǎo)致UAF漏洞漏報(bào).

此外,也有一些專門針對(duì)UAF 漏洞的自動(dòng)檢測(cè)技術(shù),根據(jù)是否需要運(yùn)行程序分為2 類:靜態(tài)檢測(cè)和動(dòng)態(tài)檢測(cè). 靜態(tài)檢測(cè),如CBMC[10]、Coccinelle[11]、Clang 靜態(tài)分析器[12]和TscanCode[13]等,通過在不執(zhí)行程序的情況下分析源代碼或機(jī)器代碼來發(fā)現(xiàn)程序中潛在的UAF 漏洞;而動(dòng)態(tài)檢測(cè),如Valgrind[14]和Dr. Memory[15]等,在程序執(zhí)行期間報(bào)告潛在的UAF 漏洞.

在眾多靜態(tài)檢測(cè)技術(shù)中,UAFChecker[16]通過構(gòu)建有限狀態(tài)機(jī)來檢測(cè)程序中的所有指針或其別名在釋放其內(nèi)存對(duì)象后是否再次被使用,作為可能的UAF 漏洞. 然后使用符號(hào)執(zhí)行檢查可能的UAF 漏洞的路徑約束的可滿足性來減少誤報(bào)率.但是由于約束求解的局限性以及使用函數(shù)內(nèi)聯(lián)技術(shù)和函數(shù)摘要技術(shù)進(jìn)行過程間分析帶來的巨大開銷,導(dǎo)致它僅適用于較小的程序. CRed[2]首先對(duì)C程序進(jìn)行基于需求驅(qū)動(dòng)的指針分析獲取可能的UAF 漏洞,然后通過函數(shù)調(diào)用上下文敏感縮減技術(shù)和路徑敏感縮減技術(shù)逐步減少誤報(bào)率. 為了減少分析時(shí)間,CRed 通過設(shè)置函數(shù)調(diào)用上下文的深度來減少需要分析的程序路徑的數(shù)量. 因此CRed會(huì)遺漏一些UAF 漏洞. 此外,由于CRed 對(duì)數(shù)組訪問別名的建模不完善,并且缺乏對(duì)鏈接列表的處理,即使沒有減少函數(shù)調(diào)用上下文深度,它也可能會(huì)遺漏真正的UAF 漏洞.

與上述對(duì)指針進(jìn)行詳細(xì)分析不同,CBMC 是將模型檢查[17]與可滿足性求解相結(jié)合的有界模型檢查工具. CBMC 首先將每個(gè)循環(huán)展開到固定邊界,然后再將程序轉(zhuǎn)換為使用UAF 斷言注釋的程序. 然后,它將所有可能的程序路徑視為約束,并使用SMT 求解器對(duì)其進(jìn)行求解,以確定程序是否包含UAF 約束違規(guī). 盡管精度很高,但由于約束求解的局限性,CBMC 只能擴(kuò)展到小型程序.

Coccinelle 和TscanCode 都是采用給定的模式來分析和驗(yàn)證C 程序中的漏洞. 因此二者具有很高的擴(kuò)展性,但給定模式也降低了漏洞檢測(cè)的精度. 此外,由于指針分析不佳和模式匹配的性質(zhì),前者容易產(chǎn)生大量誤報(bào);后者由于缺乏指針分析,所以在真實(shí)程序中難以檢測(cè)UAF 漏洞. Clang 靜態(tài)分析器通過在軟件編譯過程中執(zhí)行控制流分析、路徑敏感分析和過程間分析進(jìn)行漏洞檢測(cè). 為了平衡有效性和可擴(kuò)展性,它通過函數(shù)內(nèi)聯(lián)技術(shù)執(zhí)行有限的過程間分析,并且只進(jìn)行簡(jiǎn)單的指針分析和保守的循環(huán)分析. 因此,在減少誤報(bào)率的同時(shí),也會(huì)漏報(bào)一些程序間和程序內(nèi)的UAF 漏洞.

除以上主要針對(duì)源代碼的UAF 檢測(cè)技術(shù),對(duì)于應(yīng)用場(chǎng)景更多的二進(jìn)制程序,也有一些UAF 檢測(cè)技術(shù). 由于二進(jìn)制程序相比源碼缺失更多的信息,所以一般都是在二進(jìn)制程序的基礎(chǔ)上提取出抽象信息用于指導(dǎo)檢測(cè). 如GUEB[18]先構(gòu)建出抽象內(nèi)存模型作為其中間表示;然后通過值分析和指針別名分析來跟蹤堆的操作和指針傳播;最后為檢測(cè)到的每個(gè)UAF 漏洞提取1 個(gè)子圖,以描述指針的創(chuàng)建、釋放和使用位置. GUEB 可以在沒有源代碼的情況下檢測(cè)UAF 漏洞,并且比嚴(yán)重依賴于測(cè)試用例的動(dòng)態(tài)檢測(cè)器提供更好的覆蓋率. 然而,由于反匯編技術(shù)的誤差和不完善的指針分析,GUEB 的檢測(cè)結(jié)果既不精確也不可靠. 此外,GUEB 在分析真正的大型程序時(shí)存在一定難度,因?yàn)樗褂煤瘮?shù)內(nèi)聯(lián)技術(shù)進(jìn)行過程間分析,導(dǎo)致多次調(diào)用的函數(shù)被重復(fù)處理[19]. 而UAFDetector[20]提出釋放后使用特征模型為檢測(cè)提供指導(dǎo),再將目標(biāo)程序的二進(jìn)制代碼轉(zhuǎn)換為中間表示并構(gòu)建控制流圖,最后執(zhí)行指針跟蹤以識(shí)別UAF 漏洞. 其方案與前者類似,它使用函數(shù)摘要技術(shù)而不是函數(shù)內(nèi)聯(lián)技術(shù)進(jìn)行過程間分析,實(shí)現(xiàn)了更好的可擴(kuò)展性,并減少了不必要的分析開銷.

由于部分靜態(tài)分析技術(shù)的局限性導(dǎo)致靜態(tài)檢測(cè)存在一定的誤報(bào)率,所以部分研究采用動(dòng)態(tài)檢測(cè). Mudflap[21]在C/C++程序編譯時(shí)添加內(nèi)存檢查. Mudflap 在指針的使用位置處靜態(tài)插入合法性驗(yàn)證斷言. 斷言取決于指針是否訪問有效內(nèi)存,這由Mudflap 維護(hù)的有效內(nèi)存對(duì)象列表決定. 實(shí)際環(huán)境中,對(duì)于復(fù)雜的C/C++ 程序,Mudflap 會(huì)出現(xiàn)較高的誤報(bào)率. UAFL[3]利用SVF[22]對(duì)中間語言進(jìn)行過程間分析,依次尋找觸發(fā)UAF 漏洞的特定序列的3 個(gè)結(jié)點(diǎn):內(nèi)存申請(qǐng)、內(nèi)存釋放和內(nèi)存使用,給出可能存在的UAF 漏洞,然后利用模糊測(cè)試技術(shù)驗(yàn)證UAF 漏洞是否存在. DoubleTake[23]對(duì)共享庫函數(shù)進(jìn)行修改,使得每個(gè)被釋放的內(nèi)存對(duì)象的前128 字節(jié)都被填充指定數(shù)據(jù),下一次申請(qǐng)內(nèi)存對(duì)象時(shí)通過檢查其中的值是否為指定數(shù)據(jù)來判斷是否存在UAF 漏洞,并立即觸發(fā)重新執(zhí)行以識(shí)別此錯(cuò)誤的原因. 由于它的判斷依據(jù)是內(nèi)存對(duì)象中的指定數(shù)據(jù)是否被修改,所以對(duì)于通過UAF 漏洞泄露信息的漏洞無法檢測(cè).

Valgrind 使用反匯編技術(shù)首先將機(jī)器代碼翻譯成中間表達(dá)(Intermediate Representation,IR)形式,再在關(guān)鍵位置插入額外的IR 以啟用內(nèi)存檢查,最后將這些IR 翻譯回機(jī)器代碼. 最后在運(yùn)行時(shí),插入的代碼就可以實(shí)時(shí)檢測(cè)軟件是否有UAF 漏洞觸發(fā). Dr. Memory 與Valgrind 的不同之處在于Dr. Memory 是基于DynamoRIO[24]執(zhí)行內(nèi)存檢查優(yōu)化. DynamoRIO 復(fù)制每條指令并且對(duì)每條指令都添加相應(yīng)的注釋,以解釋這條指令的效果. 二者相同之處在于都將影子內(nèi)存拆分成類似的多級(jí)結(jié)構(gòu),即多級(jí)影子映射,以減少內(nèi)存開銷并加速查詢. Valgrind 和Dr. Memory 的缺點(diǎn)就是由于增加了檢測(cè)代碼,導(dǎo)致新的程序?qū)ο到y(tǒng)開銷增大很多.

簡(jiǎn)而言之,動(dòng)態(tài)分析一般先將程序轉(zhuǎn)換成IR或者直接在二進(jìn)制文件上進(jìn)行插樁,然后在程序運(yùn)行時(shí)檢測(cè)是否存在UAF 漏洞. 這種方式雖然具有較低的誤報(bào)率,但也存在低覆蓋率和高性能開銷問題.

本文的主要貢獻(xiàn)如下:(1) 基于導(dǎo)致UAF 漏洞的2 個(gè)條件,本文提出了輕量級(jí)的UAF 漏洞靜態(tài)檢測(cè)方案;(2) 采用調(diào)用圖的逆拓?fù)湫蛄械姆绞奖闅v并處理程序,將過程間分析簡(jiǎn)化為過程內(nèi)分析,減小了系統(tǒng)開銷;(3) 結(jié)合基于指令間關(guān)系的別名分析和Andersen 別名分析算法的別名分析快速且準(zhǔn)確地得到所有懸空指針;(4) 將設(shè)計(jì)的檢測(cè)方案實(shí)現(xiàn)并與其他靜態(tài)分析工具進(jìn)行比較,證明了該方案的有效性,且在UAF 漏洞檢測(cè)方面優(yōu)于它們.

2 LLVM

LLVM(Low Level Virtual Machine)是用途廣泛的編譯器基礎(chǔ)架構(gòu). 它將編譯器的功能進(jìn)行模塊化劃分與封裝,使得用戶可以根據(jù)自身需求定制編譯器. 如圖2 所示,其主要分為3 部分:編譯器前端、優(yōu)化器、編譯器后端. 其前端對(duì)程序源代碼依次進(jìn)行詞法分析,語法分析和語義分析,最后生成IR. 優(yōu)化器使用Pass 對(duì)IR 進(jìn)行優(yōu)化,既可以優(yōu)化代碼也可以進(jìn)行靜態(tài)分析. 編譯器后端則根據(jù)優(yōu)化后的IR 生成在目標(biāo)機(jī)器上運(yùn)行的機(jī)器碼,即目標(biāo)程序.

IR 是屬于低級(jí)語言,有如下特點(diǎn):采用靜態(tài)單一賦值(Static Single Assignment,SSA),即每個(gè)值只有1 個(gè)定義它的賦值操作;代碼被組織為三地址指令(Three-Address Instructions);寄存器的數(shù)量不受限制.

模塊是LLVM IR 的頂層數(shù)據(jù)結(jié)構(gòu),包含目標(biāo)機(jī)器信息、函數(shù)的聲明定義、符號(hào)表和全局變量.函數(shù)包含函數(shù)的返回類型、函數(shù)名、參數(shù)類型和函數(shù)體. 其中,函數(shù)體由一系列基本塊構(gòu)成,基本塊由一系列各種指令構(gòu)成,如訪問內(nèi)存指令、操作內(nèi)存指令、類型轉(zhuǎn)換指令、算術(shù)運(yùn)算指令及跳轉(zhuǎn)指令等,特殊的是最后1 條指令一般都是終止指令. 常見指令及其作用如表1 所示. 其中,getelementptr指令常用于獲取聚合數(shù)據(jù)結(jié)構(gòu)的子元素的地址,如結(jié)構(gòu)體成員變量的地址.

優(yōu)化器的功能由1 個(gè)或者多個(gè)Pass 實(shí)現(xiàn),以LLVM IR 作為輸入輸出. 多個(gè)Pass 可以協(xié)同工作,并且Pass 支持用戶自定義. 為了實(shí)現(xiàn)不同級(jí)別的優(yōu)化和分析,需要通過繼承Pass 類的子類MoudlePass、FunctionPass 和BasicBlockPass 實(shí)現(xiàn). 它們分別代表模塊級(jí)、函數(shù)級(jí)和基本塊級(jí). 示例如圖3,該自定義Pass 使用LLVM 的CallGraph?WrapperPass 打印出程序中所有函數(shù)的函數(shù)名.

LLVM 中的Value 類和User 類是2 個(gè)非常重要的基類,其中繼承于Value 的子類表示它的結(jié)果可以在其他地方使用,而繼承于User 的子類表示它會(huì)使用1 個(gè)或多個(gè)Value 對(duì)象. LLVM 在SSA 的基礎(chǔ)上根據(jù)Value 與User 之間的關(guān)系得出use-def鏈和def-use 鏈. use-def 鏈?zhǔn)侵副荒硞€(gè)User 使用的Value 列表,def-use 鏈?zhǔn)鞘褂媚硞€(gè)Value 的User 列表. 它們極大地提升了LLVM 的數(shù)據(jù)流分析能力.

3 UAF 漏洞檢測(cè)方案

本節(jié)首先概述整個(gè)UAF 漏洞檢測(cè)流程,然后再詳細(xì)描述UAF 漏洞檢測(cè)方案的具體細(xì)節(jié).

3. 1 整體設(shè)計(jì)

UAF 漏洞檢測(cè)流程圖如圖4 所示. 通過Clang編譯器編譯源代碼可獲得LLVM IR,但微軟提供的開源工具llvm-mctoll[25]實(shí)現(xiàn)將常見架構(gòu)的二進(jìn)制程序轉(zhuǎn)換成LLVM IR,可擴(kuò)大本方案的適用范圍.

UAF漏洞靜態(tài)分析流程如下:( 1) 通過Clang編譯器或者 llvm-mctoll工具獲取 LLVM IR;( 2)進(jìn)行調(diào)用圖分析,獲得程序的調(diào)用圖的逆拓?fù)湫蛄校唬?3) 進(jìn)行控制流分析和數(shù)據(jù)流分析,獲得被釋放內(nèi)存對(duì)象的指針;( 4) 使用別名分析,收集所有懸空指針;( 5) 進(jìn)行控制流分析,過濾不存在UAF漏洞的懸空指針;( 6) 利用函數(shù)的支配樹細(xì)化UAF漏洞操作序列;( 7) 以操作序列的形式報(bào)告UAF 漏洞.

通過數(shù)據(jù)流分析追蹤懸空指針的傳播,UAF漏洞檢測(cè)報(bào)告的查全率取決于數(shù)據(jù)流分析的精確性,是否可以查出所有懸空指針及其別名的傳播.UAF 漏洞誤報(bào)是將不存在UAF 漏洞的程序視為存在UAF 漏洞的程序. 由于數(shù)據(jù)流分析可以精確地獲得懸空指針及其使用指令,所以根據(jù)產(chǎn)生UAF 漏洞的2 個(gè)條件可知,誤報(bào)主要是在分析懸空指針能否被使用的階段產(chǎn)生的,即可達(dá)性分析.所以UAF 漏洞檢測(cè)報(bào)告的查準(zhǔn)率受到控制流分析的影響.

3. 2 基于靜態(tài)分析的UAF 漏洞檢測(cè)方案

UAF 漏洞檢測(cè)分為2 部分:檢測(cè)程序中可能存在的懸空指針;懸空指針是否被使用.

根據(jù)懸空指針的定義可知,若要檢測(cè)程序中存在的懸空指針,必須先獲得懸空指針可能產(chǎn)生的位置,即內(nèi)存釋放函數(shù)的調(diào)用位置,還需要確保在內(nèi)存對(duì)象被釋放后,相關(guān)指針沒有再次被定義.本文中,內(nèi)存釋放函數(shù)分為庫函數(shù)和對(duì)庫函數(shù)封裝的用戶自定義函數(shù)2 類,其參數(shù)列表中都一定存在被釋放內(nèi)存對(duì)象的指針. 具體檢測(cè)方法如算法1所示.

算法1 首先讀取配置文件獲取被測(cè)試程序中可能存在的常見內(nèi)存釋放函數(shù)的函數(shù)名,如free等,和代表內(nèi)存對(duì)象的指針參數(shù)序號(hào). 同時(shí)使用LLVM 提供的Pass 構(gòu)建被測(cè)試程序的調(diào)用圖,再通過深度優(yōu)先遍歷調(diào)用圖可以得到所有用戶自定義函數(shù)的逆拓?fù)渑判? 根據(jù)逆拓?fù)湫蛄虚_始依次分析每個(gè)用戶自定義函數(shù)時(shí),如果發(fā)現(xiàn)用戶自定義函數(shù)中存在內(nèi)存釋放函數(shù)調(diào)用,需要對(duì)該用戶自定義函數(shù)進(jìn)行深入分析.

分析過程從對(duì)內(nèi)存釋放函數(shù)調(diào)用指令的處理開始,首先根據(jù)參數(shù)序號(hào)取出被釋放內(nèi)存對(duì)象的指針,然后通過別名分析獲取其別名,得到可能的懸空指針集合. 該別名分析算法在worklist 算法的基礎(chǔ)上結(jié)合了基于指令關(guān)系的別名分析和Andersen算法[26].

其中基于指令關(guān)系的別名分析主要側(cè)重于分析指針變量之間通過賦值運(yùn)算符進(jìn)行的賦值操作. 其中,將IR 中的store 指令視為變量的定義操作. load 指令視為使用操作. 基于指令關(guān)系的別名分析首先根據(jù)內(nèi)存對(duì)象指針變量確定對(duì)應(yīng)的寄存器,然后收集與該寄存器相關(guān)的load 和store 指令并對(duì)其進(jìn)行處理. 如圖5 所示,對(duì)于函數(shù)func1,根據(jù)內(nèi)存釋放函數(shù)free 得到被釋放內(nèi)存對(duì)象指針a,遍歷func1 的指令發(fā)現(xiàn)在釋放內(nèi)存之前指針a 賦值給指針b,在IR 中主要表現(xiàn)形式為先使用load 指令獲取指針a,然后使用store 指令將其存儲(chǔ)到指針b中,所以追蹤變量a 的賦值操作時(shí)需要獲取load 和store 指令. 函數(shù)func2 同理,不過由于已知的內(nèi)存對(duì)象指針是被賦值,所以只需要獲取相關(guān)的store指令即可.

除了上述直接利用賦值操作符進(jìn)行指針復(fù)制外,還有利用函數(shù)進(jìn)行指針復(fù)制的特殊情況. 上述直接利用數(shù)據(jù)流分析進(jìn)行獲取別名的方式對(duì)此并不適用,因此考慮使用Andersen 算法. 該算法只是收集與利用上述數(shù)據(jù)流分析得到的候選懸空指針集合相關(guān)的call 指令涉及的指針,然后利用Andersen算法計(jì)算其與已知的被釋放內(nèi)存對(duì)象指針是否存在別名關(guān)系. 如果存在,則將其視為別名,反之,則舍棄.

通過上述方法獲得程序中所有可能的懸空指針之后,查找其使用位置前,還需要進(jìn)行驗(yàn)證,確保其屬于懸空指針,即沒有再次被定義. 本文根據(jù)可能的懸空指針是否是全局變量選擇執(zhí)行不同的檢測(cè)方案.

考慮循環(huán)結(jié)構(gòu)的影響,對(duì)于局部變量類型的候選懸空指針,本文在GetNotRedefined 函數(shù)中通過前向分析來確定在某個(gè)內(nèi)存釋放函數(shù)之后,哪些指針仍然保持活性. 具體來說,算法首先為函數(shù)中的每個(gè)指令設(shè)置一個(gè)in 和out 映射,分別表示函數(shù)中的指令執(zhí)行前后是否可以到達(dá)相關(guān)的store 指令,然后通過遍歷每個(gè)基本塊并按照順序遍歷基本塊中的指令(主要是store,call 和終止指令這3類)來對(duì)所有指令進(jìn)行前向分析. 對(duì)于每個(gè)指令,代碼檢查其入口和出口,并在此基礎(chǔ)上更新in 和out 映射. 具體而言,當(dāng)檢測(cè)到指令I(lǐng) 的in 與out 映射不同時(shí),算法檢查該指令是否為定義指針變量AI 的store 指令. 如果不是,代碼將修改對(duì)應(yīng)的out映射,以將所有能夠到達(dá)I 的指令設(shè)置為活性. 接下來,算法按照基本塊終止指令的類型(分支、轉(zhuǎn)換、間接分支、返回或不可達(dá))更新in 和out 映射.最后,算法根據(jù)in 和out 映射中的結(jié)果確定哪些store 指令在某個(gè)內(nèi)存釋放函數(shù)之后定義了指針.

為了減少過程間分析帶來的性能開銷,本文通過從內(nèi)存釋放函數(shù)調(diào)用處開始順序遍歷指令的方式處理全局指針變量,嘗試得到與其相關(guān)的store 指令. 如果存在該store 指令,則在檢測(cè)懸空指針的使用時(shí),還需要對(duì)懸空指針再定義與懸空指針使用之間進(jìn)行可達(dá)性分析. 如果store 指令在load 指令之前執(zhí)行,則說明該指針在利用之前已經(jīng)被再次定義,故放棄對(duì)該指針的后續(xù)處理.

通過上述步驟,最終可以得到程序中的所有的懸空指針及其產(chǎn)生的位置,其中局部懸空指針以alloca 指令形式存儲(chǔ). 特殊的是,由于僅使用 alloca指令表示局部聚合數(shù)據(jù)的成員可能導(dǎo)致很高的誤報(bào)率,所以為了精準(zhǔn)定位聚合數(shù)據(jù)中的懸空指針,還需要記錄對(duì)應(yīng)的getelementptr 指令的偏移下標(biāo).

獲取程序中所有懸空指針后,通過LLVM 的def-use 鏈逐個(gè)獲取每個(gè)懸空指針的使用者. 如果使用者是訪問內(nèi)存指令或操作內(nèi)存指令,且內(nèi)存釋放函數(shù)調(diào)用指令與該指令存在通路,則視為存在UAF 漏洞. 需要注意的是,對(duì)于局部聚合數(shù)據(jù)中的懸空指針,通過alloca 指令的def-use 鏈獲取它的使用者之后,還需要確定每個(gè)使用者是否是getelementptr指令,如果是該類型指令,還要檢查getelementptr指令的偏移下標(biāo)是否與收集懸空指針階段保存的偏移下標(biāo)一致. 只有偏移下標(biāo)一致,才表明是聚合數(shù)據(jù)中的懸空指針被使用.

通過上述方法可以檢測(cè)出程序中是否存在UAF 漏洞,并以lt;內(nèi)存釋放位置,內(nèi)存使用位置gt;映射的形式表示UAF 漏洞. 為了保證內(nèi)存釋放函數(shù)調(diào)用指令不會(huì)被忽略,還需要實(shí)時(shí)更新內(nèi)存釋放函數(shù)信息. 更新機(jī)制首先會(huì)檢查當(dāng)前集合中的懸空指針是否會(huì)導(dǎo)致UAF 漏洞,即是否有對(duì)應(yīng)的lt; 內(nèi)存釋放位置,內(nèi)存使用位置gt; 映射. 如果存在,則將對(duì)應(yīng)的lt;內(nèi)存釋放位置,內(nèi)存使用位置gt;映射存放到集合中;如果不存在,則對(duì)該懸空指針進(jìn)行數(shù)據(jù)流分析,檢查其是否屬于當(dāng)前函數(shù)的參數(shù),或存在別名關(guān)系. 如果該懸空指針屬于當(dāng)前函數(shù)的參數(shù)或存在別名關(guān)系,則將當(dāng)前函數(shù)視為用戶自定義的內(nèi)存釋放函數(shù),并更新內(nèi)存釋放函數(shù)信息.

在獲取程序中所有的UAF 漏洞之后,為了后續(xù)更好地分析UAF 漏洞,需要根據(jù)lt;內(nèi)存釋放位置,內(nèi)存使用位置gt;映射獲取對(duì)應(yīng)的UAF 操作序列. 具體來說,首先對(duì)集合中的每個(gè)映射進(jìn)行分析:獲取內(nèi)存釋放位置所在函數(shù)的支配樹,然后獲取內(nèi)存釋放位置和內(nèi)存使用位置2 個(gè)結(jié)點(diǎn)的公共祖先結(jié)點(diǎn),然后從下向上遍歷支配樹,得到從內(nèi)存釋放位置到內(nèi)存使用位置必經(jīng)的所有基本塊,即UAF 漏洞操作序列. 最后,以操作序列的形式報(bào)告UAF 漏洞.

4 實(shí)驗(yàn)結(jié)果與分析

本文實(shí)驗(yàn)均在Ubuntu 20. 04 64 bit 上進(jìn)行,處理器為AMD 銳龍5 4600 G,內(nèi)存分配4 GB. 本文代碼基于C++編寫.

4. 1 實(shí)驗(yàn)對(duì)象

為了評(píng)估該方案的有效性,本文使用了軟件保障參考數(shù)據(jù)庫公開的測(cè)試樣本集Juliet C/C++ 1. 3[27]對(duì)檢測(cè)方案進(jìn)行驗(yàn)證. 該測(cè)試用例集由一組具有已知漏洞的合成C 程序,且涵蓋了軟件中常見的118 種漏洞. 這些程序可以用于測(cè)試靜態(tài)分析器在各種系統(tǒng)環(huán)境下的有效性. 本文僅利用與UAF 漏洞(CWE-416)相關(guān)的C 語言測(cè)試用例子集,它的測(cè)試用例提供了數(shù)據(jù)結(jié)構(gòu)的不同變體以及不同的控制流和數(shù)據(jù)流模式中的漏洞示例. 每個(gè)測(cè)試文件都包含1 個(gè)有漏洞的函數(shù)和相應(yīng)的無漏洞函數(shù). 將每個(gè)測(cè)試用例都分成對(duì)應(yīng)的有漏洞測(cè)試用例和無漏洞測(cè)試用例,構(gòu)成了本文使用的包含276 個(gè)測(cè)試用例的集合. 其中包含138個(gè)存在UAF 漏洞的測(cè)試樣例和138 個(gè)不存在UAF 漏洞的測(cè)試樣例. 為了說明該方案在真實(shí)環(huán)境中的有效性,本文還利用了數(shù)個(gè)公開漏洞進(jìn)行驗(yàn)證,其基本信息如表2 所示.

4. 2 有效性驗(yàn)證

4. 2. 1 開源測(cè)試用例集驗(yàn)證

將本文提出的UAF 漏洞檢測(cè)方案與CBMC、TscanCode、Coccinelle和Clang 靜態(tài)分析器這4 個(gè)目前主流的靜態(tài)分析器進(jìn)行比較. 實(shí)驗(yàn)結(jié)果如表3 所示.

本文方案相比于其他4 個(gè)主流的靜態(tài)分析器效果更好. 其中,138 個(gè)存在UAF 漏洞的樣本都成功地被本文方案檢測(cè)出來,并且沒有錯(cuò)誤地認(rèn)為138 個(gè)正常樣本中存在UAF 漏洞. 其余4 個(gè)主流的靜態(tài)分析器雖然也沒有產(chǎn)生誤報(bào),但是檢測(cè)出來的UAF 漏洞數(shù)量都沒有達(dá)到全部漏洞的50%,甚至更少. 圖6 直觀地展示了本文方案與其他靜態(tài)分析器的有效性分析.

通過開源測(cè)試用例集的驗(yàn)證,說明本文方案對(duì)于常見的UAF 漏洞形式都能夠精確且迅速的檢測(cè)出來.

4. 2. 2 公開漏洞驗(yàn)證

公開漏洞驗(yàn)證結(jié)果如表4所示. 對(duì)于這5 個(gè)真實(shí)應(yīng)用程序,本文提出的方案表現(xiàn)良好,都成功地將其中的UAF 漏洞檢測(cè)出來. 對(duì)于結(jié)構(gòu)較簡(jiǎn)單的bzip2recover 程序甚至做到了零誤報(bào)率. 但是對(duì)于復(fù)雜的程序,為了提高檢測(cè)效率,本方案采用了較簡(jiǎn)單且保守的控制流分析,因此會(huì)導(dǎo)致檢測(cè)結(jié)果出現(xiàn)一定的誤報(bào)率. 由于靜態(tài)分析技術(shù)的局限性仍然存在一定的誤報(bào)率.Clang 靜態(tài)分析器只是成功地檢測(cè)出了gifsicle 程序中的UAF 漏洞,同時(shí)伴隨著誤報(bào). 這主要是由于其對(duì)于結(jié)構(gòu)體內(nèi)部指針的分析具有一定缺陷.由于TscanCode 和Coccinelle 通過模式匹配的方式進(jìn)行檢測(cè),所以對(duì)于結(jié)構(gòu)復(fù)雜多變的真實(shí)程序,它們表現(xiàn)得也不盡人意,只是檢測(cè)出readelf 程序中的UAF 漏洞,并且后者伴隨著大量誤報(bào).

4. 3 性能分析

為了比較5 個(gè)檢測(cè)工具之間的性能優(yōu)劣,本文統(tǒng)計(jì)了5 種檢測(cè)工具對(duì)6 個(gè)實(shí)驗(yàn)對(duì)象進(jìn)行檢測(cè)時(shí)的消耗時(shí)長,具體數(shù)據(jù)如表5 所示. 根據(jù)圖7 的直觀展示可知,本文提出的方案檢測(cè)耗時(shí)并不比主流的靜態(tài)分析器耗時(shí)更多,甚至大多數(shù)情況下能夠更快地給出檢測(cè)結(jié)果. 對(duì)于結(jié)構(gòu)越簡(jiǎn)單的程序,本文提出的方案表現(xiàn)得越好. 此外,由于CBMC利用約束求解器進(jìn)行漏洞檢測(cè),導(dǎo)致其所消耗的時(shí)間通常是最多的,甚至是本方案所需時(shí)間的數(shù)十倍以上.

5 結(jié)論

因?yàn)橛蓱铱罩羔樢鸬腢AF 漏洞對(duì)計(jì)算機(jī)系統(tǒng)的危害性越來越嚴(yán)重,所以本文提出了輕量級(jí)的UAF 漏洞檢測(cè)方案. 該方案使用調(diào)用圖的逆拓?fù)湫蛄斜闅v函數(shù),不斷更新內(nèi)存釋放函數(shù)信息,從而避免過程間分析帶來的系統(tǒng)性能消耗. 此外,該方案還通過結(jié)合基于指令關(guān)系的別名分析和Andersen別名分析算法,使得別名分析在精確性和性能之間取得平衡. 最后該方案還利用基本塊之間的支配關(guān)系豐富每個(gè)UAF 漏洞操作序列,使得UAF 漏洞報(bào)告更詳細(xì),為后續(xù)研究帶來便利. 通過LLVM Pass 實(shí)現(xiàn)該方案后,本文從開源測(cè)試用例和真實(shí)程序2 個(gè)角度驗(yàn)證了該方案的可行性和高效性.

實(shí)驗(yàn)結(jié)果表明,方案能夠有效地發(fā)現(xiàn)UAF 漏洞. 對(duì)于測(cè)試樣本集Juliet 中的276 個(gè)測(cè)試用例,本文提出的工具與其他4 種主流工具相比實(shí)現(xiàn)了零漏報(bào)率和零誤報(bào)率,初步證明了該方案的可行性.此外,本文還用數(shù)個(gè)公開漏洞進(jìn)行測(cè)試,都成功地檢測(cè)出其中的UAF 漏洞. 通過比較不同工具檢測(cè)不同程序的消耗時(shí)長可以說明,該方案對(duì)于小型程序中的UAF 漏洞檢測(cè)具有較大優(yōu)勢(shì). 并且對(duì)于結(jié)構(gòu)復(fù)雜的程序,也能展示出不錯(cuò)的效果. 不過,由于可達(dá)性分析和數(shù)據(jù)流分析的難度隨著程序規(guī)模的不斷變大而增加,所以對(duì)于較復(fù)雜的程序,依舊存在一定的誤報(bào)率.

目前,該方案也存在一些不足之處. 對(duì)于異步程序,由于其控制流圖和調(diào)用圖需要考慮回調(diào)函數(shù)和事件循環(huán),且有可能導(dǎo)致多線程執(zhí)行,因此通過靜態(tài)分析檢測(cè)其中的UAF 漏洞可能存在較大的誤報(bào)率和漏報(bào)率. 此外,本方案雖然可以通過采用llvm-mctoll 工具將二進(jìn)制程序轉(zhuǎn)化為LLVM IR,擴(kuò)大了本方案的適用范圍,但是該工具并不能支持所有架構(gòu)的二進(jìn)制程序,且轉(zhuǎn)換后可能導(dǎo)致程序結(jié)構(gòu)更加復(fù)雜.

參考文獻(xiàn):

[1] Booth H, Rike D, Witte G A. The national vulnerabilitydatabase( NVD): Overview[ EB/OL].[2023-02-05]. https://csrc. nist. gov/pubs/itlb/2013/12/thenational-vulnerability-database-nvd-overview/fi-nal.

[2] Yan H, Sui Y, Chen S, et al. Spatio-temporal contextreduction: A pointer-analysis-based static approachfor detecting use-after-free vulnerabilities[ C]//Proceedings of the 2018 IEEE/ACM 40th InternationalConference on Software Engineering( ICSE).New York: IEEE, 2018: 327.

[3] Wang H, Xie X, Li Y, et al. Typestate-guidedfuzzer for discovering use-after-free vulnerabilities[ C]//Proceedings of the 2020 IEEE/ACM 42nd InternationalConference on Software Engineering( ICSE).New York: IEEE, 2020: 999.

[4] Sotirov A. Heap feng shui in JavaScript[ R]. Amsterdam:Black Hat Europe, 2007: 11.

[5] Van Der Kouwe E, Nigade V, Giuffrida C. Dangsan:Scalable use-after-free detection [C]//Proceedingsof the Twelfth European Conference on Com ?puter Systems. New York: Association for Comput?ing Machinery, 2017: 405.

[6] Lattner C, Adve V. LLVM: A compilation frameworkfor lifelong program analysis amp; transformation[C]//Proceedings of the International Symposiumon Code Generation and Optimization. SanJose: IEEE, 2004: 75.

[7] Shen Z, Dolan-Gavitt B. Heapexpo: Pinpointing promotedpointers to prevent use-after-free vulnerabilities[ C]//Proceedings of the Annual Computer SecurityApplications Conference. New York: Associationfor Computing Machinery, 2020: 454.

[8] Lee B, Song C, Jang Y, et al. Preventing use-afterfreewith dangling pointers 1ification [C]// Proceedingsof the 2015 International Conference onCloud and Autonomic Computing. San Diego: TheInternet Society, 2015.

[9] Younan Y. FreeSentry: protecting against use-afterfreevulnerabilities due to dangling Pointers [C]//Proceedings of the 2015 International Conference onCloud and Autonomic Computing. San Diego: TheInternet Society, 2015.

[10] Kroening D, Tautschnig M. CBMC-C boundedmodel checker: (Competition contribution) [C]//Proceedings of the 20th International ConferenceTools and Algorithms for the Construction andAnalysis of Systems. Berlin: Springer Berlin Heidelberg,2014: 389.

[11] Olesen M C, Hansen R R, Lawall J L, et al. Coccinelle:Tool support for automated CERT C securecoding standard certification [J]. ScI Comput Program,2014, 91: 141.

[12] Clang. Clang static analyzer [DB/OL]. [2023-03-23]. http://clang-analyzer. llvm. org/.

[13] Tencent. TscanCode [DB/OL]. [2023-03-23].https://github. com/Tencent/TscanCode/.

[14] Nethercote N, Seward J. Valgrind: A framework forheavyweight dynamic binary instrumentation [J].ACM Sigplan Notices, 2007, 42: 89.

[15] Bruening D, Zhao Q. Practical memory checkingwith Dr. Memory [C]//International Symposium onCode Generation and Optimization (CGO 2011).New York: IEEE, 2011: 213.

[16] Ye J, Zhang C, Han X. POSTER: UAFChecker:Scalable static detection of use-after-free vulnerabilities[C]//Proceedings of the 2014 ACM SIGSACConference on Computer and Communications Security.New York: Association for Computing Machinery,2014: 1529.

[17] Biere A, Cimatti A, Clarke E M, et al. Boundedmodel checking [J]. Handbook of Satisfiability,2009, 185: 457.

[18] Feist J, Mounier L, Potet M L. Statically detectinguse after free on binary code [J]. Journal of ComputerVirology and Hacking Techniques, 2014,10: 211.

[19] Gui B, Song W, Xiong H, et al. Automated useafter-free detection and exploit mitigation: how farhave we gone [J]. IEEE T Software Eng,2021, 48:4569.

[20] Zhu K, Lu Y, Huang H. Scalable static detection ofuse-after-free vulnerabilities in binary code [J]. IEEEAccess, 2020, 8: 78713.

[21] Eigler F C. Mudflap: Pointer use checking for C/C++ [C]//Proceedings of the 2003 GCC Summit.[S. l. :s. n.],2003: 57.

[22] Sui Y, Xue J. SVF: Interprocedural static valueflowanalysis in LLVM [C]//Proceedings of the25th international conference on compiler construction.New York: Association for Computing Machinery,2016: 265.

[23] Liu T, Curtsinger C, Berger E D. Doubletake: Fastand precise error detection via evidence-based dynamicanalysis [C]// Proceedings of the 38th InternationalConference on Software Engineering. NewYork: Association for Computing Machinery,2016: 911.

[24] Bruening D. Efficient, transparent, and comprehensiveruntime code manipulation [D]. Cambridge,Boston, MA: Massachusetts Institute of Technology,2004.

[25] Yadavalli S B, Smith A. Raising binaries to LLVMIR with MCTOLL( WIP paper)[ C]// Proceedingsof the 20th ACM SIGPLAN/SIGBED InternationalConference on Languages. New York: Associationfor Computing Machinery, 2019: 213.

[26] Andersen L. Program analysis and specialization forthe C programming language[ D]. Copenhagen: Universityof Copenhagen, 1994.

[27] NIST. Juliet test suite 1. 3. test suites [DB/OL].(2017-10-01)[2023-03-23]. https://samate. nist.gov/SRD/testsuite. php/.

(責(zé)任編輯: 伍少梅)

基金項(xiàng)目: 國家重點(diǎn)研發(fā)計(jì)劃項(xiàng)目(2021YGB3101800)

广灵县| 永康市| 增城市| 双峰县| 鹿邑县| 凌海市| 石首市| 北辰区| 凤山县| 乾安县| 积石山| 广西| 神木县| 达孜县| 凯里市| 河津市| 灌南县| 镇平县| 陆川县| 弋阳县| 淮北市| 清原| 鹤庆县| 托克逊县| 迁安市| 岚皋县| 沈丘县| 屏边| 彝良县| 南溪县| 沙河市| 梁平县| 安图县| 师宗县| 内乡县| 南川市| 区。| 南宫市| 大同市| 晋城| 平罗县|