ProFuzzer: On-the-fly Input Type Probing for Better Zero-day Vulnerability Discovery

目錄

摘要

介紹

動機

總覽

設計與實施

類型探測

探測

類型指導突變


摘要

現有的基於變異的模糊器傾向於在不瞭解其底層語法和語義的情況下隨機變異程序的輸入。在本文中,我們提出了一種新穎的即時探測技術(稱爲ProFuzzer),該技術可自動恢復並瞭解在模糊過程中對漏洞發現至關重要的輸入字段,並智能地調整突變策略以增加擊中零日目標的機會。由於這種探測透明地揹負於常規的模糊測試,因此無需事先了解輸入規範。在模糊測試期間,首先對各個字節進行突變,並自動分析它們的模糊測試結果,以將相關的內容鏈接在一起,並確定連接它們的字段的類型;這些字節按照類型特定策略進一步突變在一起,這會大大減少搜索空間。我們通常在所有應用程序中定義探針類型,從而使我們的技術應用程序不可知。我們在標準基準測試和實際應用中進行的實驗表明,ProFuzzer的性能明顯優於AFL及其優化版本AFLFast,以及其他先進的Fuzzer,包括VUzzer,Driller和QSYM。在兩個月內,它在10個經過嚴格測試的程序中暴露了42個零日,生成了30個CVE。

介紹

模糊測試是一種廣泛使用的軟件測試技術,可以針對程序隨機或有策略地生成輸入以發現其漏洞。長期以來,它一直被認爲是程序安全性分析中最有效的方法之一,有助於發現最具影響力的安全性法則,例如CVE-2014-0160,CVE-2017-2801和CVE-20173732 [1], [2]。這種動態分析的關鍵是產生具有高度代碼覆蓋率的輸入,並且很可能會遇到隱藏在代碼內部的安全漏洞。通常,這可以通過使用輸入模型的知識來生成合法輸入,或者通過對一組初始種子輸入進行變異來完成,例如,通過隨機翻轉其位或策略性地將已知值替換爲輸入內容。然而,在以輸入空間大和輸入執行關係複雜爲特徵的現代軟件的存在下,這些常規方法變得越來越不足。

挑戰.更具體地說,基於生成的方法依賴於描述輸入格式的語法來產生合法的測試用例。這裏的語法需要先驗[3],[4]或從離線[5],[6]的執行跟蹤中恢復。更重要的是,儘管結構合理的語法確實減少了搜索空間,但它幾乎沒有提供各種輸入可能對程序執行產生影響的線索:例如,一組輸入是否都將導致相同的執行路徑,因此僅其中之一應進行測試。此外,利用漏洞的輸入甚至可能不會遵循輸入語法,因爲如果實現與功能無關,則實現可能會選擇忽略某些輸入字段(例如,圖像格式轉換器可能會忽略與渲染相關的字段);錯誤的實現甚至可能接受格式錯誤的輸入。

基於變異的方法不需要有關輸入模型的知識。相反,它使用一組合法的輸入實例作爲種子,並不斷對其進行修改以探索各種執行路徑。先前的研究已經研究了選擇可能導致執行程序進入易受攻擊的程序位置的正確種子的方法,以及確定可能增強代碼覆蓋率的關鍵輸入字節的方法[9],[10]。但是,對於給定的種子,變異通常是隨機的,即使輸入數據大小適中,變異也不會縮放。

正如我們在此處看到的那樣,對於高效和可擴展的模糊測試過程而言,至關重要的是深入瞭解目標程序的輸入。這樣的輸入通常是結構化數據,並且可以劃分爲具有特定語義的數據字段序列:例如,緩衝區大小,類別指示符等。這些字段的語義對於發現漏洞非常有用,有助於模糊測試人員確定要訪問的字段。變異,合法值的範圍,數據字段對程序執行的影響等。利用這些信息,模糊器可以以更智能的方式操作,僅關注於最有可能導致執行路徑從未見過的輸入子空間。但是,此信息(字段及其語義)可能沒有記錄,也無法提供給模糊測試者,並且如果不進行深入的重量級分析過程,可能很難恢復。

使用類型探測進行模糊測試。爲了解決挑戰並使用豐富的輸入語義提升當今的模糊技術,我們提出了一種新的智能模糊技術,稱爲ProFuzzer,它通過稱爲“探測”的輕量級隨機模糊過程自動發現輸入字段及其語義,以指導種子突變的在線進化。這種探測完全揹負於常規的模糊測試,並立即執行。更具體地說,ProFuzzer通過使一組種子變異來對目標程序執行兩階段模糊測試。在第一階段(即探測階段),它會按順序逐字節進行探測,即每次更改一個字節,針對目標程序枚舉其值,然後移至下一個字節。此順序的模糊測試步驟還會收集有關不同字節值下目標的執行路徑的信息。信息會自動在線分析以恢復數據字段(將相關字節鏈接在一起)並確定其字段類型:例如,特定內容導致突變的同一異常路徑的連續字節可以分組爲字段。在我們的研究中,我們確定了6種字段類型,這些字段類型對內容影響程序執行的方式進行建模,例如大小,循環數和枚舉,這些字段只有幾個有效值可以正確解釋輸入中的後續內容。這些類型與應用程序無關,描述了模糊相關的語義。數據字段及其類型的發現爲第二階段的模糊測試提供了指導,在此階段,ProFuzzer對每個字段進行突變以利用可能導致攻擊的值(例如,大數據量可能會利用緩衝區溢出漏洞),並根據字段類型探索合法值,以實現更好的覆蓋範圍。

我們在AFL上實施該設計[11]。我們將ProFuzzer與AFL,AFLFast [7],最先進的程序分析輔助模糊器VUzzer [12]和兩個最新的混合模糊器Driller [13]和QSYM [14]進行了比較4具有20個已知漏洞和兩個標準基準的應用程序(LAVA-M [15]和Google模糊測試套件[16])。結果表明,ProFuzzer能夠以更少的時間發現更多的錯誤。例如,對於4個實際應用程序,ProFuzzer可以在24小時內發現18個錯誤,而其他Fuzzer的最佳結果僅爲15個。此外,ProFuzzer每次錯誤所需的平均時間僅爲所需時間的18-73%由其他的模糊測試。可以在第五節中找到更多詳細信息。

發現。我們還在10種流行的現實世界開源應用程序上運行了ProFuzzer兩個月,其中包括用於圖像處理的軟件(例如OpenJPEG),音頻和視頻解碼器(例如LibAv),PDF閱讀器(例如MuPDF)和壓縮庫(例如ZzipLib)。我們的研究結果發現了42個零日漏洞,例如堆溢出,無限循環等。一旦被利用,大多數漏洞將帶來嚴重後果。例如,可以通過非常小的製作的圖像文件觸發Exiv2(CVE-2017-17725)中的堆緩衝區讀取漏洞,從而導致4字節的信息泄漏,從而有助於進一步利用(例如,繞過地址空間隨機化)。請注意,即使Exiv2已經過廣泛的測試[17],但這種脆弱的能力仍然落空了。我們已將調查結果報告給所有受影響的軟件供應商。到目前爲止,他們中的大多數人已經承認我們發現的問題是真實的和重要的。我們已經獲得30份CVE,並且正在對其他報告的問題進行調查。

貢獻。我們有以下貢獻:

•新的智能模糊技術。我們設計了一個高效的智能模糊器,它通過輕量級的探測來發現輸入字節與程序行爲之間的關係,以指導後續針對性的種子突變。這種方法將語義知識發現無縫透明地集成到模糊處理過程中,不僅提高了模糊處理的準確性,而且提高了其性能,而不會降低適用性。

•發現0day漏洞。在實際的應用程序上運行我們的模糊器,我們在兩個月內發現了42個0day漏洞。我們的發現表明,這種在線語義發現和變異指導技術可以改善現有技術。

動機

我們使用OpenJPEG [18]來解釋傳統的模糊技術和ProFuzzer的思想問題。 OpenJPEG是一個開源圖像編解碼器庫,可將各種圖像格式轉換爲JPEG2000。它已廣泛集成到用於圖像處理的商品軟件中。

基於變異的模糊測試。基於變異的模糊測試會在不瞭解種子輸入語義的情況下對其進行變異。這樣,突變很大程度上是隨機應用的。該方法簡單且與應用程序無關。但是,由於缺少輸入語義,它無法有效工作。圖1a顯示了OpenJPEG的種子輸入。我們使用最廣泛使用的基於突變的模糊處理工具AFL對具有5個已知漏洞的舊版本OpenJPEG庫進行模糊處理,並且在24小時後僅發現了其中3個。我們發現62個字節中只有24個字節(圖1a中突出顯示)有助於改善覆蓋範圍。圖1b顯示了24小時內每個字節上的突變數。超過60%的突變沒有幫助。根本原因是,在沒有輸入規範的情況下,基於突變的模糊測試沒有得到適當的指導。目前已經進行了推斷輸入語義以改善模糊的工作。 AFL提供了一個簡單的離線文件格式分析器實用程序(AFL-analyze [19])來推斷輸入語法,以及一個內置的字典構造功能[20]來標識應用程序特定的關鍵字。但是,由於其簡單性,它們的有效性有限(請參閱V-C部分)。

基於規範的模糊測試。類似AFL的方法的自然增強是使用輸入規範(例如,輸入語法和語義約束)來指導模糊測試。確實,先前對基於符號執行的測試的研究表明,輸入語法可以大大提高模糊測試的有效性[21]。但是,這些方法通常很難部署。首先,規格並非總是可用。其次,規範可能是隱含的,需要大量的人工來提取。這極大地影響了模糊技術的適用性。最重要的是,模糊測試是一個二進制過程。它與實際的實現高度相關,實際的實現可能與其輸入規範有不小的偏差。應用程序通常僅支持部分規範,有時規範將包括一些保留的字節,其功能在各種實現/擴展中進行了自定義[22]。例如,圖1a中從偏移量0x1c-0x1d開始的字節用於表示顏色深度。根據規範[23],它們可能的值爲0x01、0x04、0x08、0x10、0x18和0x20。但是,當前版本的OpenJPEG不支持0x01或0x04。最後,這些規範不是面向模糊測試的,因此,許多生成的輸入對於模糊測試仍然是多餘的。也就是說,這些輸入對程序有效,但不能改善路徑覆蓋範圍或漏洞發現。

ProFuzzer的基本概念。 ProFuzzer受到兩個重要觀察的啓發。首先,對於模糊測試,不需要全面,特定於應用程序且語義豐富的輸入規範。例如,圖1a中從偏移量0x26到0x2d的字節表示圖像的分辨率。根據文件格式規範,它們是重要的輸入字段。但是,OpenJPEG在圖像轉換期間會跳過這些字節。因此,識別字段不會帶來太多的模糊感,因爲它們的內容不會影響轉換期間的執行路徑。相反,更有用的信息是識別對於模糊測試至關重要的特殊類型的字段。例如,如果我們知道字段描述了緩衝區大小,則可以應用定製的變異規則來找出是否存在易受攻擊的緩衝區。其次,可以通過直接觀察模糊過程來理解輸入,並可以發現其字段和數據類型,特別是輸入內容的更改方式以及響應該更改的程序執行路徑的更改。這樣,依靠重量分析的現有輸入格式逆向工程技術(例如,REWARDS [24],TIE [25],Howard [26])既沒有必要,也沒有成本效益。相反,我們相信可以通過對先前的模糊結果進行即時語義分析來識別輸入字段及其類型,然後指導將來的輸入突變,從而將輸入理解無縫地集成到模糊過程中。

根據觀察結果,我們設計了兩階段的模糊技術ProFuzzer。在第一階段,它通過按字節的突變來探查種子輸入的輸入字段和字段類型。特別是,根據目標程序在突變下的行爲變化(例如執行路徑更改),ProFuzzer可以識別關鍵的輸入字段。然後在第二階段中使用字段和字段類型信息來指導在線輸入突變。不同的領域類型具有不同的優先級,並且需要採取各種變異策略。例如,我們的方法避免了對原始數據類型的字段進行變異,因爲原始數據類型的變異導致目標程序經過相同的路徑。對於具有緩衝區大小類型的字段,遵循特定的突變模式(例如,優先考慮邊界值),將屬於同一字段的多個字節一起突變。相反,即使AFL具有某些預先定義的突變模式,例如將連續輸入字節的隨機子序列更改爲特殊值(例如0xFF),也很難將其應用於正確的子序列。

藉助可感知的場域突變,ProFuzzer可以提高模糊測試的有效性和性能。我們在OpenJPEG上運行ProFuzzer 24小時,發現所有5個已知漏洞,並且路徑覆蓋率比AFL高60%。我們還計算了圖1c中每個字節在24小時內經歷的突變數。請注意,相同字段中的連續字節具有相同的突變計數。具體而言,由於62個輸入字節中的數據對於模糊測試很重要,因此只有24個輸入字節發生了突變。例如,ProFuzzer探測並確定在0x0e到0x11之間存在一個偏移量域,該偏移量域確定了後續數據字節(來自文件頭)的偏移量。偏移場對於漏洞檢測非常重要,因爲它們會對內存行爲產生重大影響。這些信息可以使ProFuzzer避免盲目模糊,而可以使用特定的突變策略(例如,將偏移字段的值設置爲當前位置和文件結尾之間的差)來策略性地探索字段的輸入空間。再舉一個例子,在512次探測運行之後,位於0x1a和0x1b的字節被識別爲原始數據,因此這些字節上沒有進一步的突變,而它們被AFL突變了407,170次。

總覽

圖2

ProFuzzer的體系結構如圖2所示。它由四個組件組成:探測引擎,變異引擎,執行引擎和報告引擎。

探測引擎。探測引擎的任務是根據給定二進制文件的種子輸入生成類型模板。對於每個種子輸入,ProFuzzer將遍歷所有字節。對於每個字節,它遍歷所有可能的值(0x00至0xff),並收集相應的執行文件。然後,從這些配置文件中提取一些指標(例如,由突變引起的邊緣覆蓋率變化),並將其用作字節的特徵。然後,ProFuzzer將具有相似功能的連續字節分組到字段中。最後,它根據可能值的變化與觀察到的特徵的相應變化之間的關係來確定每個字段的類型(例如,幻數字段可以通過所有突變都發生在原始值中的模式來表徵)。種子輸入導致輸入無效,因此執行時間短)。

變異引擎。突變引擎使用所探查的模板(即字段和字段類型)來指導後續的突變。指南從兩個方面給出:首先是以具有成本效益的方式擴大覆蓋範圍。例如,ProFuzzer可以避免對原始數據字段進行模糊處理,而將注意力集中在確定後續數據解釋的變異字段上。這將使我們能夠到達原本很難到達的代碼區域。在第二方面,領域信息可以用來指導漏洞利用的產生。例如,緩衝區大小字段是許多漏洞的根本原因。衆所周知,某些突變模式對於規模領域至關重要。

 

執行引擎和報表引擎。我們使用標準的AFL執行和報告引擎。每次探測引擎或變異引擎請求執行應用程序時,執行引擎都會派生一個新進程。執行期間,它會自動收集執行配置文件。報表引擎監視執行情況,尤其是崩潰或掛起。

假設。 我們假定目標應用程序具有以下屬性。 首先,它的執行是確定性的:也就是說,給定相同的輸入,應用程序的多次執行都遵循相同的執行路徑併產生相同的結果。 其次,可獲得合理大小的初始有效種子輸入。 ProFuzzer的重點是類型探測和基於類型的突變,而不是種子選擇。 因此,現有的種子輸入生成/選擇技術[27]是ProFuzzer的補充。 第三,如果對某些字節的驗證失敗,則執行將迅速終止,這意味着異常執行的執行路徑比正常執行路徑短。 我們在第V-A節中進行了一項實證研究,以驗證上述假設。

設計與實施

模糊相關的輸入字段類型。如前所述,與應用程序無關的輸入字段類型的知識可以爲模糊測試提供強有力的指導。爲此,我們確定了6種輸入字段類型,包括斷言,原始數據,枚舉,循環計數,大小和偏移量。這些類型涵蓋了流行應用程序的大多數輸入內容,例如圖像處理工具,文檔閱讀器和壓縮實用程序。最重要的是,這些類型以獨特的方式影響程序的執行,因此對於增強程序模糊化的有效性非常有用。在下面對這些類型的討論中,我們以圖1a爲例。對於每種類型,我們提供OpenJPEG中BMP轉換組件的簡化代碼段,以處理該類型的輸入。稍後,我們將展示如何識別這些類型以及如何在模糊測試中利用它們。

•斷言。斷言類型的輸入字段只有一個有效值,可以使程序正確執行。其他值將導致程序終止並出現錯誤。示例映像中偏移量0x00和0x01處的字節形成一個聲明字段。如下面的代碼片段所示,OpenJPEG檢查該字段以確定它是否等於0x4d42,這是BMP文件的幻數。在模糊測試期間,任何聲明字段的內容都不應更改。否則,測試用例將無效。

•原始數據。對於原始數據類型的輸入字段,其內容不影響程序的執行(例如,其控制流和內存訪問)。請注意,原始數據是特定於實現的。在我們的示例圖像中,從偏移量0x26到0x2d的字節是圖像分辨率,這對於圖像渲染應用程序很重要。但是它們是OpenJPEG的原始數據,因爲它僅轉換格式而不渲染圖像。在模糊測試期間,我們不需要更改原始數據字段。

•枚舉。枚舉類型的輸入字段的特徵是一小套有效值,其他值導致程序錯誤地終止。一個示例是示例圖像中從偏移量0x1c到0x1d的字段。這些字節代表圖像的顏色深度,根據文件格式規範,其可能值爲0x01、0x04、0x08、0x10、0x18和0x20。但是,在當前的OpenJPEG實現中,僅支持0x08、0x10、0x18和0x20。如下面的代碼片段所示,將調用不同的處理函數來處理不同的有效顏色深度。在模糊測試中,我們只想測試有效值。

循環計數。 循環計數類型的輸入字段決定了循環結構(例如for / while循環或遞歸調用)中代碼片段應執行的時間。 循環計數值對路徑計數有實質性影響,而對路徑本身的影響則微不足道。 示例圖像中偏移量0x36處的字節是循環計數的實例。 它是根據文件格式指定的原始數據字段。 但是,它表示RGB值,這樣在進行顏色變換(例如,修改的普查和離散小波變換)之後,其值會影響變量bpno,如以下代碼片段所示。 變量又決定循環中需要編碼的位數。

偏移量。偏移量類型的輸入字段確定程序可以從中訪問輸入文件中後續數據的位置。偏移量域對於模糊測試很重要,因爲錯誤的偏移量值可能會導致程序訪問範圍之外的數據(例如,文件末尾),從而導致後續驗證檢查出錯並終止。在有效範圍內,不同的偏移會導致訪問不同的後續數據。如果訪問的數據對控制流有影響(即非原始數據),則其不同的值可能導致執行採用不同的路徑。例如,示例圖像中從偏移量0x0a到0x0d的字段是偏移量的一個實例,它指向程序從中加載圖像數據的位置。在我們的例子中,它從文件的第54個字節開始。如以下代碼片段所示,如果將偏移量設置爲大於54,則fseek()會超出文件末尾,從而導致異常。在模糊測試期間,需要以與之前的位置轉換突變相一致的方式來更改偏移字段(例如,添加數據字段)。

Size.大小類型的輸入字段確定程序應從輸入文件讀取以進行進一步處理的數據量。與偏移量類型類似,如果大小值導致任何超出範圍的數據訪問,程序將終止並顯示錯誤;在有效範圍內,由於處理了不同的數據,不同的大小可能會導致不同的執行路徑。偏移量和大小之間的區別在於,如果將大小值設置爲零,則必須發生錯誤,而將偏移量設置爲0可能不會引起類似的問題。示例圖片中從0x16到0x19的字節是size的一個實例,代表了圖片的高度。正確的大小是0x02。如果大小設置爲零或大於0x02(例如0x03),則程序將終止並顯示錯誤消息。在模糊測試期間,大小字段突變受總輸入大小限制。

請注意,這些字段類型不同於編程語言中的傳統類型或程序員定義的類型。我們類型系統的重要設計標準包括與應用無關和模糊相關。這六種類型可能並不全面。輸入字節可能不屬於任何一個。在這種情況下,ProFuzzer會退回到AFL進行的常規隨機突變。

類型探測

ProFuzzer會通過逐字節突變並分析各個突變字節對程序執行的影響,由ProFuzzer自動發現字段類型。 具體來說,給定一個程序,ProFuzzer在探測過程中一次更改其輸入一個字節,枚舉該字節的所有256個值以收集相應的256個執行文件。 這些配置文件存儲在緊湊的哈希數組中,該數組保持各個控制流邊緣的執行頻率(即,控制從基本塊到另一個的轉移)。 我們稱這種運行時輪廓邊緣向量的表示。 在我們的系統中,每個邊緣向量都用於提取許多特徵,以表徵正在探測的字節。 然後,利用這些功能將多個字節分組到一個字段中,並進一步確定該字段的類型。

定義。 爲了便於討論,我們引入以下定義。 讓I作爲輸入– len字節序列,每個字節的範圍從0x00到0xff,T_{I}是函數execute的輸出,該函數在I上運行目標程序並返回邊沿向量。 我們有:

I=\left \{0x00,0x01,...,0xff \right \}^{len},T_{I}=execute(I)

I_{\left [ i \right ]:v}爲函數替換的結果,該函數將I的第i個字節替換爲值v

 I_{\left [ i \right ]:v}=substitude(I,i,v)

對於在偏移量i處突變爲值v的輸入字節,我們基於邊緣矢量T_{I}T_{I\left [ i \right ]:v}定義了兩個度量:覆蓋相似度S_{I\left [ i \right ]:v}和頻率差D_{I\left [ i \right ]:v}。 前者着重於測量邊緣覆蓋率的相似度(即不考慮邊緣被取的次數),而後者則測量是否佔優勢的邊緣具有不同的執行頻率。 特別地,S_{I\left [ i \right ]:v}計算爲兩個向量的邊緣覆蓋交集的大小除以它們的並集大小。D_{I\left [ i \right ]:v} 計算爲具有不同頻率的邊緣數量與具有不同覆蓋率(即,一個覆蓋但不被另一個覆蓋)的邊緣數量之比。

作爲示例,在下面,我們顯示示例圖像輸入的邊緣矢量T_{I}T_{I\left [ 0x1c \right ]:0x20} ,其對應的輸入在偏移量0x1c處有所不同,原始值爲0x18,突變值爲0x20。 我們可以看到,兩個向量在具有索引13的邊緣具有相同的覆蓋範圍,在邊緣583和13052處具有不同的覆蓋範圍。對於邊緣34093,兩個執行都覆蓋了邊緣,但是頻率不同。 邊緣覆蓋相交和並集的大小分別爲1727和1766。 因此,覆蓋相似度爲0.978(1727/1766)。 不同的邊緣頻率和不同的覆蓋範圍分別爲1和39。 因此,頻率差爲0.026(1/39)。 這兩個指標表明這兩個執行非常相似,不同之處主要在於邊緣覆蓋率而不是邊緣頻率。

 STEPI:特徵提取。 我們爲每個字節i提取兩個特徵,作爲兩個元組,每個元組的大小爲256:F_{i}^{S}表示[0x00,0xff]範圍內的變異值的覆蓋相似度,稱爲覆蓋特徵;F_{i}^{D}表示256個突變值的頻率差,稱爲頻率特徵。

爲了測量覆蓋特徵F_{i}^{S}的集中趨勢,我們將其中值\alpha _{i} 定義爲:

爲了易於理解,我們通常將覆蓋範圍特徵F_{i}^{S}可視化爲條形圖,例如,圖3。x軸表示從0x00到0xff的字節值。 y軸表示與字節值相對應的coverage相似性度量。 我們向讀者介紹附錄A中示例圖像中每個字節的覆蓋範圍。

第二步:現場識別。 字段識別的目標是將相同輸入類型的連續字節分組爲一個字段。 觀察

到目標程序傾向於對整個輸入字段而不是單個字節執行驗證檢查。 憑直覺,如果連續字節屬於同一個字段,則很有可能它們共享與無效(變異)值相對應的大部分變異特徵。 具體來說,儘管字段中的每個字節可能具有多個有效值(例如,枚舉字段),這些值通常會導致執行路徑不同,從而導致度量不同,但許多無效值總會導致相同的終止路徑,但例外情況是 最短路徑。 因此,這些無效值必須導致相同的覆蓋範圍和頻率指標。 因此,如果滿足條件(6),我們將字節從i到j的偏移量分組爲一個字段。

注意,最小覆蓋相似度值對應於由無效突變引起的最短路徑。 在我們的示例中考慮偏移量爲0x1c和0x1d的字節。 偏移量爲0x1c處字節的覆蓋範圍特徵如圖3c所示。 儘管該字節可能具有多個與原始執行具有較高覆蓋相似度的有效值(例如,具有0.978相似度的值0x20和具有0.959相似度的值0x10),但是當給出無效值時,其最小覆蓋度相似度爲0.068,與 字節在0x1d處的最小相似度。 回想一下,源代碼在這兩個字節上有一個switch case語句,這樣對任何一個字節的所有無效突變都會導致相同的失敗路徑。

步驟III:字段類型標識。 給定一組連續的字節作爲輸入字段,下一步是確定字段的類型。

斷言字段。 對於從i到j偏移的字段,如果它滿足條件(7),我們認爲它是斷言字段。 該條件意味着,對於偏移量爲x∈[i,j]的任何字節,該字節都只有一個值v,該值會誘發相似性得分1。對於其他任何值,相似性得分均小於中間值。

直覺是斷言字段中的任何字節都只有一個有效值,該值允許程序正常運行。 其他值將導致相同的帶異常終止路徑,從而導致與原始執行的相似度較低。 中間值\alpha _{x}可用於區分原始執行和錯誤執行。

例如,圖1a中偏移量爲[0x00,0x01]的字段是一個斷言字段。圖3a展示了字節在0x00處的相似性。 如我們所見,只有0x42的值會導致相似度得分爲1的正常執行,其他值會導致相似度得分爲0.059的異常。

原始數據字段。 對於從i到j偏移的字段,如果它滿足條件(8),我們認爲它是原始數據字段。 該條件意味着,對於偏移量爲x∈[i,j]的任何字節,其與原始執行相比的相似性分數對於所有值始終爲1。

直覺是原始數據字段的值一定不會影響程序的控制流。 例如,圖1a中偏移量爲[0x26,0x2d]的字段被視爲原始數據字段。 它表示圖像分辨率,它對圖像轉換的控制流沒有影響。 圖3b顯示了字節0x26的相似性特徵。

枚舉字段。 枚舉字段滿足條件(9),這意味着在偏移量x∈[i,j]處存在一個字節,並且集合VS是集合{0x00,...,0xff}的適當子集,子集大小大於1所示,對於VS中的任何值v,其相似性得分均大於中值,而對於不在VS中的任何字節u,其相似性得分均小於中值。

直覺是枚舉字段具有少量有效值。 對於那些有效值,相似度得分相對較高,因爲程序可以正確進行。 但是,對於其他值,相似度得分非常低,因爲控制流最有可能轉移到錯誤處理代碼。

圖1a中[0x1c,0x1d]處的字段是一個枚舉字段(指示顏色深度)。 圖3c可視化了字節0x1c的覆蓋範圍。 該圖還告訴我們,OpenJPEG的當前實現支持四種圖像格式。

循環計數字段。 循環計數字段滿足條件(10),這意味着覆蓋範圍相似性得分的方差小於β,這是一個預定義的值,表明數據變化較小[28],[29]。 頻率差異的平均值大於1,這意味着與覆蓋差異相比,頻率差異占主導地位。

這種情況背後的直覺是,循環計數值對邊緣頻率有實質性影響,而對邊緣覆蓋率的影響可忽略不計。 圖1a中偏移量0x36處的字節是循環計數字段。 它確定循環中需要編碼的位數。 圖3d可視化了字節的覆蓋範圍特徵。 我們可以看到,這些值的相似性得分非常接近,這意味着它們的覆蓋率差異很小。 但是,當我們計算不同頻率的邊緣數與不同覆蓋率的邊緣數之比時,平均值爲7.355,表明前者佔優勢

偏移字段。 偏移量字段需要滿足(11),這意味着在偏移量x∈[i,j]處存在一個字節,以使覆蓋範圍相似度值0(即,當字節更改爲0時,覆蓋範圍與原始執行的相似度)大於中間範圍,並且範圍[0x00,0xff]中也存在值t ,這樣有兩個小於t的值u和v具有不同的相似性評分,而任何大於t的值w始終具有小於中值的相似性評分。。

直覺是,偏移字段的有效範圍由其餘輸入的長度(即,從字段旁邊的字節到結尾)的長度來界定。 將字段更改爲大於界限的任何值可能會導致超出範圍的訪問,並因此導致異常。 將字段更改爲小於界限的任何值都會導致訪問不同的後續數據,進而可能導致不同的執行路徑。 這樣,存在兩個這樣的值u和v,它們的覆蓋相似度度量是不同的。 此外,將該字段更改爲0很可能是有效的,因爲這意味着該程序將在該字段之後立即訪問後續數據。

例如,圖1a中[0x0a,0x0d]處的字節是一個偏移字段,它指向程序從中加載圖像數據的位置。 圖3e可視化了字節0x0a的覆蓋範圍。 我們可以看到0x36是邊界。 超出界限時,覆蓋範圍相似性指標會很低,因爲程序會因錯誤而終止,從而導致與原始執行的實質性差異。 在邊界內,不同的偏移值會導致不同的相似性指標。 值0的覆蓋相似度大於中間範圍。

size字段。大小域需要滿足類似於(11)的條件,除了在偏移量x∈[i,j]處存在一個字節,以使值0的覆蓋相似度小於中間範圍。直覺上,大小域與偏移域具有相似的特性,因爲也存在一個由剩餘輸入的長度決定的界限。區別在於將偏移量字段更改爲0可能會導致成功執行,而將尺寸字段更改爲0則通常會導致提前終止。

例如,圖1a中[0x16,0x19]處的字節是指示圖像高度的大小字段。圖3f可視化了字節0x16的覆蓋範圍。注意,由於我們使用小圖像作爲輸入,因此值0x02是邊界。大於邊界的值具有非常小的相似性分數,表明提早終止,並且值0的分數低於中間範圍。

我們將大小域與偏移域區分開來,因爲它們具有不同的突變策略。例如,當將偏移字段增加1時,我們在該字段之後立即插入一個字節,以便在變異運行中訪問相同的原始後續數據。相反,當將大小字段增加1時,我們在輸入的末尾插入一個字節。如果輸入以斷言字段結尾,則將字節添加到該字段之前。

在某些情況下,偏移量/大小字段可能緊鄰原始數據字段。確定這些字段的邊界可能很棘手,因爲對偏移量/大小字段的最小字節進行更改可能不會導致任何執行更改,從而使其與原始數據字節無法區分。我們通過將識別出的大小/偏移字節與它們相鄰的原始字節分組來解決該問題,只要分組字節表示的值不超過種子輸入的大小即可。

我們的實驗表明,我們的領域探測非常精確,平均假陽性率只有5.2%,假陰性率只有4.5%(請參閱第V-C節)。

探測

在模糊化過程中,給定新的(突變的)輸入,ProFuzzer首先嚐試重用被探測的模板,該模板的執行跟蹤與輸入的執行跟蹤類似。 如果沒有這樣的模板,我們將變異輸入視爲新的種子輸入,並像探測原始種子輸入一樣重新探測其字段。 在重新進行探測之前,ProFuzzer會利用AFL內置的輸入微調功能來儘可能減小輸入大小,並對小尺寸輸入進行優先排序。

挑戰在於新的種子輸入可能不會導致正常執行,而是導致異常執行。 因此,重新探測的基本思想是,當對新的種子輸入進行突變導致執行時間比種子更長時,我們認爲重新探測的突變正接近於有效輸入,因此,我們將當前種子替換爲變異的種子並繼續。 請注意,執行時間越長,表明變異的種子會通過更多的驗證檢查

重新探測特徵提取。 由於種子執行的無效性,重新探測必須基於測量執行長度變化的不同執行特徵。 對於偏移量爲i的字節(其突變爲值v),我們基於邊緣矢量T_{I}T_{I\left [ i \right ]:v}定義了重測指標R_{I\left [ i \right ]:v} 。 度量標準度量執行期間獲取的邊數之間的比率,即TI 中和TIi:v 中具有非零計數的邊數。 然後,我們提取偏移量爲i的字節的重探測特徵FiR 作爲256個元素的元組,每個元素對應一個重探測度量。

字段類型重新標識。 在下文中,我們將說明如何使用新功能來探究斷言字段和枚舉字段。 由於篇幅所限,無法重新探測其他領域。

•重新聲明斷言字段。 對於i處的字節,如果滿足條件(13),則將其視爲聲明字段。 該條件意味着該字節存在一個且只有一個值v,該值導致比原始執行更長的執行時間。 對於任何其他值,執行時間都小於或等於原始執行時間。 識別出這樣的值後,我們用識別出的值替換字節,以使執行進一步進行。 按照第IV-A節中描述的相同方法,將多個這樣的字節分組到一個斷言字段中。

重新探測枚舉字段。 對於偏移量爲i的字節,如果滿足條件(14),則認爲該字節屬於枚舉字段。 該條件意味着存在一個集合VS,它是集合{0x00,...,0xff}的適當子集,其大小大於1,因此對於VS中的任何值v,結果執行時間都比原始執行時間長 。 對於其他任何值,執行時間都小於或等於原始值。 可以將多個此類字節分組到一個枚舉字段。

類型指導突變

探測場用於指導突變。該指南從兩個方面提供。在第一個方面,它將突變限制爲字段類型的所有合法值,以實現更好的覆蓋範圍。我們稱之爲探索突變。在第二個方面,ProFuzzer對每個字段進行突變,以利用可能導致潛在攻擊的一組特殊值(針對特定字段類型)。我們稱其爲利用突變。在模糊過程中,ProFuzzer會交錯這兩種模式。從直覺上講,它嘗試利用當前種子涵蓋的路徑。如果該過程沒有結果,它將開始通過產生更多種子來探索更多的覆蓋範圍,依此類推。

探索突變。擁有字段信息的一個重要優點是我們可以在字段級別而不是字節級別應用突變,從而大大減少了無效突變的數量。此外,我們在探索階段採用了以下突變策略。 (1)我們不允許對原始數據字段進行任何更改。 (2)對於一個枚舉域,我們分配一個在其有效範圍內的值(請參閱第IV-A節)的可能性很大(在我們的研究中爲0.9),而在該範圍之外的值則分配的可能性很小(0.1)以探索其他探測期間遺漏了有效值。特別是,我們利用類似於VUzzer [12]的技術從主題程序中提取常量(例如,數字和字符串),以使那些與字段大小相同的值成爲候選突變。 (3)即使對於斷言字段,我們不應該在模糊化過程中更改其內容,但在探測字段歸類錯誤的情況下(例如,將枚舉字段視爲斷言)。 (4)對於偏移量字段,當突變將其值增加(或減少)X時,我們會在字段後立即插入(或刪除)X字節。 (5)對於一個大小域,當突變將其值增加(或減小)X時,我們將在最後一個非斷言域的末尾插入(或刪除)X字節。插入的數據是隨機生成的。 (6)對於循環計數字段,我們執行二進制搜索以識別其最小和最大有效值。 (7)對於無法歸類爲六種類型之一的其他字段,我們執行默認的AFL隨機每字節突變。

剝削突變。我們手動分析了一百多個已知漏洞的PoC,發現給定字段類型通常具有少量值,可能導致利用。此類模式與應用程序無關。由於我們已經認識到了領域和領域類型,因此利用這些模式可以幫助有效地發現新的漏洞。特別是,對於每個PoC,我們使用ProFuzzer探查其字段模板,然後對字段類型和導致剝削的相應值進行了手動研究。當前,該過程需要領域知識和手動工作。我們將剝削規則的自動學習從大量的PoC留給我們的未來工作。表I列出了我們發現的大小,偏移量和循環計數字段。由於篇幅所限,其他的被省略了。考慮規則1,該規則指定我們可以將大小字段更改爲程序找到的任何大小字段的最大值。直觀地,各種大小值對應於我們不關心其特定於應用程序類型的不同數據結構。突變實質上迫使程序將後續數據解釋爲不同的數據結構(具有更大的大小)。如果程序具有與類型相關的錯誤,例如類型混淆[30],則該突變將有助於揭示問題。規則2、3、4、7、8有類似的想法。規則9意味着通過指定的突變,我們迫使程序開始在輸入結束後開始讀取。請注意,在開發過程中,我們的目標是暴露錯誤。因此,當增加偏移量時,我們不需要用新的字節來修補輸入。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章