?

基于模糊測試的智能合約正確性檢測

2024-03-12 08:59王嘉誠蔣佳佳趙佳豪張玉書王良民
計算機工程與應用 2024年5期
關鍵詞:以太測試用例調用

王嘉誠,蔣佳佳,趙佳豪,張玉書,王良民

1.南京航空航天大學計算機科學與技術學院/人工智能學院/軟件學院,南京 211106

2.東南大學網絡空間安全學院,南京 211106

伴隨著區塊鏈技術[1]的飛速發展,其應用場景越來越廣泛,在生活中的普及程度也越來越高。目前,區塊鏈技術已經進入了一個新紀元。作為第二代區塊鏈技術的核心,智能合約[2]在區塊鏈平臺上發揮著日益重要的作用,區塊鏈平臺上的賬戶在智能合約的基礎上管理著價值越來越龐大的數字資產,也正因如此,黑客也開始將目光瞄準這一新興的技術領域。由于智能合約和區塊鏈技術的發展時間還較為有限,已經暴露的安全問題和潛在的安全隱患都對以太坊區塊鏈平臺上的資產管理造成了嚴重威脅。

智能合約本質上是一種通過區塊鏈部署并存儲在以太坊平臺上的具有特定功能的程序,因此上鏈數據不可篡改也成為智能合約所具備的特點之一,這就導致即使發現已部署的智能合約中存在影響其正確運行的漏洞,也很難對其進行修改。所以,在智能合約被部署之前就對其進行正確性檢測成為了亟待解決的問題。

近年來,隨著智能合約技術的日漸成熟以及愈加廣泛地應用區塊鏈平臺之上,越來越多的學者注意到隱藏在智能合約中的漏洞對于用戶以及區塊鏈平臺安全造成的威脅[3],他們開始探索各種類型的方法對智能合約中存在的安全漏洞進行分析、檢測?,F有的智能合約安全漏洞檢測技術[4]主要有五個類別:基于靜態分析的漏洞檢測技術、基于測試的漏洞檢測技術、基于機器學習的漏洞檢測技術、組合技術以及其他。

靜態分析[5-10]屬于較為傳統的漏洞檢測方式,其檢測合約中隱藏的安全漏洞的方法是在不執行程序的情況下對程序的靜態特征進行分析。符號執行技術通過抽象方式模擬執行程序并涵蓋程序的多個可能路徑。Luu 等人[11]在2016 年提出并構建了一種名為Oyente 的基于符號化執行的漏洞檢測工具,用以對智能合約中潛在的安全漏洞進行檢測分析,Oyente工具屬于目前符號分析領域較為領先的漏洞檢測工具,其可以檢測堆棧大小限制漏洞、事務順序依賴漏洞等4種類型的漏洞。形式化方法[12]使用數學和邏輯方法來描述和驗證智能合約的設計是否滿足其要求。Bartoletti 和Zunino[13]兩人在2018年提出了一種在不依賴可信任的中心的去中心化體系內,對涉及比特幣交易的合約進行監管的形式化驗證語言BitML,交易的參與者可以根據這種語言構建自己的交易并上鏈,從而執行智能合約。Tsankov等人[14]在2018 年提出了一種名為Securify 的以太坊智能合約自動化安全分析工具,其可以根據漏洞特征分析智能合約是否存在漏洞。Securify分析智能合約源代碼編譯后生成的字節碼。Securify首先根據智能合約的字節碼重構依賴圖,通過分析依賴圖得到智能合約的語義信息。然后Securify根據給定的特征分析智能合約是否符合或違反這些特征,結合從智能合約中獲得的語義信息,判斷是否存在漏洞。污點分析技術是一種用于跟蹤程序中不可信數據或私有數據在一定規則下產生的數據流的程序分析技術。Rodler 等人[15]在2019 年提出了一種使用動態污染跟蹤技術保護智能合約免受重入攻擊的工具,名為Sereum。當Sereum工作時,它的污染引擎通過動態污染跟蹤為預定義源生成的數據分配標簽。之后,攻擊檢測器可以通過觀察標記的數據如何影響程序的正常執行來識別程序執行的異常狀態。當Sereum確定當前程序中正在發生重入攻擊時,Sereum 將與EVM事務管理器連接,并終止正在進行的程序。

在基于測試的漏洞檢測技術[16-18]中,模糊測試技術[19-21]通過向目標程序提供大量意外輸入來暴露異常結果,從而發現程序漏洞。Liu 等人[22]在2018 年提出了Reguard,這是一種基于模糊測試的智能合約漏洞分析工具,其專門針對智能合約中包含的可重入性漏洞進行自動監測,這種工具是通過迭代的方式生成隨機的交易,通過執行這些交易來對智能合約進行模糊測試,并根據對交易執行過程的監控,動態地檢測合約中的可重入性漏洞。變異測試會對源程序中的某些語句進行修改,并結合測試用例觀察修改后程序的執行結果,從而發現錯誤。Li等人[23]在2019年提出了MuSC。MuSC首先將每個待測合約的源代碼轉換為抽象語法樹并在抽象語法樹中生成變異數據,然后變異數據轉換回源代碼文件進行編譯和執行,從而暴露智能合約的缺陷。MuSC作為首個應用于以太坊智能合約漏洞檢測的突變測試工具,實現了突變測試的基本功能,并能在一定程度上暴露合約中的漏洞。

機器學習[24-26]利用過去的數據或經驗,以計算機為工具,致力于實時模擬人類的學習。機器學習作為當前的熱點技術,也被越來越頻繁地應用于智能合約漏洞檢測領域。2018年,Tann等人[27]提出了首個應用于智能合約漏洞檢測的機器學習方法。該方法利用長短期記憶連續學習智能合約安全漏洞,將智能合約字節碼序列映射為矢量序列,作為長短期記憶模型的輸入,預測智能合約漏洞。

為了追求更好的漏洞檢測效果,彌補單一程序分析技術的局限性,組合技術(將多種類型的程序分析技術結合用于智能合約漏洞檢測)從2019 年開始受到業界研究人員的關注。2020 年,Ashouri[28]提出了一種將動態污染跟蹤技術與動態符號執行技術成功結合的智能合約漏洞檢測工具,名為Etherolic。該工具首先對由輸入數據組成的事務進行標記,并在執行期間使用動態污點跟蹤技術跟蹤事務的傳播。當其追蹤到受污染的交易后,會檢查其相關的敏感數據流,從而識別智能合約中的潛在漏洞。定位漏洞后,Etherolic會對智能合約進行動態符號執行,生成一系列試圖觸發智能合約漏洞的交易。最后,Etherolic根據受污染數據的跟蹤結果和易受攻擊代碼的觸發結果生成漏洞檢測報告。

除了上面提到的四類典型的智能合約漏洞檢測技術外,還有一些不太常見的漏洞檢測技術。例如代碼克隆檢測、攻擊向量檢測、在線檢測、入侵檢測、語義感知和氣體感知等。2018 年,Liu 等人[29]提出了一種新的語義感知安全審計技術,稱為S-gram。該審計技術將NGram 語言建模與輕量級靜態語義標記相結合,通過識別不規則的語義標記序列和優化現有的漏洞分析器來捕獲智能合約的高級語義,并預測潛在的漏洞。

本文以基于測試的智能合約漏洞檢測技術中的模糊測試技術為主要思路,在智能合約被正式部署之前對其進行動態漏洞檢測,判定其正確性。智能合約的正確性一般包括代碼正確性和運行正確性。作為一段計算機程序,智能合約的運行正確性在其編譯以及部署在區塊鏈平臺投入應用時會得到驗證,編譯不通過以及無法正常運行的智能合約皆不滿足其運行正確性。本文重點關注的是智能合約的代碼正確性,在某種程度上,代碼正確性會對運行正確性造成不可忽視的影響。與一般的計算機程序相同,影響智能合約代碼正確性的因素通常包括編程語法錯誤、邏輯錯誤等,這一系列問題導致了軟件漏洞的引入,使得智能合約無法實現預期的功能或被惡意用戶所利用,這都將造成實際的損失。本文著重關注針對七種具有區塊鏈特點的軟件漏洞時智能合約的正確性問題。

為實現模糊測試,本文構建了一個針對智能合約的內容以及規范生成模糊輸入的框架。該框架通過對智能合約的ABⅠ接口以及字節碼進行分析,根據智能合約所調用的函數的參數的不同類型生成不同的模糊輸入,并針對不同種類的漏洞構建測試樣例。向待測智能合約導入模糊輸入后,在執行測試樣例時通過以太坊虛擬機來監控智能合約的執行情況,通過對監控獲得的若干日志文件進行分析,實現對于智能合約漏洞的檢測。經測試,在416個部署在測試網上的智能合約中檢測出19個包含漏洞的不正確智能合約,對檢測結果進行人工分析后發現,檢測的準確率達到了94.7%。

1 區塊鏈、以太坊及智能合約簡介

區塊鏈是一個分布式的共享賬本,也是一個去中心化的數據庫,區塊鏈以分布式存儲的方式將比特幣交易的信息保存在各個區塊中,而每一個區塊所包含的數據又直接決定了其子區塊的生成,在生成新區塊時,需要共識機制來化解分叉問題,同時需要對信息的有效性進行驗證。作為支撐比特幣的底層技術之一,區塊鏈技術為價值轉移提供了新的思路和方法。然而,比特幣的功能較為單一,無法在區塊鏈網絡上實現較為復雜的應用,其實際應用價值受限。在區塊鏈技術的發展過程中,以太坊的出現很好地解決了這個問題,讓區塊鏈的商業應用成為可能。

以太坊(Ethereum)是一個去中心化的應用平臺,與比特幣等加密貨幣相同,以太坊同樣具備電子支付、數字資產轉移等功能。除此之外,任何用戶都可以在其上構建去中心化應用,并與其他應用程序進行交互。以太坊上構建的去中心化應用程序便是由智能合約構成的,智能合約管理著以太坊的許多關鍵功能、操作、用戶行為。以太坊支持兩類賬戶:實體用戶所有的賬戶以及智能合約賬戶。以太坊會在每一筆交易產生之后更新自己的狀態,其交易本質是在不同賬戶(智能合約賬戶和實體賬戶)之間發送虛擬貨幣或二進制數據,當接收方是智能合約賬戶時,將會把二進制數據作為智能合約的輸入數據,執行其代碼。

智能合約[30]是第二代區塊鏈核心技術,Nick Szabo在1995 首次提出了“智能合約(smart contract)”的概念,直到2013年以太坊區塊鏈平臺出現之后,智能合約的實體才真正誕生。智能合約其本質是由代碼組成的程序,也可以理解為是由代碼定義的交易規范、準則。智能合約的執行需要達成某些特定的條件或是發生特定的行為事件,其本身具有自己的狀態,并且是以區塊鏈平臺(如以太坊)為載體存在的。結合區塊鏈不可篡改的特點,智能合約一經部署便不容易被惡意攻擊者篡改。當智能合約被部署在區塊鏈平臺之后,智能合約自身的狀態會和區塊鏈的狀態建立起非常緊密的聯系,這樣一來,智能合約的執行將變得非常高效。

然而,由于智能合約在執行時有可能會涉及到多個不同智能合約之間的協作交互,如果編寫智能合約的工作人員未能清晰地掌握智能合約與區塊鏈平臺的關系以及智能合約之間的潛在關系,那么開發出的合約就有可能存在安全漏洞。除此之外,因為智能合約和區塊鏈均是近幾年新興的技術,編寫智能合約的編程語言以及運行智能合約的區塊鏈平臺對于大部分開發者來說接觸時間并不長,加之開發工具本身也并不夠完善,這就導致開發人員在開發的過程中容易遇到困難和問題,編寫出的智能合約極易存在漏洞。這些漏洞都將影響智能合約的正確執行,從而對區塊鏈平臺的安全穩定造成威脅。

總的來說,區塊鏈技術作為一項具有重要意義的新興技術,其快速發展的過程同樣也是不斷拓展、打破固有思維、消除技術局限性的過程。從比特幣、區塊鏈到以太坊、智能合約,從區塊鏈1.0時代到2.0時代,區塊鏈技術得到了越來越廣泛的應用,實際應用的推廣又進一步推動了技術的發展。發展越是迅猛,安全則越是關鍵,作為當前技術核心部分的智能合約安全問題則越應受到重視。本文工作即是在以智能合約為核心的二代區塊鏈技術飛速發展的背景下,以模糊測試為主要技術手段,對以太坊智能合約進行漏洞檢測,從而對其正確性做出判斷。

2 智能合約安全漏洞

本章將對本文中涉及的7 種類型的智能合約漏洞進行介紹。

2.1 不消耗gas的send(Gasless Send)漏洞

不消耗gas 的send 漏洞的產生是基于一種特殊情況:當使用send()函數(相當于一個特殊的call())發送以太幣到一個合約時,簽名如果匹配不到任何的函數時,將會觸發回退函數(fallback())。由于send()函數指定了一個空函數簽名,所以當fallback()函數存在時,send()函數將總是會調用回退函數。但和一般的函數不同的是,執行send()所消耗的gas 默認上限是2 300(如果特別指定上限的話,可以大于2 300),因此,如果接收方合約在交易時觸發的fallback()函數需要的gas超過其默認上限,以太幣的發送方將會遇到一個名為“out-of-gas”的異常。如果這種異常沒有被適當地檢查并做出提醒,那么惡意的發送者可能會使以太幣的發送出現錯誤。

2.2 異常無序(exception disorder)漏洞

異常無序漏洞是一種由于不同合約對于異常處理的穩定性不一致所導致的漏洞。異常無序漏洞通常在不同合約彼此調用時發生。當一個合約調用另一個合約的函數時,調用行為可能會因為不同類型的異常而失敗,當這種異常發生時,處理異常的機制是由合約之間彼此調用的方式確定的。在一個嵌套調用鏈中,每個調用都是對智能合約中的函數的直接調用,當異常發生時,所有的交易(包括以太幣的發送)都會被還原。然而,如果這種異常發生在嵌套調用鏈中就會產生問題,因為在嵌套調用鏈中,總是存在一個調用address.call()、address.DelegateCall()、address.send()等函數的調用行為,交易行為的恢復在調用函數處便會停止并返回false,而交易行為對更深層次的調用產生的影響將不會被恢復,拋出的異常也不會傳播。異常處理方面的這種不一致性將使調用合約無法獲知執行過程中出現的錯誤。

2.3 可重入性(reentrancy)漏洞

導致可重入性漏洞的原因:有些函數在設計之初并不允許對其進行重入操作,然而,一些惡意代碼故意用可重入的方式調用這些函數,例如通過fallback()函數進行調用,這與fallback()函數本身的性質有關。一個智能合約如果沒有定義fallback()函數,它在進行以太幣交易的時候會拋出異常,會導致以太幣無法發送或者退還。于是便給一些不懷好意的攻擊者提供了可乘之機。通過fallback()函數調用一些不允許重入的函數可能會導致以太幣重復支付的問題出現,從而丟失以太幣。著名的Dao[31]攻擊便是通過這個方式造成了當時價值六千萬美元的以太幣丟失。

2.4 時間戳依賴(timestamp dependency)漏洞

很多智能合約的執行邏輯是和當前區塊的時間戳有關的,在執行一些類似于發送以太幣的關鍵操作時,如果區塊的時間戳是觸發該關鍵操作的條件的一部分,又或是智能合約的代碼獲取時間戳作為產生隨機數的依據變量,就可能會導致合約中存在時間戳依賴漏洞。在區塊鏈這樣的分布式系統中,礦工不僅可以決定一個新開采出的區塊的時間戳,還可以在900 s 的內自行設置區塊的時間戳。如果智能合約在傳輸以太幣時用到了區塊的時間戳或時間戳相關的數據,那么可能會存在惡意礦工通過操縱區塊的時間戳獲取不正當收益。

2.5 區塊號依賴(block number dependency)漏洞

區塊號依賴漏洞的作用原理與時間戳依賴漏洞類似,當智能合約使用區塊號作為觸發某些重要步驟的條件的組成部分時或作為生成隨機數的依據時,就會造成區塊號依賴漏洞。其本質還是因為區塊的區塊號可以被礦工所操作,如果智能合約基于區塊的區塊號進行交易,攻擊者就可以通過操縱區塊的區塊號來利用該漏洞。即使不直接使用區塊號,將區塊號作為某些隨機數生成器的參數用以生成隨機數,其結果仍然是脆弱的。

2.6 危險的DelegateCall(dangerous Delegate-Call)漏洞

DelegateCall()是以太坊智能合約中較為常見的一種用來實現函數調用的函數,其功能與call()函數較為類似,這二者之間的區別也正是該漏洞產生的原因,call()函數在進行函數調用時,被調用函數的代碼是在被調用方本身合約內運行的,但是DelegateCall()調用的目標函數的代碼是在DelegateCall()所在的智能合約內運行的,這樣的區別便造成了一定的安全隱患。如果DelegateCall()調用的目標函數來自于一個惡意的合約賬戶,該函數內包含一些危險的操作,當該目標函數在調用者智能合約中運行的時候,將有可能給調用者造成損失。

2.7 凍結以太(freezing Ether)漏洞

存在一些智能合約,其功能是接收以太幣,并將收到的以太幣轉賬給其他地址,起到以太幣中轉的作用。但這些合約本身并不包含發送以太幣的函數,無法自行實現轉賬功能,而只能通過DelegateCall()調用一些其他智能合約中的發送以太幣的函數從而實現轉賬功能。當這些提供以太傳輸代碼的合約執行自毀操作時,調用了這些合約中的轉賬函數的合約將無法發送以太幣,智能合約賬戶所管理的所有以太幣都將被凍結。由于Parity Wallet 漏洞而被第二次攻擊的原因便是許多Wallet 合約只能依賴Parity Library 來完成對以太幣的操作,然而,當Parity Library被初始化為智能合約,然后被黑客殺死后。依賴Parity Wallet 進行以太幣操作的所有Wallet合約管理的以太幣都被凍結了。

3 基于模糊測試的安全漏洞檢測

本章分為測試用例的構建和模糊測試兩個部分,第一部分分別對七種類型的智能合約安全漏洞的測試用例的構建規則進行了描述(測試用例在漏洞檢測中的意義是:以太坊虛擬機在監控智能合約執行的過程中會收集一些信息,通過這些信息和測試用例的對照來判斷智能合約中是否包含該測試用例對應類型的漏洞);第二部分針對以太坊智能合約面臨的安全問題,根據3.1 節描述的測試用例構建方法,本文提出了一種基于模糊測試的漏洞檢測方案,對模糊測試的主要功能模塊設計思路以及漏洞檢測時的流程進行了講解。

3.1 測試用例的構建

3.1.1 不消耗gas的send漏洞的測試用例

在以太坊虛擬機中,對于send()函數的定義其實是一種特殊類型的call()函數。于是,構建出的不消耗gas的send 的測試用例要確保以太坊虛擬機中的調用確實是send()調用,并且測試用例需要發現send()調用在執行期間返回了ErrOutOfGas的錯誤信息。

為了檢查以太坊虛擬機中的調用是否為send(),需要對調用的輸入是否為0 以及調用的gas 限制是否為2 300進行驗證。

3.1.2 異常無序漏洞的測試用例

對于異常無序的測試用例的構建原則是:對于一個嵌套調用鏈(或DelegateCalls()),其總是會起源于一個根調用(或DelegateCall()),在這個嵌套調用鏈(或DelegateCalls())中,如果至少有一個嵌套調用返回了異常,但根調用卻并沒有返回異常,這樣的情況說明異常沒有在嵌套調用鏈中正確地傳播回到根調用,于是認定該嵌套調用鏈包含異常無序的漏洞。

3.1.3 可重入性漏洞的測試用例

可重入性的測試用例是基于兩個子用例定義的:第一個子用例是ReCallTest,用于檢測在以調用Call()為根調用的調用鏈中,函數調用Call()是否不止一次地出現在這個調用鏈中;第二個子用例是AgentCallTest,其需要對三個條件進行檢查:條件一:用于傳輸的以太幣的數量(call()調用值)大于0;條件二:被調用的函數有足夠的gas來支付執行復雜代碼時的費用;條件三:調用call()的是本文提出的漏洞檢測工具所提供的代理合約,而不是測試中待測智能合約所指定的賬戶。

基于兩個子用例構建可重入性的測試用例的具體形式如式(1):

在具體情境中,可重入性漏洞的表現為:當一個函數調用既是某個調用鏈的根調用,又是該調用鏈的結尾調用,也就是該調用經過一串調用之后又回到其自身,并且該調用儲備了充足的gas,該調用通過call()函數向測試框架所提供的代理合約發送了以太幣。例如代理合約是通過對fallback函數的重復調用來體現它的可重入性的,當智能合約的執行觸發了測試用例時,說明其存在遭受重入攻擊的可能性,便會將該智能合約標記為存在可重入性漏洞的脆弱智能合約。

3.1.4 時間戳依賴漏洞的測試用例時間戳依賴的測試用例是由三個子用例組成的。

三個子用例都是布爾型變量。第一個子用例是TimeStampBool,它代表的是當前待測的智能合約在執行期間是否調用了時間戳的操作碼,如果調用,可以初步認定該智能合約的某些操作中用到了時間戳。第二個子用例是SendBool,它代表智能合約中是否包含發送以太幣到其他智能合約賬戶的send()調用。第三個子用例是EtherBool,它代表發送以太幣的數量是否大于0。

這三個子用例通過一種特定的關系組合之后獲得針對時間戳依賴漏洞的測試用例,該種關系如式(2):

判斷某一智能合約是否存在時間戳依賴漏洞的方法:待測智能合約使用了區塊的時間戳,并且在智能合約的執行期間進行了以太幣的交易。

3.1.5 區塊號依賴漏洞的測試用例

區塊號依賴的測試用例類似于時間戳依賴,與時間戳依賴不同的是,區塊號依賴的測試用例主要檢查的是智能合約在執行期間是否調用了區塊號的操作碼,而不是區塊的時間戳的操作碼。同樣,區塊號依賴的測試用例也是由三個子用例組成的。第一個子用例是BlockNumberBool,它代表的是當前待測的智能合約在執行期間是否調用了區塊號的操作碼,其他兩個子用例與時間戳依賴的兩個子用例相同,分別是SendBool 和EtherBool。

區塊號依賴的測試用例是其三個子用例安裝和時間戳依賴相同的方式組合的,其具體表達為式(3):

對于是否存在區塊號依賴漏洞的判斷原則即為:當前待測智能合約使用了區塊的區塊號,并且在智能合約的執行期間進行了以太幣的傳輸。

3.1.6 危險的DelegateCall漏洞的測試用例

危險的DelegateCall 的測試用例會對當前執行的智能合約是否包含至少一個DelegateCall()函數以及DelegateCall()調用的函數是否是從初始調用的智能合約的輸入中獲得的??偟膩碚f就是測試用例會檢查被測試的智能合約是否調用了一個DelegateCall(),該DelegateCall()的目標函數是由潛在攻擊者所提供的。

3.1.7 凍結以太漏洞的測試用例

凍結以太的測試用例檢測的是一個智能合約在本身沒有transfer()、send()、call()、suicide()等函數的相關代碼來將以太幣發送到其他賬戶地址的情況下,是否可以接收以太幣以及是否在執行的過程中使用了DelegateCall()函數。換一種方式來描述就是,如果一個智能合約在執行期間其賬戶余額大于0,但該智能合約無法自行實現發送以太幣的功能,而是需要通過DelegateCall()調用其他智能合約中的可以實現以太幣轉賬功能的函數,那么凍結以太的測試用例就會將該合約標記為有可能存在凍結以太漏洞的脆弱合約。

3.2 模糊測試

3.2.1 模糊測試概述

模糊測試主要包含兩個部分,其一是一個離線的以太坊虛擬機插樁工具,其二是一個在線的模糊測試工具,本文將著重就模糊檢測工具進行介紹。離線的以太坊虛擬機插樁工具通過對以太坊虛擬機進行插樁,使線上的模糊測試工具能夠對智能合約的執行進行監控,分析執行日志文件用于漏洞分析;模糊測試工具通過對智能合約的代碼進行分析,生成模糊輸入,并根據漏洞的特征定義針對該種漏洞的測試用例,通過提取執行日志文件中的關鍵信息與測試用例進行比較,從而判斷智能合約中是否包含該種類型的漏洞。該模糊測試工具的工作流程如圖1所示。

圖1 基于模糊測試的漏洞檢測概覽圖Fig.1 Overview of vulnerability detection based on fuzzing

在正式進行本文所涉及的工作之前,先通過網絡爬蟲的方式從Etherscan網站上爬取了一些已經部署在以太坊平臺上的智能合約,爬取的內容包括智能合約創建的代碼、ABⅠ接口以及這些智能合約的構造函數參數。在本文所涉及的工作中,已將爬取的智能合約重新部署在自行搭建的以太坊測試網絡中。一方面是將這些智能合約作為模糊測試的對象,另一方面是將這些智能合約作為使用合約地址作為參數的智能合約調用的輸入。

漏洞檢測的過程主要包含以下幾個步驟:

(1)ABⅠ及字節碼分析。對待測的智能合約的ABⅠ接口以及字節碼進行分析,需要對ABⅠ函數的每一個參數的數據類型和ABⅠ函數中所使用到的所有函數的函數簽名進行提取。

(2)映射關系建立。對從以太坊平臺上爬取下來的所有待測或是待引用地址的智能合約進行ABⅠ簽名分析,之后需要建立起智能合約和函數簽名的一個映射關系,即根據不同智能合約所包含的不同函數簽名進行索引。

(3)生成模糊輸入。在這一步模糊測試框架需要根據第一步和第二步的分析結果,根據待測智能合約的ABⅠ規范,生成有效的模糊測試輸入以及并未嚴格按照ABⅠ規范生成的異常輸入。

(4)啟動模糊測試。以隨機函數調用的方式將第三步生成的模糊測試輸入以及異常輸入并發送給相應的ABⅠ接口,智能合約進行執行。

(5)結果輸出及分析。以太坊虛擬機對于模糊測試過程中智能合約的執行情況進行監控,并生成若干執行日志,通過對這些執行日志進行分析,實現智能合約的漏洞檢測和正確性分析。

當所有待測智能合約都完成了模糊測試時,整個模糊測試的過程結束。

3.2.2 模糊測試核心步驟

(1)對待測智能合約進行靜態分析

模糊測試框架對待測的智能合約進行靜態分析,并提取待測的智能合約的公共函數的函數簽名。從細節出發進行描述:將每個待測的智能合約的合約文件加上.abi 后綴,導出JSON 格式的ABⅠ,并提取出ABⅠ中聲明的所有函數簽名,再計算每一個函數簽名的前四字節的哈希值(此處哈希的方法是SHA-3)作為其函數選擇器,保證不同的函數簽名對應不同的函數選擇器。最后構建出了一個以函數選擇器為鍵,以包含所有該函數選擇器的智能合約的地址向量為值的鍵值對映射。

接下來將具體介紹模糊測試過程中對智能合約的靜態分析。工具通過分析JSON格式的智能合約ABⅠ接口,提取智能合約中每個函數的參數的參數類型以及關于函數的描述,大多數數據類型模糊的輸入域是可以確定的,但地址數據類型與其他數據類型不同。在模糊測試框架中,地址數據類型的參數不能隨機產生,其具體指代的是外部賬戶和智能合約賬戶的地址。當智能合約的地址作為實參被提供給智能合約中包含的函數的時候,函數接收到地址數據類型的參數輸入后便會調用call()函數和收到的地址參數對應的智能合約建立聯系,進行交互。所以,模糊測試框架必須要使用智能合約的地址來作為帶有地址數據類型的參數的ABⅠ函數的輸入。

算法1智能合約靜態分析算法

在對待測智能合約進行模糊測試時,需要對智能合約的ABⅠ函數簽名進行提取,并確定函數簽名與智能合約之間的映射關系。當具體給出一個智能合約的ABⅠ函數時,需要確定所有待測智能合約中,哪些可以與這個ABⅠ函數進行交互,也就是說哪些智能合約中還包含了該ABⅠ函數。該確定過程需要調用一個非常重要的函數call,call函數的參數的前四字節對應了模糊測試框架為每一個ABⅠ函數計算的函數選擇器(函數簽名前四字節的SHA-3哈希)。

算法1 將待檢測的二進制形式的智能合約作為輸入,輸出智能合約的每個ABⅠ函數到智能合約代碼中使用的函數選擇器集合的映射。首先,算法使用了以太坊虛擬機自帶的反匯編工具將智能合約的二進制代碼反匯編為匯編代碼。接下來,算法會對已經轉為匯編代碼形式的智能合約中的公共ABⅠ函數進行提取,生成一個函數集合,該集合中存放的就是所有提取出的公共ABⅠ函數。之后算法會通過循環結構對上一步生成的函數集合中的每一個ABⅠ函數進行遍歷,在遍歷的過程中將會獲得該函數用到的函數選擇器,并生成一個函數選擇器集合。該循環結構在對每個ABⅠ函數進行遍歷的時候,首先會獲取其函數體,并通過函數體來獲取代碼段部分,并在每一次循環時為每一個ABⅠ函數創建一個函數選擇器集合。在該循環結構中還嵌套了兩層循環,二層循環是對代碼段中的每一段進行遍歷,三層循環是對每一段中的每一行進行遍歷,通過每一段的第一行匯編代碼內容來判斷該段內容是否包含要提取的函數選擇器,如果是,就將函數選擇器分離出來并添加到函數選擇器集合中。在對每一段進行遍歷之后,函數選擇器集合中可能有不止一個函數選擇器,也可能一個都沒有,于是先對函數選擇器是否為空進行判斷,如果不為空,就將該集合與本輪遍歷的ABⅠ函數建立映射關系。當所有ABⅠ函數遍歷結束后,每一個ABⅠ函數都將建立和它對應的函數選擇器集合的映射關系。該算法需要對每一個待測的智能合約執行。

根據該部分第一自然段可知,在本模塊功能中除了建立了ABⅠ函數和函數選擇器的映射關系以外,還建立了函數選擇器和支持該函數選擇器對應的函數的智能合約的地址向量的鍵值對關系。根據這兩對關系,不難再建立起ABⅠ函數和ABⅠ函數包含的函數選擇器對應的函數所支持的智能合約的關系。于是就根據ABⅠ函數找到所有相應的智能合約,并將它們存放在一個集合之中,再根據ABⅠ函數和智能合約建立起的關系,通過智能合約找到其包含的所有ABⅠ函數,對這些ABⅠ函數進行模糊處理,針對其不同的類型的參數生成不同的模糊輸入。在前文提到了關于地址類型輸入的問題,如果隨機生成地址數據類型的輸入,無意義的地址會導致無法在智能合約之間建立聯系,所以地址數據類型的參數應該選用智能合約對應的地址。

(2)產生模糊輸入

在整個模糊測試框架中,生成模糊輸入是非常關鍵的一個步驟,也是工具實現以模糊測試為基本思路來檢測智能合約中的安全漏洞的技術核心,是“模糊”最直接也是最真實的體現。

首先需要明確的是對什么內容進行模糊處理,生成模糊輸入。模糊測試框架是對待測智能合約中所包含的函數的參數進行模糊處理,生成模糊化的參數作為函數的輸入,并且不同類型的參數會對應不同的模糊處理方式。本文主要采用的模糊處理方法是先獲取該函數的所有參數,將其存放在一個集合當中,然后對這個集合中的每一個參數進行遍歷,首先對它的類型進行判斷,然后再根據參數類型確定不同的模糊處理方式,按照選定的方式為每一個參數生成一個隨機的候選值集合,以備為函數提供多次不同的模糊輸入,進行漏洞檢測。該候選值集合所包含的模糊化參數個數也是根據參數的不同類型在不同的區間范圍內隨機生成的。

本文采用的參數類型劃分方法是按照參數長度來劃分不同類型的參數,將函數的所有參數劃分為定長參數和不定長參數兩個類型。對于定長參數,只需要按照參數的長度,調用相應生成隨機數的函數,產生模糊輸入集合即可;對于不定長的參數,例如字符串等類型的參數,首先需要隨機生成一個數據作為參數的長度,然后按照隨機生成的長度再隨機生成其參數的具體數據內容。這樣的方式可以提高輸入的模糊程度,最大程度上覆蓋有可能的所有輸入。

對于每個函數參數的候選值集合,其候選值并非全部由隨機函數按照一定的條件生成,最終的候選值集合由兩個部分所組成,一部分是模糊輸入,另一部分是在對函數進行靜態程序分析的時候確定的該參數常用的一些數據。

在對于智能合約進行模糊測試時,需進行多次測試,次數不固定。在對待測智能合約集合中的每個智能合約進行測試之前會先生成一個確定范圍內的隨機數作為其模糊測試的次數,以此來達到同時保證測試效果以及測試效率的目的。接著會對該合約循環執行隨機次數的模糊測試,在每次模糊測試時,還會在該智能合約包含的所有函數中隨機選擇一個函數進行模糊測試,從其參數的候選值集合中隨機選擇作為函數的模糊輸入。本文提及的七種智能合約安全漏洞中的大多數漏洞都可以按照常規的針對函數的參數生成模糊輸入,然后將模糊輸入作為參數傳遞給函數,執行智能合約這樣的方式進行漏洞檢測。但這樣的方式并不適合可重入性漏洞,或者可以說并不適合所有涉及到不止一個智能合約之間的相互聯系的漏洞類型。于是,為了解決這一問題,需要針對可重入性漏洞,根據其漏洞的原理,結合某些智能合約本身的結構特點,設計一個可能觸發可重入性漏洞的攻擊場景,以此來標記合約中的可重入性漏洞。

(3)收集測試樣本

上一部分介紹的模糊輸入為整個測試框架提供了輸入,輸入之后進行模糊測試,模糊測試的本質即在輸入了模糊化參數之后,執行待測智能合約。在智能合約的執行過程中,需要提取一些關鍵信息來構建出本文第三章提到的針對不同安全漏洞類型的測試用例,對這些測試用例進行分析,以此來判斷正在執行的智能合約中是否包含某種安全漏洞。

通過觀察智能合約的函數調用情況可以發現,智能合約中非常多的規則的定義、交易行為的規定都和call()函數有關,有的會直接使用call()函數,同時send()和DelegateCall()函數也占據了相當的函數調用比例。原因其實也很簡單,這幾種函數都可以實現不同賬戶之間的交易轉賬,而對于智能合約來說,其本身就包含了很多關于交易、轉賬的行為定義以及相關規則。前文中提到過send()函數其實是一種特殊的call()函數,二者實現了相同的功能,區別是send()函數對gas 的最大支付值有限制(限制為2 300),而call()函數對gas 沒有限制;call()函數和DelegateCall()函數的功能也十分類似,二者的主要功能是通過調用其他合約的代碼,或是函數來實現轉賬、交易等行為。區別之處在于當他們在調用其他合約的函數時,程序的運行位置是不同的,當一個合約中的call()函數在調用其他合約的函數時,是在call()函數調用的函數所在的合約中運行的,當DelegateCall()函數調用其他函數時,代碼是在DelegateCall()函數本身所在的合約中運行的。由此可知,智能合約中call()函數相關的數據對于分析智能合約執行過程中的交易行為有無異常非常重要。于是便對智能合約中call()函數的一些指標進行了提取,列舉在此:發起調用的智能合約賬戶地址、當前智能合約內的函數、被調用的函數所在的智能合約賬戶地址、被調用的函數名、被調用的函數的輸入參數、傳輸的以太幣的數量、調用行為所需花費的gas、當前調用中用到的操作碼。

操作碼是這些指標中非常重要的一項,當在構建關于時間戳依賴漏洞和區塊號依賴漏洞的測試用例時,將會直接對于智能合約是否包含區塊時間戳和區塊號的操作碼進行檢查;除此之外,在前文提到的判斷智能合約中的ABⅠ函數的每段代碼是否包含函數選擇器時也用到了操作碼,其判斷方法是每個代碼段的第一行是否是操作碼PUSH4,PUSH4 的含義是將前四字節的數據放入堆棧中(以太坊虛擬機是堆棧虛擬機的一種),與之對應的是函數選擇器是由函數簽名的前四字節經過SHA-3 哈希后得到的。操作碼不僅被直接用在某些測試用例中的,作為支撐起以太坊虛擬機執行指令的重要部分,部分操作碼在執行的過程中還會對智能合約的狀態產生影響。所以,對操作碼相關信息的分析對于安全漏洞檢測有著顯著的意義。

(4)日志分析與漏洞檢測

日志分析與漏洞檢測模塊通過調用go-ethereum庫(https://geth.ethereum.org)的以太坊虛擬機插樁工具對智能合約的執行過程進行監控,在監控的過程中插樁工具會將能夠反饋智能合約執行情況的信息以執行日志文件的形式輸出。在對相關日志文件進行分析時,該模塊會提取日志文件中反映交易相關行為(轉賬、賬戶地址等)以及調用信息(Call()、Callnode()、DelegateCall()等)的內容,并將提取的信息記錄在棧中。

在日志分析與漏洞檢測模塊中,棧是核心數據結構,發揮著非常重要的作用。該模塊會將交易的發起者、交易的接收者、轉賬的以太幣數量、耗費的gas、賬戶余額、以太幣存儲狀態等反映智能合約狀態以及區塊鏈狀態的信息存入棧中。當棧的長度達到一定數值(本文工作設置的閾值為1)時,分析模塊便會利用存儲在棧中的信息,調用對應的功能函數,結合針對特定類型漏洞構建的測試用例進行檢查和判定。對棧中的信息分析完成后便清空棧,之后繼續將新提取的信息記錄在棧中進行分析,重復以上過程直到當前所有候選待測智能合約執行完畢且全部交易執行完畢。

在分別針對每種類型漏洞進行檢測時,會對該類型漏洞的所有候選智能合約執行上述分析過程,逐一檢測判定這些智能合約中是否包含相應類型的漏洞,并將經檢測可能存在對應漏洞的智能合約名稱匯總在一個名單列表文件中,該文件即為漏洞檢測的結果,該文件中包含的智能合約即為不滿足正確性的智能合約,包含任一類型或若干類型漏洞的智能合約均不滿足其正確性。候選智能合約集合中未出現在檢測結果名單的智能合約即為針對該種漏洞類型滿足正確性的智能合約。

4 漏洞檢測實驗

本章對于使用本文提出的模糊測試框架對智能合約進行漏洞檢測的實驗過程進行了具體的闡述。在搭建好實驗平臺、配置好實驗環境之后,將該模糊測試框架部署在以太坊虛擬機中,將416個待檢測的智能合約部署在測試網上。針對7種類型的漏洞,對合約進行漏洞檢測,檢測出19個存在漏洞的不正確智能合約,經人工分析驗證,其中18個檢測結果正確。

4.1 實驗環境/實驗設置

在進行智能合約漏洞檢測的實驗部分時,選用的實驗環境是在本機上安裝的Linux虛擬機,虛擬機系統選用的CentOS-7-x86_64,分配內存為4 GB,部署4核處理器,硬盤分區40 GB。本機配備Ⅰntel?CoreTMi5-6200 CPU,已安裝內存(RAM)8 GB。

搭建實驗環境的過程主要分為安裝CentOS7 虛擬機以及在虛擬機中安裝docker 應用容器引擎兩個主要步驟,安裝虛擬機時需要注意的是一定要分配足夠的內存,原因是需要在虛擬機中搭建一個以太坊虛擬機平臺和一個測試網,并且要在以太坊虛擬機中部署上百個智能合約,如果分配的內存不夠會導致實驗無法正常進行,工具載入到某一步耗盡內存之后便會拋出異常。對于docker 的安裝,采用了自動執行的腳本命令,選用的是阿里云的鏡像。

由于在整個實驗中關注的只是智能合約包含安全漏洞的情況,于是在整個測試網中只設置一個對等節點。Docker應用容器引擎成功安裝后,在其中部署以太坊虛擬機平臺,并且在docker中安裝用于測試的geth客戶端并創建一條只包含一個節點的私有鏈。由于模糊測試框架的主體部分是基于go 語言編寫的,該語言與Java 有很多的相似之處,并且關于測試部分是以一個JavaScript項目架構的,于是選擇了web3.js(以太坊虛擬機兼容的JavaScript 應用程序接口)與docker 中的geth客戶端建立聯系。因為創建私有鏈的原因并不是為了實現真實的以太幣交易,而是對部署在測試網的四百余個智能合約進行漏洞檢測,所以私有鏈中對于新區塊的開采的虛擬過程設計較為簡單,以降低實驗復雜度并提高實驗效率,從而獲得較為理想的實驗結果。

4.2 爬取智能合約相關信息

實驗部分涉及的待檢測智能合約通過Python 爬蟲程序從Ethersca網站(https://etherscan.io/)爬取。Etherscan是瀏覽以太坊區塊鏈平臺上所有公共數據的安全工具,可以通過Etherscan 瀏覽的數據包括交易轉賬數據、錢包地址、智能合約等。Etherscan 網站支持查看智能合約、驗證智能合約、與智能合約進行必要的交互等操作。智能合約能夠被公開查看是Etherscan網站的優勢之一,也滿足了本文工作的相應需求。

由于Etherscan 網站并沒有較為完善的反爬蟲機制,網站上的智能合約信息也相對固定,于是在爬蟲程序的編寫部分只要采用較為基礎的靜態爬取方法即可實現。在爬取過程中,獲取的信息主要包括智能合約的源代碼(存入.sol文件中)、智能合約的ABⅠ(存入.abi文件中)、智能合約的二進制代碼(存入.bin文件中)、智能合約的構造函數參數(存入.txt文件中)等。

然而,并非所有獲取的合約都將部署在測試網上進行漏洞檢測。首先,獲取的智能合約全部是帶有源代碼的合約,本文所采用的漏洞檢測方法是以提取并分析處理智能合約代碼中的指定信息為基礎的,雖然模糊測試框架對于智能合約的分析主要是針對于字節碼的(智能合約以字節碼的形式被部署在以太坊平臺上),但在手工對漏洞檢測的結果進行審計驗證時,需要對智能合約的源代碼,即高級編程語言進行分析,所以,獲取智能合約的源代碼對于實驗的正常進行有著非常重要的作用。其次,如果獲取的智能合約中涉及到其他賬戶或智能合約地址的調用,那么該地址需是有效地址,這樣才能保證部署在測試網上的智能合約可以和其他合約建立正常的交互關系。

4.3 實驗過程

實驗的具體過程嚴格遵循了測試框架進行模糊測試、漏洞檢測的步驟,實驗的具體細節描述如下:

本文采用的方法是以不同類型的漏洞為檢測基準,先選定即將投入檢測的漏洞類型,然后針對該種漏洞,對部署在測試網上的所有智能合約一一進行檢測(提取相關內容并針對該種類型漏洞的測試用例進行分析),檢測的內容即該合約中是否存在選定類型的漏洞。最后針對該種類型的漏洞生成一個檢測結果文件,即被測的智能合約中有哪些合約包含該類型漏洞,檢測結果中將這些合約的名稱列出。該種方法相比于前一種方法最明顯的改善是去除了很多冗余的檢測。最后達到的檢測效果便是每一種類型的漏洞對應一個合約名稱列表,該列表中包含的便是對所有待測合約進行檢測后得到的存在該種類型漏洞的智能合約。這樣的方式將會明顯提高漏洞檢測的效率,獲得的檢測結果也更加直觀。

對于待測智能合約的靜態分析是整個漏洞檢測過程的開始,同時也是支撐整個檢測過程的最基本的步驟。模糊測試框架主要是對待測智能合約的ABⅠ接口以及字節碼進行分析,在分析的過程中建立智能合約和ABⅠ函數、ABⅠ函數和其調用的函數兩對映射關系(分析過程中會為被調用的函數計算其獨一無二的函數選擇器)。通過這兩對映射,本文為每一個待測智能合約建立一個函數調用集合,針對函數調用集合中的每一個函數,測試框架又會為其建立一個由模糊輸入組成的候選值集合,為后續的檢測過程做好準備。

在完成對于待測智能合約的靜態程序分析之后,便需要根據分析獲得的結果生成模糊輸入。這一步是整個漏洞檢測過程中的核心步驟。模糊測試其實并不是對智能合約本身進行模糊化處理。因為智能合約是由一些定義交易規則規范的代碼組成的程序,所以并不能對程序的代碼或是程序的執行步驟進行模糊,這將會改變程序的功能或者直接導致程序崩潰,使得交易在執行時出現一系列混亂和錯誤。測試框架真實的模糊對象是智能合約代碼中所包含的函數調用的參數。在對于智能合約的靜態分析步驟,可以獲得某一智能合約包含的所有函數調用集合,針對該集合中的每一個函數的參數(也可能不包含參數),模糊測試框架會根據參數的不同類型,按照不同的方案生成若干模糊候選值,在執行智能合約進行模糊測試時,將這些候選值作為參數傳入函數。

智能合約的執行過程本質上就是不同賬戶之間根據智能合約所提供的規則(對智能合約所包含的ABⅠ函數的調用)進行交易,這些交易有可能涉及以太幣的轉移,也有可能是單純的信息傳遞。在常規的漏洞檢測流程之外,為了保證智能合約的正常執行,還需要構建交易的參與者,即外部賬戶。除去普通的外部賬戶之外,針對一些特殊的漏洞類型,例如可重入性漏洞(其特殊之處在于該種漏洞會涉及到不同合約之間的相互調用以及函數的嵌套調用),無法通過普通的交易行為來檢測其是否存在于合約之中,于是便需要根據其具體的攻擊場景來構建代理賬戶,代理賬戶按照會造成可重入性攻擊的方式和其他用戶進行交易,與此同時標記出存在可重入漏洞的合約。

完成靜態分析,生成相關的模糊輸入后,便開始針對某一特定類型的漏洞,對已部署的每個智能合約進行漏洞檢測。首先通過隨機數生成器在某一區間內生成一個整數作為對該智能合約進行漏洞檢測的次數,該數字的選取區間需要適中,盡可能達到檢測效率以及檢測覆蓋率的平衡。在每一次漏洞檢測時,會隨機選擇該智能合約對應的函數調用集合中的某個函數進行模糊輸入。模糊輸入的內容便是在該函數的參數對應的已生成好的若干候選值中隨機選取得到的。在一次漏洞檢測的過程中涉及了多次隨機選擇,強調隨機性的原因是為了最大限度的保證漏洞檢測的覆蓋率以及準確性,并通過隨機化的方式來模擬智能合約在不同的函數調用順序下的執行情況。輸入完成之后,即監控智能合約的執行情況以及交易的情況。

測試框架通過以太坊虛擬機的HTTP 服務器監控智能合約執行的過程,收集交易過程中產生的一些關鍵信息,例如交易的發起者和接收者的地址、智能合約在執行過程中的一些特定操作碼、交易涉及的以太幣金額、gas的耗費以及私有鏈在交易過程中的狀態,賬戶余額等,將這些信息放入棧中,根據收集到的信息對已經根據漏洞的特點構建好的測試用例進行分析、判斷,從而獲得最后的檢測結果,即某一智能合約中是否包含某一類型的漏洞。

在經過大約40小時的實驗過后,針對7種類型智能合約安全漏洞,完成了對部署在測試網上的416個智能合約的漏洞檢測。

本文還與業內的其他智能合約漏洞檢測工具進行了比較。本文使用開源的符號執行領域的經典工具OYENTE[11]對數據集中的全部416個智能合約進行漏洞檢測,并使用同樣開源的模糊測試工具ReGuard[17]對已分配給可重入性漏洞的13個智能合約實體進行漏洞檢測,對它們的檢測結果進行相應的對比分析。

4.4 實驗結果及其分析

首先,考慮到對不同類型漏洞進行檢測所需時間并不相同,所以根據檢測每種類型漏洞的時間耗費,分別為7 種典型的漏洞大致分配了一定數量的智能合約供其檢測??傆媽?16 個智能合約進行了漏洞檢測。針對7 種類型的漏洞分別進行漏洞檢測的智能合約的數量列舉如如表1所示。

表1 漏洞類型與智能合約數量對照Table 1 Vulnerability type versus number of smart contracts

下面,將對漏洞檢測實驗的結果進行展示,在表2中列舉了針對每種類型的漏洞檢測出的不正確智能合約的數量、不正確智能合約在所有被測智能合約中的數量占比、檢測出的不正確智能合約經人工分析后是否確實包含漏洞,檢測正確率是多少。

表2 漏洞檢測結果Table 2 Vulnerability detection results

在17 個智能合約中,工具檢測出2 個包含不消耗gas的send漏洞的合約(EthronTokenPonzi和BuyerFund),在所有被檢測的智能合約中占比約11.76%,根據該種漏洞的特點可以確定,當合約在執行過程中拋出了outof-gas異常,那么該合約包含不消耗gas的send漏洞,在實驗的過程中,監控這兩個合約的執行時,都拋出了該異常,可以認定并沒有出現錯報的情況,檢測結果是正確的。

在38個智能合約中,本文提出的方案檢測出1個智能合約包含異常無序漏洞。在對這個智能合約的代碼進行分析之后發現,它們的代碼中均包含嵌套調用鏈,再結合以太坊虛擬機對于合約執行的監控信息,嵌套調用鏈中拋出異常的位置不是根調用,以此可以判斷,對于包含異常無序漏洞的合約的檢測結果是正確的。

在13個智能合約中,檢測出了1個包含可重入性漏洞的智能合約,在對于該智能合約進行人工審計驗證后可以判斷,其確實包含可重入性漏洞,檢測結果真實可信。

對于時間戳依賴漏洞和區塊號依賴漏洞,實驗中部署了相對較多的智能合約進行檢測。在152 個智能合約中檢測出4個包含時間戳依賴漏洞,在88個智能合約中檢測出3 個包含區塊號依賴漏洞。在經過對于檢測結果的人工檢查之后發現,對于區塊號依賴漏洞的檢測出現了誤報的情況(檢測出包含區塊號依賴漏洞的智能合約中,有一個智能合約并未包含相關的漏洞)。結合針對這兩種類型的漏洞構建測試用例的方法以及錯報的智能合約的實際情況,可以總結出錯報的原因是:工具根據測試用例中的判定規則進行判斷(規則即為合約代碼中是否包含時間戳/區塊號的操作碼以及是否涉及以太幣的傳輸,如果通過滿足條件,即判定包含漏洞),出現錯報情況的智能合約確實滿足測試用例的判定條件,但測試用例忽略了一種特殊情況,即智能合約中既包含區塊號的操作碼,又涉及了以太幣的交易轉賬,但區塊號在智能合約中的使用并不是作為以太幣傳輸等關鍵操作的一部分,二者并無關聯。這種情況屬于少數現象但確實存在,而且在這兩種相似的漏洞類型中均可能出現,所以對于時間戳依賴的檢測也可能出現錯報。這屬于對于漏洞的測試用例定義不完善所導致的錯報,若要想解決這個問題,則需要在測試用例中加入關于時間戳/區塊號是否與以太幣轉移行為有關的條件的判斷,并且需要在監控合約執行的過程中額外提取一些信息,特別是對交易發起方的交易行為的監控信息。

對于危險的DelegateCall 漏洞,工具在28 個智能合約中檢測出1個包含該漏洞的合約,為了確認該檢測結果是否真實,對這個被檢測出的包含漏洞的智能合約進行了人工審查,發現這個合約中包含DelegateCall()函數,并且該DelegateCall()調用的函數確實是從初始調用的智能合約的輸入中獲得的,由此發現完全符合該漏洞的測試用例條件,得到檢測結果正確的結論。

對于凍結以太漏洞,80個智能合約中經過檢測發現了7個包含該漏洞的合約。經過對于這7個合約的人工分析后發現,它們確實自身沒有包含傳輸以太幣的功能,必須借助于對其他合約的函數的調用才能夠實現以太幣轉賬的功能,所以可以證明檢測結果真實無誤。

對416個智能合約的漏洞檢測結果顯示,在報告的19 個包含漏洞的不正確合約中,18 個合約檢測結果是正確的,1個存在錯誤的判斷,整體上,本文提出的智能合約漏洞檢測技術具有較高的檢測正確率,達94.7%。

為了更加直觀地展示本文提出的方法在檢測以太坊智能合約漏洞的性能以及目前仍然存在的問題,本文進行了與智能合約漏洞檢測領域部分相關工作的對比實驗。本文提出的方法與Oyente、ReGuard兩種漏洞檢測工具進行對比,針對若干種相同類型的漏洞并針對相同數據集中的智能合約進行漏洞檢測實驗,并對實驗結果的差異性進行對比分析。

Oyente 工具作為符號執行技術領域較為先進且經典的漏洞檢測工具,可以對堆棧大小限制漏洞、事務順序依賴漏洞、時間戳依賴漏洞以及可重入性漏洞四種智能合約漏洞進行檢測;ReGuard是一種專門針對可重入性漏洞進行檢測的模糊測試工具。表3 對本文提出的方法、Oyente以及ReGuard三者能夠檢測的漏洞類型進行了統計。根據統計結果,在三種檢測方法涉及的9種漏洞類型中,本文提出的方法可檢測其中的7種,Oyente工具可以檢測其中的4 種,ReGuard 工具可以檢測其中的1 種。實質上,在以太坊EⅠP150 硬分叉獲得的新鏈上,堆棧大小限制漏洞作為一種不具備區塊鏈特性的程序漏洞已經得到了解決。將其排除后,對于涉及到的8種漏洞,本文提出的方法可以檢測其中的7 種,Oyente工具可以檢測其中的3 種,Reguard 工具可以檢測其中的1 種。三者中明顯本文提出的方法能夠檢測的漏洞種類最為豐富,并且Oyente工具能夠檢測的3種漏洞中只有事務順序依賴漏洞不能被本文提出的方法檢測。

表3 參與對照工具可檢測漏洞類型Table 3 Types of vulnerabilities detected by tools participating in comparison

本文提出的方法和Oyente 工具二者均可檢測的漏洞類型為可重入性漏洞和時間戳依賴漏洞,可重入性漏洞同時也可被ReGuard 工具檢測,于是在對比實驗中,使用Oyente 工具和ReGuard 工具對數據集中劃分給可重入性漏洞的13 個候選智能合約進行檢測,并使用Oyente 工具對劃分給時間戳依賴漏洞的152 個候選智能合約進行檢測,得到的實驗結果如表4所示。

表4 對比實驗結果Table 4 Results of comparison experiment

在參與對比的三者對可重入漏洞的檢測結果中,本文提出的方法檢測出1個包含可重入漏洞的智能合約,經人工驗證檢測結果正確;Oyente工具檢測出5個包含可重入漏洞的智能合約,經人工驗證,其中3個為誤報;ReGuard 工具檢測出2 個包含可重入漏洞的智能合約,經人工驗證檢測結果均正確。

由此不難發現,對比其他兩種工具的檢測結果,本文提出的方法遺漏了一個存在可重入漏洞的智能合約。對該合約進行人工分析后發現,該合約在傳輸以太幣之前會進行較為復雜的條件判斷,在大多數情況下,所有條件判斷完成后,智能合約的執行走向不涉及根調用函數經過一連串調用又回到自身的情況,無法觸發本文制定的可重入漏洞的測試用例,因此導致漏報。后續還應對文中提出的漏洞檢測測試用例進行進一步完善,覆蓋盡可能全面的漏洞觸發路徑的同時確保檢測的準確性。

Oyente工具采用了符號執行技術,在面對復雜的程序路徑時具備優勢,其在13個候選合約中檢測出5個可能存在重入威脅的合約,但其中3個屬于誤報。誤報的原因包括未能充分考慮gas不足時無法執行重入調用的情況、未能充分考慮即使存在重入調用,但被調用函數不涉及以太幣的轉移或涉及以太幣轉移的函數無法被調用的情況等。雖然Oyente 工具對于可重入漏洞的檢測更加全面完善,但其對于可重入漏洞的判定標準劃分不夠精確,檢測準確性明顯低于本文提出的方法。

ReGuard工具同樣采用了模糊測試技術,其在13個候選合約中檢測出2 個脆弱智能合約,檢測結果均正確,同時具備了漏洞檢測覆蓋能力以及檢測準確性。ReGuard工具在產生模糊輸入方面與本文不同的是,其對合約管理的交易行為進行模糊處理,生成隨機的交易,在合約執行這些交易的過程中對不安全因素進行監控。交易行為必然涉及虛擬數字貨幣的轉移,該種模糊處理方式可以對智能合約執行過程中的關鍵行為進行針對性關注,排除無效信息的干擾。該思路對本文工作的后續延伸及改善具有借鑒意義。相較于本文提出的方法,ReGuard工具對于可重入性漏洞具備較強的檢測能力,但其能夠檢測的漏洞類型較為有限。

在本文提出的方法和Oyente 工具對時間戳依賴漏洞的檢測結果中,本文提出的方法檢測出4個包含時間戳依賴漏洞的智能合約,經人工驗證檢測結果正確;Oyente 工具檢測出7 個包含時間戳依賴漏洞的智能合約,經人工驗證,其中4個為誤報。

與檢測可重入漏洞時表現出的情況類似,Oyente工具面對同樣的候選合約數據集,相較于本文提出的方法檢測出了更多的潛在脆弱合約,但同時也存在一定的誤報情況,導致誤報的原因與本文提出的方法在對區塊號依賴漏洞進行檢測時出現的一次誤報情況的原因類似,即:在檢測的過程中發現智能合約中存在時間戳相關的操作,并且進行了以太幣的轉移,便認為該合約存在時間戳依賴漏洞,但時間戳并未直接參與以太幣轉移,一些通過操作時間戳進行攻擊的惡意行為實質上并不會對以太幣的轉移造成威脅。與此同時,相較于本文提出方法的檢測結果,Oyente工具遺漏了一個存在時間戳依賴漏洞的合約,經人工分析發現,該合約在進行以太幣轉移操作之前,調用當前時間戳進行涉及密碼學加解密的條件判斷操作,符號執行技術難以對該種涉及復雜數學函數的代碼結構進行分析。

對比實驗總結:相較于Oyente 工具,本文提出的方法在針對可重入性漏洞和時間戳依賴漏洞的檢測上具備更高的準確性,并且能夠檢測的漏洞種類更多,在對于可重入性漏洞的檢測能力上Oyente工具占優;相較于ReGuard工具,本文提出的方法雖然在針對可重入漏洞的檢測能力上略顯遜色,但仍具備較高的檢測準確性,并在可檢測漏洞種類方面明顯占優。本文后續工作還應對于選擇更有效的模糊種子以及制定更完善的模糊輸入生成方案進行進一步探索。

5 結語

本文提出了基于模糊測試的智能合約正確性檢測方案,構建了一個較為完整的基于模糊測試的漏洞檢測框架,并針對當前典型的7 種具備區塊鏈特點的漏洞,對若干智能合約進行了正確性檢測。從實驗結果來看,該工具生成的模糊輸入有效解決了傳統模糊測試方法存在的輸入數據量過大影響檢測效率的問題,與此同時在檢測過程中的隨機化過程又能從整體上保證檢測的覆蓋率。根據漏洞構建出的測試用例也能被監控合約執行時收集到的信息有效觸發,對于智能合約是否因包含漏洞而影響正確性做出較為準確的判斷。

針對這7 種類型的漏洞,對416 個合約進行了漏洞檢測,報告了19個包含漏洞的不滿足正確性的合約,經過對于代碼的人工分析后發現,這19 個智能合約中18個存在漏洞,1個誤報,具有較高的檢測正確率。

針對本文進行的工作,其主要的幾個技術指標:檢測準確率、檢測代碼覆蓋率、可檢測的漏洞種類等都還有較大的上升空間。對于檢測準確率,需繼續對已知漏洞進行全面的分析,構建更加完善的測試用例,與此同時在監控過程中收集更加全面的信息,以此來盡量避免誤報情況的出現;對于檢測代碼覆蓋率,可通過統計漏洞檢測過程中進行模糊處理的函數占所有代碼的百分比獲得覆蓋率,并通過定義更加合理的隨機化處理過程提高檢測覆蓋率??蓹z測的漏洞種類越多,檢測工具的功能將會越發強大和完善,可以通過分析更多種已知的漏洞,構建更多種漏洞的測試用例,以此來擴展工具的檢測范圍。目前本文提出的模糊測試框架只能對以太坊平臺上的智能合約進行漏洞檢測,未來希望可以實現跨平臺的智能合約正確性檢測。

猜你喜歡
以太測試用例調用
以太極為旗,開啟新時代“黃河大合唱”
基于SmartUnit的安全通信系統單元測試用例自動生成
核電項目物項調用管理的應用研究
LabWindows/CVI下基于ActiveX技術的Excel調用
車易鏈:做汽車業的“以太坊”
基于混合遺傳算法的回歸測試用例集最小化研究
基于系統調用的惡意軟件檢測技術研究
基于依賴結構的測試用例優先級技術
百通推出入門級快速工業以太網絡交換器系列
以太互聯 高效便捷 經濟、可靠、易用的小型可編程控制器
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合