◆林 敏 張 超
(清華大學(xué) 北京 100084)
隨著業(yè)界對軟件安全問題的關(guān)注度不斷提升,漏洞挖掘逐漸成為重點研究的內(nèi)容。模糊測試[1]作為一種通過隨機樣本挖掘軟件漏洞的技術(shù),相比于其他漏洞挖掘技術(shù)更加簡單高效。它是一種向應(yīng)用程序提供非預(yù)期的輸入,通過監(jiān)控執(zhí)行中的異常,來發(fā)現(xiàn)軟件漏洞的方法。目前應(yīng)用得較為廣泛的灰盒測試工具是AFL[2]及其擴展[3-6]。
然而傳統(tǒng)的模糊測試存在一個公認的缺點:對于具有復(fù)雜文件格式輸入的應(yīng)用程序,隨機的比特變異難以生成合法有效的文件,往往在應(yīng)用程序初始執(zhí)行階段就無法通過檢查,難以對應(yīng)用程序的深層邏輯進行有效的檢測,導(dǎo)致了模糊測試的低效。
本文對EOS執(zhí)行智能合約所使用的WebAssembly二進制虛擬機進行研究,該目標對象的輸入不僅具有高結(jié)構(gòu)化的特征,同時因其代碼段由各種指令組成,還包含豐富的語義信息。想對虛擬機進行完整的測試,不僅要保留 WebAssembly二進制文件的整體結(jié)構(gòu)信息,同時還要在符合 WebAssembly語法的情況下盡可能地變異出包含各種語義的文件。
但是基于覆蓋率的模糊測試最大的問題是缺乏對輸入文件的結(jié)構(gòu)理解。測試中的變異操作通常在比特的層面進行,例如進行位翻轉(zhuǎn)、刪除、添加等,但是對于具有復(fù)雜文件格式規(guī)范的應(yīng)用程序來說,不合法的文件可能導(dǎo)致程序在初始的合法性檢查階段就退出,導(dǎo)致生成了大量無效的測試用例,難以發(fā)現(xiàn)應(yīng)用程序的深層次邏輯漏洞。針對傳統(tǒng)方案的局限性,研究人員也提出了新的方案,比較主流的有基于字典和污點跟蹤的方法。
AFL的作者采用了自定義字典[15]的方式,讓用戶提供關(guān)于輸入文件結(jié)構(gòu)的信息。當(dāng)輸入文件中存在魔數(shù)和塊標識符的情況下,這種方式能發(fā)揮比較好的作用?;贏FL的拓展工具VUzzer[7]通過靜態(tài)分析和動態(tài)污點跟蹤和的方法來定位變異點。但是這兩種方式都不能解決上述的問題,即無法從更高的層面,而非比特層面來改變文件的結(jié)構(gòu)信息。例如,通過字典和污點跟蹤的方案都不能添加或完刪除文件塊。
Driller[8]在AFL的基礎(chǔ)上加入了動態(tài)符號執(zhí)行引擎,交替探索程序執(zhí)行路徑,引導(dǎo)模糊測試探索到程序更深層次的節(jié)點。但是,基于符號執(zhí)行增強的模糊測試技術(shù)仍然會受限于符號執(zhí)行中的約束求解問題,符號執(zhí)行的引入可能會弱化模糊測試本身的可擴展性。
針對上述問題,本文提出了一種針對EOS的WebAssembly二進制虛擬機進行模糊測試的方案,與傳統(tǒng)的模糊測試方案不同,本方案通過研究 WebAssembly各模塊對執(zhí)行的影響,利用WebAssembly的文件格式構(gòu)造有效文件,對WebAssembly文件進行分解,再將各個模塊之間進行組合和修改,增加了在高級結(jié)構(gòu)而非比特層面的變異。同時,本方案還對WebAssembly的代碼段進行了深入的變異,通過改變初始化數(shù)據(jù)、打亂的合法指令序列來增加變異的多樣性,讓輸入能探索更多的路徑。同時,本方案還引入了一個基于有效性的能量調(diào)度方案,讓模糊測試在有效的種子上花費更多的時間,增加發(fā)現(xiàn)程序處理邏輯漏洞的概率。
基于本文的方案,實現(xiàn)了WASMAFL,是一個基于AFL的模糊測試工具,在其基礎(chǔ)上增加了 WebAssembly變異的策略和能量調(diào)度策略。在我們的評估中,將兩者進行了比較,評估結(jié)果表明,在給定的24小時內(nèi),WASMAFL可以比AFL發(fā)現(xiàn)更多的崩潰,還顯著提高了路徑覆蓋率。
總之,本文的主要貢獻是對 WebAssembly虛擬機提出了新的模糊測試方案,能夠高效地對其進行灰盒模糊測試,同時該方案也適用于其他腳本語言的虛擬機。
隨著業(yè)務(wù)邏輯越來越復(fù)雜,前端開發(fā)的代碼量變得越來越大,然而由于JavaScript動態(tài)類型語言的限制,造成了嚴重的性能瓶頸,因此WebAssembly應(yīng)運而生。WebAssembly[9]是一種體積小、加載快、可移植并且兼容Web的全新二進制格式,可以很方便地將C、C++和Rust等低級語言的代碼以接近原生性能的速度運行在瀏覽器等本地客戶端中。同時,WebAssembly也被新興的區(qū)塊鏈技術(shù)所看好,被稱為“區(qū)塊鏈 2.0”的以太坊[10]計劃使用WebAssembly虛擬機取代目前的 EVM,被稱為“區(qū)塊鏈 3.0”的EOS[11]選用了WebAssembly虛擬機作為合約的執(zhí)行引擎。
EOS作為最具代表性的委托股權(quán)證明DPoS平臺和第一個去中心化的操作系統(tǒng),近年來發(fā)展迅速,是全球最活躍的社區(qū)之一。EOS采用WebAssembly作為智能合約的執(zhí)行語言。智能合約[12]是一種以信息化方式傳播、驗證或執(zhí)行合同的計算機協(xié)議,允許在沒有第三方的情況下進行交易,這些交易可追蹤且不可逆轉(zhuǎn)。由于智能合約可以由任何人發(fā)布,因此攻擊者可以通過構(gòu)造惡意合約來對區(qū)塊鏈平臺進行攻擊。同時,由于區(qū)塊鏈平臺去中心化的特點,單個節(jié)點的漏洞會導(dǎo)致成千上萬的節(jié)點遭到攻擊,甚至在傳統(tǒng)軟件漏洞領(lǐng)域被認為相對危害較小的拒絕服務(wù)漏洞,在區(qū)塊鏈網(wǎng)絡(luò)中則可能引發(fā)整個網(wǎng)絡(luò)癱瘓。2018年國內(nèi)安全公司360發(fā)現(xiàn)了 EOS節(jié)點的遠程執(zhí)行任意代碼,即可以通過遠程攻擊,直接控制和接管 EOS上運行的所有節(jié)點。因此針對區(qū)塊鏈合約執(zhí)行的安全研究尤為重要。
針對傳統(tǒng)灰盒測試對 WebAssembly二進制虛擬機進行漏洞挖掘中存在的問題,本文提出了新的針對 WebAssembly二進制虛擬機的模糊測試方案,同時基于該方案我們實現(xiàn)了漏洞挖掘系統(tǒng)WASMAFL。本章將先對該系統(tǒng)的總體設(shè)計進行介紹,再闡述每個組件的設(shè)計方案和實現(xiàn)細節(jié),以及各模塊之間如何在系統(tǒng)中協(xié)調(diào)工作,最終實現(xiàn)針對WebAssembly虛擬機的高效模糊測試。
本文針對傳統(tǒng)灰盒模糊測試中隨機變異帶來的低效問題,提出了分層變異算法,通過對段表的組合和指令的比特變異,來實現(xiàn)變異的隨機性。接著方案通過指令修正來保證文二進制文件的合法性,生成更有可能觸發(fā)程序中難以到達路徑的測試用例。最后方案在模糊測試的過程中引入了基于合法性的能量調(diào)度策略,根據(jù)種子的合法性來分配種子的執(zhí)行時間和變異次數(shù),保證優(yōu)秀的種子能得到更充分地測試。
WSAMAFL基于AFL進行拓展和修改,其中WASMAFL增加了三個組件,分別是WebAssembly段表組合變異模塊、指令變異模塊和指令合法性修正模塊,同時在對種子進行執(zhí)行時間分配時,我們引入了基于合法性的能量調(diào)度模塊??傮w架構(gòu)如下圖1所示。用于文件合法性檢查的指令修正模塊是獨立的,和模糊測試器解耦,這樣方便更靈活地增加其他規(guī)則,以及將算法應(yīng)用到其他虛擬機對象中。
標準的 WebAssembly模塊[13]是由一系列具有特定功能的段結(jié)構(gòu)組成的,段結(jié)構(gòu)中存放著用于描述模塊功能和屬性的信息,如圖2所示。同時模塊還定義了一系列用于存儲靜態(tài)資源的索引空間,索引空間內(nèi)的資源可以由模塊中定義的各類指令及相關(guān)段結(jié)構(gòu)來進行引用。
圖1 WASMAFL架構(gòu)
WebAssembly二進制遵守嚴格的格式,使用隨機變異方法的盲目模糊測試策略會導(dǎo)致大量無效的測試用例并且降低模糊測試效率。因此,為了使得生產(chǎn)的測試用例更有針對性,更有可能滿足程序?qū)?shù)據(jù)結(jié)構(gòu)和邏輯判斷的要求,我們提出了分層變異的策略,通過段表組合和指令變異相結(jié)合的方式,來改變虛擬機內(nèi)存中控制流和數(shù)據(jù)流的信息,從而對虛擬機進行更充分的測試。分層變異后生成的測試樣例具有高度結(jié)構(gòu)化的特征,不會使得程序在合法性檢查階段就退出測試。同時變異后的種子文件具有更加豐富的語義和隨機性,能夠測試到不符合邏輯的指令流程和數(shù)據(jù)處理,使得對虛擬機的測試更為充分和全面。
變異過程分為兩個部分,分別是對模塊的各個段表之間進行組合變異,以及對模塊代碼段的函數(shù)指令進行變異。模糊測試先進行模塊段表層的組合變異,再進行段表組合變異和代碼段指令變異相疊加的混合變異。
3.1.1 對模塊的各個段表之間進行組合變異
段表間的組合變異本質(zhì)上是通過WebAssembly的模塊結(jié)構(gòu)、數(shù)據(jù)格式等先驗知識,來指導(dǎo)并改善測試用例的生成。根據(jù)上一章對WebAssembly格式的介紹,我們知道WebAssembly模塊由多個段表組成,其中某些段表為模塊必須的段表,有且僅有一個,另一些段表則為非必須的段表,通常這些段表通常是虛擬機構(gòu)造內(nèi)存模型和上下文執(zhí)行環(huán)境的數(shù)據(jù)來源,通過對段表的組合變異,可以測試虛擬機是否按照標準進行實現(xiàn),同時可以檢測出段表在不同的上下文環(huán)境中,是否存在安全漏洞。這個階段的變異通過對段表進行合理組合,分別為刪除、添加、替換和篡改四類操作。
圖2 WebAssembly二進制段表組成示例
(1)段表刪除
刪除操作以段表為單位,從給定的種子文件中隨機選取一個段,只要該段不是僅有的代碼段則對其進行刪除。例如,隨機選擇模塊的Start段,標準規(guī)定在一個WebAssembly模塊中只能設(shè)置一個Start段,但是因為其不是僅有的代碼段,則對其刪除,即將 Start段對應(yīng)的字節(jié)部分進行移除,生成新的測試樣例。在段表的刪除操作中需要注意的是,由于要對虛擬機的指令處理邏輯進行深入的測試,因此需要保證 WebAssembly模塊具有實際的語義,所以我們需要保留至少一個代碼段,如果模塊中存在多個代碼段則可以對代碼段進行刪除。
圖3 段表刪除操作
(2)段表插入
同理,段表的插入也是以段為單位。對給定的種子文件s1,從其他種子文件中隨機選擇另一個種子文件s2,選取s2中的隨機段,將其插入到s1的模塊中,插入的位置不能破壞s1原有的段表結(jié)構(gòu),即只能插入在原有的任意段表之前或者之后。和段表刪除操作不同的是,插入的段表可以是代碼段。
圖4 段表插入操作
(3)段表替換
段表替換是段表層變異中相對復(fù)雜的操作。和段表插入的操作類似的,先選擇兩個種子文件s1和s2,接著從種子文件s2中選取任意的段表,替換種子文件 s1中對應(yīng)的段表,生成新的種子文件。需要注意的是,進行替換的段表必須是相同的段表,例如我們隨機選取了s2中的start段,想對s1中的start段進行替換,但是s1中不存在start段,那么我們則需要重新選擇s2中的其他段表,如果選擇的次數(shù)超過三次,則放棄此次的替換操作。和插入操作一樣,替換操作也不能破壞原有種子文件 s1的模塊段表結(jié)構(gòu)。
圖5 段表替換操作
(4)段表篡改
段表篡改是針對模塊的自定義代碼段,根據(jù)我們的觀察,虛擬機在對自定義段表的處理容易出現(xiàn)崩潰,因此在段表層的變異操作中,我們特地引入了段表的篡改。對于給定的種子文件s,從中任意選擇一個段表,將其段表的標識變?yōu)樽远x段表的標識。例如,對于種子文件s,我們將其type段的標識1變?yōu)?,從而該段就變成了自定義段。
圖6 段表篡改操作
段表層的變異是在保證模塊基本合法性的前提下,盡可能地豐富虛擬機在執(zhí)行模塊時的上下文環(huán)境。同時,變異過程也不完全遵守 WebAssembly的標準規(guī)定,因此能在模糊測試的過程中驗證虛擬機的實現(xiàn)規(guī)范。
3.1.2 對模塊代碼段的函數(shù)指令進行變異
段表層的重組變異可以改變虛擬機的內(nèi)存初始化狀態(tài)和程序上下文數(shù)據(jù),但是虛擬機主要的功能在于對代碼段的指令邏輯進行執(zhí)行。所以在完成段表層的重組后,我們單獨對模塊的代碼段進行變異。
WebAssembly模塊的代碼段由函數(shù)及其指令組成,指令類似于匯編指令,由操作碼和操作數(shù)組成。我們觀察到,在傳統(tǒng)模糊測試變異中,如果對指令的操作碼進行比特變異,會產(chǎn)生兩種結(jié)果:變異破壞了指令的合法性,即將指令變成了非法指令,當(dāng)虛擬機執(zhí)行到該非法指令會直接報錯退出。而如果將指令變異成了其他合法指令,虛擬機也會因為操作數(shù)中可能存在的零字節(jié)以及編碼解析等問題退出執(zhí)行,導(dǎo)致能夠連續(xù)正常解析的指令數(shù)較少。另一方面,從指令操作數(shù)變異的層面上來看,只有少數(shù)的變異是有意義的。例如,對于常量指令i32而言,后面跟著的常量的變化大部分可能無法改變程序執(zhí)行的分支,但是如果是常量的臨界值,則可能會導(dǎo)致虛擬機在處理數(shù)值時發(fā)生溢出。
綜上,為了保證代碼段變異的充分性,我們在代碼段使用比特的粒度進行變異,變異操作包括翻轉(zhuǎn)、替換、算術(shù)加減、隨機比特變換刪除、復(fù)制增加等AFL的變異操作。同時,為了減少非法指令造成的退出,我們通過指令修正的方式,保證虛擬機對指令進行完整的解析。
圖7 代碼段比特變異
上文提到對代碼段的比特層面的變異會導(dǎo)致虛擬機在遇到非法指令時退出,因此我們設(shè)計了一個優(yōu)化方案,再使用傳統(tǒng)的比特變異方法對代碼段數(shù)據(jù)進行變異后,再對指令進行修正。
指令修正的核心思想是將指令的非法操作碼進行NOP指令替換,將指令的非法操作數(shù)修改成最大臨界值。指令修正模塊對變異后的文件進行掃描,識別出變異導(dǎo)致的非法指令位置,根據(jù)該位置是指令操作碼還是操作數(shù)來進行相應(yīng)的操作。如果識別出是非法操作數(shù),則通過NOP指令進行替換,使得虛擬機能執(zhí)行后面的邏輯。WebAssembly的操作數(shù)通過有符號LEB128、無符號LEB128等進行編碼,如果識別出是操作數(shù),則根據(jù)操作碼對應(yīng)的操作數(shù)編碼類型,將操作數(shù)改為最大值。
圖8 指令合法性修正
指令修正能讓虛擬機正常解析的指令數(shù)變多,執(zhí)行的邏輯更多樣、更深入,因此,能夠提高模糊測試過程中的代碼覆蓋率。
模糊測試的過程中需要反復(fù)選擇種子進行變異,如何從語料庫中選擇有效的種子是模糊測試中的重要課題。通過良好的種子選擇策略,模糊器可以優(yōu)先考慮更有用的種子,包括覆蓋更多代碼并更有可能觸發(fā)漏洞,同時減少重復(fù)執(zhí)行同一路徑的浪費并節(jié)省計算資源。我們將為種子文件分配的執(zhí)行時間稱為種子的能量,能量調(diào)度策略決定了在模糊測試過程中為哪些種子分配更多的執(zhí)行時間和機會。
在 AFL中將能量分配給較小的種子,這樣可以提高執(zhí)行的速度。AFLfast[11]則將更多的能量分配給執(zhí)行低頻路徑的種子。本文提出了一種新的能量調(diào)度策略,基于文件變異的有效性來分配能量。如果對文件變異后的結(jié)果修正越少,那么說明文件變異的效果越好,并且種子修正所需要花費的時間也越低。因此,應(yīng)該分配更多的能量給這些種子。通常來說,我們會認為文件變異的有效性是一個布爾值,即變異是有有效的或者無效的。但是這里我們使用一個比例來衡量文件變異的有效性。我們將文件變異的有效性定義成修正操作的比例。
對于給定的種子s,基于變異有效性的能量調(diào)度prob(s)的分配如下:
其中,t是指令修正的次數(shù),當(dāng)指令的修正次數(shù)大于最大值MAX時,我們認為初始的變異造成的無效文件較多,將對其分配較低的能量,當(dāng)指令修正的次數(shù)小于最大值,則根據(jù)修正次數(shù)與最大值的差值和比例進行分配。
指令修正次數(shù)的最大值是通過實驗進行設(shè)置,是一個經(jīng)驗數(shù)值。同時,在模糊測試的初始階段,可以通過選項對其進行設(shè)置。我們收集了20個較為流行的合約文件進行測試,發(fā)現(xiàn)一次變異需要修正的次數(shù)超過50,則會顯著降低測試的速度。因此,本文選擇的最大修正次數(shù)為50。
根據(jù)本文的方案,我們在AFL的基礎(chǔ)上實現(xiàn)了WASMAFL,將工具與原版AFL_2.52進行對比,分別對EOS的Webassembly虛擬機進行了24個小時的模糊測試。我們對比了新方案和原有方案下發(fā)現(xiàn)路徑情況和產(chǎn)生的崩潰數(shù)量,從表2中我們的可以發(fā)現(xiàn),在路徑覆蓋率上,有了 35%的提升。在崩潰的產(chǎn)生數(shù)量上,WASMAFL比AFL多了6.17%。同時,我們對導(dǎo)致程序崩潰的樣本進行分析,根據(jù)樣本產(chǎn)生崩潰的位置和原理進行了分類,發(fā)現(xiàn)AFL只找到了1種段錯誤類型的崩潰,而WASMAFL工具則找到了2種段錯誤類型的崩潰。
表1 模糊測試執(zhí)行結(jié)果對比
本文的方案旨在引導(dǎo)程序向更深的路徑進行探索,因此表2對兩個工具的路徑深度和分支覆蓋率進行比較,發(fā)現(xiàn)路徑深度提高了兩層,同時分支覆蓋率也相應(yīng)地提高了34%。由于新的方案在執(zhí)行過程中引入了文件的結(jié)構(gòu)識別和合法性檢查,因此實驗對執(zhí)行速度進行了比較,發(fā)現(xiàn)執(zhí)行速度的降低在可接受范圍內(nèi)。
表2 模糊測試執(zhí)行效果對比
同時我們還對24小時內(nèi)總路徑數(shù)和路徑深度隨時間變化的曲線進行了繪制,從圖9可以看出WASMAFL能比AFL更快地到達更深的路徑,到達更深路徑后總路徑數(shù)的增長WASMAFL快于AFL。
圖9 執(zhí)行24小時總路徑變化曲線
本文通過對 WebAssembly虛擬機的模糊測試方案進行了設(shè)計,提出了分層變異算法,最后和通過工具AFL進行測試,通過24小時的對比驗證,與原AFL工具效果進行對比評估分析, 表明該方案能夠提升模糊測試的覆蓋率和崩潰發(fā)現(xiàn)數(shù)量。
本文提出了一種針 WebAssembly虛擬機的模糊測試方案。通過研究WebAssembly各模塊對執(zhí)行的影響,利用WebAssembly的文件格式構(gòu)造有效文件,對WebAssembly文件進行解析,再將各個模塊之間進行組合和修改,增加了在高級結(jié)構(gòu)而非比特層面的變異。同時,本方案還對WebAssembly的代碼段進行了深入的變異,通過改變初始化數(shù)據(jù)、打亂的合法指令序列來增加變異的多樣性,讓輸入能探索更多的路徑。同時,本方案還引入了一個基于有效性的能量調(diào)度方案,讓模糊測試在有效的種子上花費更多的時間,增加發(fā)現(xiàn)程序處理邏輯漏洞的概率。
基于本文的方案,實現(xiàn)了WASMAFL,是一個基于AFL的模糊測試工具,在其基礎(chǔ)上增加了 WebAssembly變異的策略和能量調(diào)度策略。在我們的評估中,將兩者進行了比較,評估結(jié)果表明,在給定的24小時內(nèi),WASMAFL可以比AFL發(fā)現(xiàn)更多的崩潰,還顯著地提高了路徑覆蓋率。