作者:螞蟻安全實驗室
原文鏈接:https://mp.weixin.qq.com/s/CTCGt4GwlIB63lMkAucunA

近日,螞蟻集團與南洋理工大學、中國科技大學聯合論文《APICRAFT: Fuzz Driver Generation for Closed-source SDK Libraries》入選網絡安全領域四大頂會之一USENIX Security 2021

在黑盒的自動化漏洞挖掘過程中,閉源SDK庫缺失源代碼、API接口未知,而逆向成本高、效果差等問題,常常困擾安全研究者。

基于遺傳算法,研究團隊的APICraft 框架技術能對閉源SDK的API依賴關系進行最大程度的挖掘和還原,很好地解決了閉源SDK庫的fuzz driver自動化生成難題,從而實現在0人工干預下挖掘漏洞。

通過運用這項技術方案,截止2021年2月,螞蟻安全光年實驗室已向Apple提交142個macOS系統庫漏洞,并已收獲54個Apple官方致謝。

螞蟻光年安全實驗室林性偉也因此獲得安全屆的奧斯卡大獎—2021年Pwnie Award “Most Innovative Research”獎提名。

圖片

以下是他的技術分享

01 背景

在fuzzing過程中,安全研究員需要構建好一個應用程序用來接收fuzzer提供的fuzz input,這個應用程序我們稱之為fuzz driver。過往的fuzzing相關研究大多針對于fuzzing引擎本身的優化提升,包括種子變異策略以及調度算法的優化,增加多維度的反饋,以及提升fuzzer速度等,這些研究已經將fuzzing研究變為紅海,極其“內卷”。

而我們關注到,如何自動化地構建一個高質量的fuzz driver其實是一個同樣關鍵的問題。直觀來看,如果一個fuzz driver能夠調用更多SDK提供的API,有更豐富的程序行為,那它在fuzzing過程中必然會有更高的覆蓋率,從而更容易觸發漏洞。因此如何生成高質量的fuzz driver是個值得深究的研究問題。

這篇文章主要解決了如何針對閉源SDK自動化生成高質量的fuzz driver問題。

1.1 實例

圖片

圖 1:基于 CoreText庫的兩個 fuzz driver

圖1是一個構建fuzz driver的例子,以macOS CoreText庫為例,圖1有兩個fuzz drivers,分別是Consumer 1以及Consumer 2,將具體API簡化,以偽代碼形式來表現(下面的序號標識了每個API調用,與圖1相對應):

1.Consumer 1調用ProviderCreateWithData API創建了一個DataProvider對象prov;

2.基于prov對象創建了Font對象font;

3.最后計算出font對象的LeadingSpace的double值。

4.而Consumer 2調用CreateFontDescriptor API創建了FontDescriptor對象desc;

5.再基于desc對象創建Font對象font;

6.最后計算font對象的LeadingSpace值。

圖片

圖 2:不同的fuzz driver組合方式

圖2是簡化出來的API調用序列。(a)是原始的調用序列,(b)是我們將Consumer 1與Consumer 2進行了一個交叉變換,將Consumer 1的序列號1調用與Consumer 2的序列號4調用交換,但我們會發現,這個交叉變換并沒有用。因為1與4的調換,只是改變了從raw data創建font對象的方式,并沒有改變后續API調用的語義,后續的2->5,2->3都是沒有變化的。所以我們其實是想要 (c)這種的組合,將3調用與5調用組合在一起。并且可能由于調用時序的不同會有意想不到的結果。比如先調用3計算LeadingSpace的double值,再調用5計算LeadingSpace可能會導致整數溢出漏洞。

從這個例子來看單純依賴人工進行fuzz driver 構建耗費時間且容易出(error-prone)。需要一個自動化的框架來輔助完成這個fuzz driver構建過程。

02 系統總覽

圖片

圖 3:APICraft系統總覽

我們設計并實現了APICraft系統用于針對閉源SDK fuzz driver自動化生成工作。圖3是整體的系統框架總覽。APICraft整體設計思路可以概括為Collect-Combine。

  1. Collect:APICraft會對使用相關SDK的GUI應用程序進行動態trace,用于收集GUI應用程序的動態行為信息,包括GUI應用程序調用SDK API的data dependency以及control dependency等。

  2. Combine:隨后將這些dependency解析好之后進行多目標優化的遺傳算法(Multi-Objective genetic algorithm)的變異進化。產生合乎我們要求的fuzz driver。

03 框架設計

框架設計章節將詳細介紹APICraft框架的設計與實現細節。

3.1 API Function Dependency信息收集

首先是如何收集(Collect)API function dependency信息。APICraft最終目標是想自動化的完成fuzz driver 構建過程,而人工構建fuzz driver最核心的部分基于SDK提供的API構建API調用序列,API調用序列包含了data dependency以及control dependency。APICraft需要收集data dependency以及control dependency信息,用于作為后續的多目標遺傳算法的變異進化的基因/染色體。

3.1.1 Data Dependency

3.1.1.1 定義

圖片

圖 4:Data Dependency定義

在data dependency中,APICraft定義兩個函數A與B有data dependency的關系在于,函數A的某個輸入參數是函數B的輸出參數/返回值,或者函數B的某個輸入參數是函數A的輸出參數/返回值。如果函數A與B存在data dependency,以圖4的公式來表征,即函數A的輸出參數/返回值會被用作函數B的輸入參數。

APICraft定義了兩類的API Data Dependency:

  1. return value:函數A的返回值(return value)被用做函數B的輸入參數;

  2. output parameter:函數A的輸出參數(output paramater,一般是以指針形式存在)被用做函數B的輸入參數。

如果兩個API函數滿足data dependency關系,那這兩個API函數就有時序調用關系。

3.1.1.2 解析

圖片

圖 5:APICraft實現框架圖

當APICraft收集完程序動態行為信息后,需要將信息解析成相應的data dependency。具體的解析步驟是:

  1. 由圖5所示,在預處理階段,APICraft會通過SDK提供的頭文件解析出每個API的參數與返回值的類型信息;

  2. 而參數與返回值的值是由動態獲取到的,APICraft基于function interposition機制實現了一套輕量級的動態trace框架,基于該trace框架,APICraft能夠獲取到動態運行過程中API函數進入前以及退出之后的參數與返回值信息,具體包括了thread id,nested level,以及會遞歸的將函數的參數值,返回值,輸出參數值dump出來;

  3. APICraft基于thread id來將不同線程的trace信息區分開;

  4. APICraft會篩掉nested level大于1的API。APICraft針對的API函數都是SDK頭文件里面提供的合法調用API。在動態trace過程,如果某個API不是由其他API所調用,即由我們的GUI應用所調用,他的nested level就是1,如果該API是在另外的API所調用的,那他的nested level就是2,以此類推。在fuzz driver生成的應用場景中,我們關注的是API函數如何正確地被GUI應用所調用,而不關注API內部調用的邏輯。APICraft需要演化學習的是GUI應用程序的程序行為邏輯,因此不關注SDK庫內部調用的邏輯;

  5. 區分輸出參數:如果一個參數類型是指針,APICraft會監控該指針指向的內容在進API函數前,以及退出API函數之后是否有變化,如果有的話,則該參數會被判別為輸出參數;

  6. 結合類型(type)信息以及值(value)信息進行data dependency匹配:APICraft認為即使在類型信息一致的情況下,兩個值為0的比對是不匹配的,因為值為0基本無意義。隨后APICraft會將typedef給展開,如果類型不一致,APICraft會看兩個比對對象的類型信息是否能夠轉換,如果(1) 兩個比對對象的基本類型是一致的,只是修飾符不一樣,比如const這種修飾詞;(2)如果是指針類型的話,并且兩者指針大小一致,或者對象之一指針是void類型的。上述情形都是可轉換的,兩個對象可被匹配上。

圖片

圖 6:Data Dependency解析算法

圖6所示算法是APICraft Data Dependency解析算法,輸入T是收集到的API函數的調用序列信息,輸出R是解析完的data dependency的集合。

1.初始化階段,R以及cache都將初始化為空;

2.算法會遍歷每個函數A,在第8?中,算法會將output值不為0的函數加入cache中,cache是個字典類型,key為output的值,value為函數A的 output實例;

3.在第4行中,算法會遍歷函數的每個輸入參數(input parameter),用輸入參數的值(value)當作key從cache中取出相應的函數的output,看看是否有函數的輸入參數與另外函數的output類型與值匹配上的。如果有的話就加到集合R中。

3.1.1.3 Dependency推測

除了通過動態trace收集到的API data dependency關系,有些合理的API data dependency關系并不會被trace到(GUI應用程序沒有相應的 API調用組合)。APICraft還會做dependency推測(inference)這一步。APICraft定義了三個推測規則:

1.R1: Dependency-based transition:如果函數A的output與函數C的輸入參數相匹配,并且函數B的output與函數C的輸入參數相匹配,以及又trace到,函數A的output與函數D的輸入參數相匹配, APICraft會推斷出,函數B的output跟函數D的輸入參數能夠相匹配并產生一組data dependency關系;

圖片

圖 7:R1推測公式

2.R2: Type-based transition:當APICraft觀察到函數A的output的類型信息與函數B的輸入參數類型信息一致,這個時候APICraft會做個推測,因為這個沒有值(value)信息,所以是個推測,推測出函數A的 output是函數B的輸入參數;

圖片

圖 8:R2推測公式

3.R3: Inter-thread data flow dependency:R3與圖6的算法是一致的,只不過在這個規則下,會限定類型是指針,一般跨線程之間會傳遞指針,需要減少誤報。

3.1.2 Control Dependency

APICraft收集到的Control Dependency主要是用來解決error code checking的:

1.API函數的輸出參數(output parameter)或者返回值(return value)是指針類型,將對這個output值 進行非空判斷(null check);

2.API函數的輸出參數(output parameter)或者返回值(return value)是整數類型,并且是個status code的話,將進行動態污點分析來獲取error code checking分支的表達式。(1)獲取這個API函數的調用處(callsite);(2)通過靜態分析找到一些error code checking的系統調用,比如exit,abort 等。這些basic block會被標記為checkpoint。(3)最后從調用處(callsite)開始進行taint analysis,因為正常的GUI應用程序會走正常分支,當走到checkpoint相應分支的時候將表達式取反, 讓污點分析傳播到checkpoint處。拿到對應的表達式。

3.2 Dependency Combination

APICraft將收集并解析完成的data dependency以及control denpendency進行Combination,再通過多目標優化遺傳算法進行變異演化。

3.2.1 問題建模

APICraft將fuzz driver生成問題抽象成一個數學問題,利用多目標優化遺傳算法(Multi-Objective Genetic Algorithm)進行求解。

具體而言,以GUI應用程序(調用相應 SDK提供的 API)的API函數使用方式為初始種群,對這些種群進行變異演化生成fuzz driver,通過判斷生成的fuzz driver的優劣,將優越fuzz driver保留下來繼續變異,最后生成滿足要求的fuzz driver 用于fuzzing。我們認為一個高質量的fuzz driver需要滿足三個目標

1.多樣性(Diversity):多樣性(Diversity)指的是fuzz driver能夠調用足夠多樣的API使fuzz driver程序行為更豐富。即為了讓生成出來的fuzz driver有更多不同的data dependencies,如果data dependencies能夠組成loop,每條loop都會給這個目標加分數。圖9所示的多樣性(Diversity)的公式是生成的fuzz driver的有向多邊圖的邊(即單個data dependency)的數量,加上這個圖的圈復雜度。總體是要表征data dependency圖(或者說fuzz driver的API調用)的多樣性。

圖片

圖 9:Diversity公式

2.有效性(Effectiveness):有效性(Effectiveness)是這三個指標中的唯一一個需要動態反饋信息的指標,其目標是要讓生成的fuzz driver的API調用更合法有效。我們會給basic blocks中有調用其他函數的,以及這個basic block處于loop循環中的更多分數,因為我們覺得相對于核心代碼而言error handling code在一個API函數中會執行更少的basic blocks,而核心代碼會有更多的loop信息或者其 他函數調用。該指標是個動態的feedback,是需要將fuzz driver序列化成代碼編譯運行后得來的,我們對每個basic block評分(如圖10所示):(1)調用其余函數以及處于loop循環中,評分3分;(2)調用其余函數或者處于loop循環中,2分;(3)兩者均無則1分。

圖片

圖 10:Effectiveness公式

3.緊湊性(Compactness):core dependency指的是從接收input file的API函數為起點,以此為根結點的展開的data dependency圖。non-core dependency就是與這顆樹無關的data dependency。F是core function(處于 core dependency中的函數)集合,f是集合里面的每個函數,If是每個函數的參數集合。k是每個input參數的無關函數數量,5是個經驗值(即如果無關函數數量超過5,則該緊湊性(Compactness)指標得分為0)。

緊湊性(Compactness)指標目的是為了讓fuzz driver去除冗余API調用,冗余API調用就是跟以接收input file API為起點的data dependency 圖無關的API調用,即存在于non-core dependency圖中的API調用。所以在core dependency的data dependency分數會高,non-core dependency中的data dependency分數會低。圖11是Compactness的具體公式。

圖片

圖 11:Compactness公式

3.2.2 多目標優化遺傳算法(Multi-Objective Genetic Algorithm)

APICraft采用了NSGA-II算法來對Diversity、Effectiveness、Compactness這三個目標進行多目標優化的遺傳算法演進。

圖12是整體的APICraft的多目標優化遺傳算法,輸入data dependency集合,輸出是一系列的fuzz driver集合:

  1. 25-31行即傳統的遺傳算法,先生成初始的種子集,選取初始種子集,然后開始變異,再選擇存活下來的個體,繼續變異,往復。直到到了我們限定的變異輪數。28行進行變異,29行選取最優個體;

  2. 17-23行選取兩個種?進?交叉變異;

  3. 11-16行對交叉變異后的種?進行多目標優化的評分計算,然后篩出最優個體。12行計算目標評分,13行進行非支配排序算法,進行分層。14行計算擁擠度與擁擠度比較算子。15行篩選出來最優個體;

  4. 1-10行就是對個體先進行序列化后,計算三個目標的分值。

圖片

圖片

圖 12:APICraft的多目標優化遺傳算法

04 實現

APICraft工程實現中核心之一是動態trace功能,動態trace是為了獲取API函數的參數以及返回值。如圖13所示,在hook中有兩種機制:

1.Type-I需要兩個hook點,函數的enter point以及exit point,enter point容易分析,但函數的exit point無法準確判斷,因為一個函數可能會有多個exit點,單純通過判斷ret指令是無法精確判斷exit點的,特別是當二進制程序被高度編譯優化過。錯誤的exit點的hook機制會導致后續收集的nested level等信息都有誤;

2.Type-II則沒有這個問題,基于interposition的機制是中間有個媒介層在進行函數前接管,在退出函數之后也接管。我們就能準確拿到參數值以及返回值。Interposition機制的核心是會有一個跟被hook函數相同函數簽名的替換函數,然后基于這個替換函數接管原函數的信息之后再調用原函數。在macOS上 APICraft用DYLD_PRELOAD跟DYLD_INTERPOSE機制來實現,在Windows上我們用的是detour來實現。

圖片

圖 13:兩種 hook機制

05 實驗結果

5.1 多目標優化遺傳算法

我們一共對5個攻擊面進行了漏洞挖掘,包含了Image,Font,PDF,Audio,RTF,這里用Image這個攻擊面來看看我們算法的實驗效果,其他攻擊面實驗效果可查閱論文。

  1. 圖14左圖是經過多目標遺傳算法生成的fuzz driver跟人工寫的fuzz driver在fuzzing過程中覆蓋率比對。紫色的線是APICraft生成的fuzz driver,淺色線是Google Project Zero的安全研究員手寫的fuzz driver,這個fuzz driver是研究員在對攻擊面熟悉,并且通過逆向構建出來的fuzz driver。實驗來看, 通過APICraft產生的fuzz driver在fuzzing過程中的覆蓋率仍比P0頂尖安全研究員手寫的fuzz driver實驗效果卓越;

  2. 圖14右圖是三個目標(Diversity、Effectiveness、Compactness)都結合起來生成的fuzz driver跟去掉每一個單一目標而生成的fuzz driver比對,比如綠色這條線是去掉多樣性(Diversity)的覆蓋率,去掉每個單一目標的實驗效果沒有三個目標都結合起來生成的fuzz driver在fuzzing過程中的實驗效果好。

圖片

圖 14:圖片攻擊面的多目標優化遺傳算法實驗效果

5.2 漏洞挖掘產出

基于APICraft生成的fuzz driver,我們進行了長達8個月的fuzzing。最終在macOS系統庫5個攻擊面上發現了142處漏洞,收到Apple 54個官方漏洞致謝(該數據統計截止5到論?投稿時,2021年2月)。

圖15節選了一些漏洞,每一列分別是攻擊面(Attack Surface),獲取到的CVE號或者 Issue-ID,macOS的復現版本,漏洞類型,已經能在哪些 APP上上復現這些bug。

圖片

圖 15:漏洞挖掘產出

06 總結

APICraft基于function interposition技術實現了輕量級的GUI應用程序動態行為收集框架,以及基于NSGA—II多目標優化遺傳算法實現的fuzz driver自動化生成框架。基于APICraft框架生成的fuzz driver在fuzzing過程中幫助我們挖掘到了macOS系統庫142處漏洞,共收獲Apple 54個官方漏洞致謝。

APICraft項目主頁鏈接為:https://sites.google.com/view/0xlib-harness 我們將在Usenix Security 2021會議完成之后開源代碼。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1706/