陳可欣,劉嘉勇,賈 鵬
(四川大學網絡空間安全學院,成都 610065)
近年來,加密貨幣和區塊鏈技術在行業和學術界獲得了極大的普及和關注。區塊鏈的發展一共經過了以下兩個階段:第一個階段主要解決不信任的情況下網絡對等方之間的安全轉賬問題。第二個階段出現了許多支持智能合約的增強型區塊鏈平臺,其中最受歡迎的平臺之一是以太坊,它使用圖靈完備的編程語言增強了區塊鏈平臺,使開發人員可以編寫智能合約和去中心化應用程序。
隨著以太坊的不斷發展,智能合約的數量也在急速增長。智能合約的概念最早是在1995年被提出的,是一種旨在以信息化方式傳播、驗證或執行合同的計算機協議。智能合約將與合約相關的所有條款以及邏輯全都編寫到一段代碼中去。智能合約可以進行自我執行以及自我驗證,在執行的過程中不需要人工進行干預。然而,智能合約不斷發展的同時,其存在的安全漏洞也逐漸顯露。近年來,利用以太坊智能合約中的安全漏洞進行攻擊的新聞報道越來越多。一個著名的事件就是針對去中心化的自 治 組 織 DAO (decentralized autonomous organization,DAO)的攻擊,造成了6000 萬美元的損失。智能合約易受攻擊的原因主要有以下幾個方面:
(1)智能合約的運行依賴于底層的區塊鏈平臺以及其他的協作合約,合約開發者沒能完全理解這些合約之間以及合約與底層區塊鏈平臺之間隱含的關系。
(2)智能合約的編程語言與運行環境對于合約開發者來說都是全新的,這些工具本身也還不夠成熟,合約開發者沒能很好地處理這些工具自身的不足。
(3)區塊鏈具有不可篡改的性質,智能合約在被部署至區塊鏈平臺之后難以更新。模糊測試是一種發現軟件漏洞的有效方法,其基本原理是,在很少或根本不知道文件的底層語法結構的情況下,隨機地改變輸入文件的某些部分生成變異文件,通過變異文件嘗試觸發目標程序的異常和安全漏洞。該技術自出現以來得到了廣泛的應用,并發現了大量的軟件漏洞。
因為模糊測試技術在挖掘漏洞方面的高效性,開始有研究者將模糊測試技術應用在智能合約的漏洞挖掘場景中,并且提出了一些針對智能合約的漏洞挖掘工具,如Nguyen 等提出的sFuzz、Jiang 等提出 的ContractFuzzer、Luu 等提出的Oyente 等。然而,現有的智能合約漏洞挖掘工具還存在著一些不足之處:sFuzz 結合了AFL(american fuzzy lop)模糊器中的策略,是一個覆蓋率引導的智能合約模糊測試工具,雖然其在實現高代碼覆蓋率和發現漏洞方面是有效的,但并沒有考慮到種子的優劣,均等對待每個種子,會導致花費很多時間在低質量的種子上。Oyente 將需要分析的合約的字節碼和當前以太坊的全局狀態作為輸入,檢測合約是否存在安全問題,并向用戶輸入有問題的符號路徑。但是,由于符號執行的路徑深度限制,驗證所有可能的路徑會遇到路徑爆炸問題,當路徑約束復雜且難以解決時,符號執行可能無法探索深層路徑,并且具有較差的可伸縮性。ContractFuzzer 使用預先部署的合約構建網絡并生成事務以運行智能合約,基于一組預定義的參數值生成測試用例,并以一組特定于智能合約的測試用例來判斷是否存在某種漏洞。但ContractFuzzer 只是簡單地通過輸入大量的參數來發現漏洞,并不能有效地觸發更深層次的路徑。
針對上述智能合約模糊測試工具存在的不足,本文提出了一種效率導向的智能合約模糊測試工具ConFuzz。根據測試用例的執行速度、到達的路徑深度等因素給測試用例進行打分,基于分值來調整測試用例在havoc 階段的用時。實驗結果表明,ConFuzz 可以在更短的時間里檢測出更多的漏洞,有效提高了針對智能合約的模糊測試的效率。
本文的組織結構如下:第一節介紹智能合約的一些常見漏洞。第二節對ConFuzz的實現方式進行詳細介紹。第三節給出了實驗結果,并與其他方法進行了比較。最后,在第四節中進行了總結并對未來工作進行了展望。
在本節中,將詳細介紹智能合約幾種常見漏洞。
當存在重入漏洞的合約將以太幣發送給惡意的合約地址時(惡意合約地址來源于輸入或者是調用者地址),攻擊者可以通過重入漏洞重新進入存在漏洞的合約。此時漏洞合約雖然已經發送了以太幣完成交易,但合約狀態還未更新,攻擊者可以執行一些開發人員不希望執行的合約邏輯,比如利用漏洞合約中的轉賬操作向攻擊者賬戶進行非法轉賬。
以太坊中的每一筆交易都是按照智能合約的規定一步一步執行命令的,每執行一個命令都會產生一定的消耗,這個消耗用燃氣(gas)作為單位。另外,不同命令消耗的燃氣(gas)數量也不相同。每一筆交易都被要求包含一個燃氣上限(gas limit),該上限代表是這筆交易允許消耗的燃氣的最大值,可以理解為交易服務本身的服務費。當合約使用send 函數發送以太幣到某一合約時,接收合約中的回退函數將會被調用,如果回退函數執行過程中消耗的燃氣大于2300,就會觸發一個異常,導致轉賬失敗,但是原有合約會繼續執行。該漏洞產生的根本原因是使用send 調用其他合約函數時,在執行期間觸發的異常不會影響原有函數的執行。
智能合約間的相互調用除了直接調用以外還有通過函數的嵌套調用方式。如果每一個調用都是對合約函數的直接調用,當異常發生時,包括以太幣轉賬在內的所有交易都會被還原,并返回false。但是,當合約間以函數的方式嵌套調用其他合約時,由于solidity語言中沒有一個一致的方法去處理異常,交易的fallback 便會在該調用函數處停止并返回false。發起調用的合約可能無法獲取被調用的合約中的異常信息。這種處理異常的不一致性會影響到合約的安全性。比如,如果僅僅根據沒有異常拋出就認為轉賬是成功的,這是很不安全的。
DelegateCall 函數的目的是用于實現類似于代碼庫的調用。它可以讓合約在不用傳輸自身狀態的情況下使用其他合約的代碼。但是當函數的參數是由當前調用者指定時,攻擊者便可以用合約擁有者的身份執行其他合約的任意函數。利用這個漏洞進行攻擊的典型事件是對錢包(wallet)合約的攻擊,該攻擊導致合約的擁有者損失了3000萬美元。
當一個智能合約使用區塊狀態變量作為發送以太幣等關鍵操作的執行條件,或者作為生成隨機數的來源時,就有可能存在此類型漏洞。區塊狀態變量包括時間戳、深度、燃氣上限等,由于一個區塊的時間戳是由礦工挖礦時的系統決定的,礦工可以事先計算出對自己有利的時間戳,并且在挖礦時將時間設置成對自己有利的時間。因此一個惡意的礦工能夠通過修改區塊的時間戳獲取利益。
以太凍結漏洞產生的原因是有些合約用于接受以太幣,并轉賬給其他地址,但是,這些合約本身并沒有實現一個轉賬函數,而是通過調用其他合約中的轉賬函數實現轉賬的功能。如果這些提供轉賬功能的合約執行了銷毀操作的話,那么,調用了這個轉賬功能的合約就有可能發生以太幣被凍結的情況。當以太幣被凍結后,因為合約的代碼無法被修改,也就無法進行轉出操作。
與其他的編程語言一樣,在solidity 語言中,合約余額的檢查中如果直接使用了加減乘除而沒做額外的判斷時,就會存在算術溢出隱患,攻擊者可以通過傳入超大數字導致溢出繞過判斷,這樣就可以轉走巨額代幣。
在本節中,首先定義智能合約模糊測試中存在的問題,然后逐步詳細介紹本文的方法。
在AFL 的變異機制中,維護了一個種子隊列,每次把種子隊列中的文件取出來后,對其進行變異然后投送給目標程序。如表1 所示,AFL 的文件變異方法主要有6 種,其中前4 種變異方式由于不存在隨機性,所以也叫作確定性變異,后2種因為存在隨機性,稱為非確定性變異。當種子隊列中的所有文件變異結束后,代表完成了一個cycle,進入下一輪變異。現有智能合約模糊測試工具沒有考慮種子的重要程度,所有的種子都會得到相同的變異時間,這一定程度上會影響Fuzz的效率。

表1 AFL文件變異方法
ConFuzz的整體結構如圖1所示。

圖1 ConFuzz的整體結構
ConFuzz 從初始種子集中選取種子,根據表1 所示的種子變異算法對種子進行變異以生成fuzz智能合約的測試用例。同時其監視測試用例的執行,將fuzz 過程中的覆蓋率、分支數、每秒執行的變異種子數、種子到達的路徑深度等信息記錄在執行日志中。如果發現了程序崩潰,ConFuzz 就檢查執行日志并報告漏洞類型。如果發現了新的路徑,那么把到達該路徑的測試用例添加到種子池中做進一步的變異。在種子變異算法上,ConFuzz 根據種子的執行速度、到達的路徑深度等因素給種子進行打分,根據分值,來調整在非確定性變異階段havoc 方法的用時。換而言之,打分機制的根本目的使得執行時間短、代碼覆蓋高、到達更深路徑深度的種子執行的時間更長,擁有更多的havoc變異機會。
如2.1 節所述,為了解決sFuzz 在非確定性變異階段沒有考慮種子重要程度的問題,ConFuzz 提出了一種打分機制,來實現對種子重要性的評估,并且給予重要程度高的種子更多的變異時間。打分機制被廣泛地應用于衡量候選種子質量,在AFL、Li 等提出的vFuzz等著名模糊測試框架中,都有運用。許多實踐表明,通過打分機制,能讓質量更高的種子優先變異,顯著提高fuzz過程的效率。
ConFuzz 構造了一個名為calculate_score 的函數對種子進行打分,調整havoc 階段用時,如算法1 所示。第2 行從種子樣本池中選擇種子,遍歷池中的所有種子。第3 到4 行是第一個打分判斷條件,首先計算出一個速度的平均值,并以這個平均值作為后續打分的標準,即,將每個種子的執行速度乘以某個(0,4]之間的數,并將結果與平均值比較。運行快速種子的成本更低,所以ConFuzz給它們更多的時間,如果結果大于平均值,乘的數越小的種子,代表該種子的運行速度越快,給的分就越高;反之,如果小于平均值,那么乘的數越大的種子,代表該種子的運行速度越慢,得分就越低。第5 到8行是第二個打分判斷條件,根據測試用例到達的深度來進行打分,能夠到達更深層次的測試用例更可能揭示無法發現的漏洞,到達的深度越深,也就是覆蓋率越高,得分就越高。值得注意的是,在第7行,增加了一個判斷條件,如果最大深度小于3,就不給該種子打分。這樣做有兩個原因:一是因為深度淺的待測的合約小,分支少,對小合約用大量的樣本進行fuzz 并不能提高發現漏洞的機會;二是因為隨機性變異過于盲目,變異出到達更深路徑的種子概率過低。通過加入打分機制,能夠保證執行速度快、覆蓋深度深的種子具有更多的變異次數、更長的havoc 變異時間,進而就有更大的幾率發現更多的漏洞。


在本節中,通過實驗將ConFuzz 與Contract Fuzzer 和sFuzz 這兩個智能合約模糊測試工具進行比較。
本文的實驗是在配有8GB 內存的Ubuntu18.04.1 LTS 上運行的。測試合約一共有381 個,都 是 從EtherScan網 站 上 爬 取 的。EtherScan 是2015年推出的一個以太坊區塊探索和分析的分布式智能合約平臺, 作為探索以太坊的窗口,可以查看合約信息、交易信息等。
ConFuzz 一共測試了381 個合約,共有兩種類型的賬戶去調用這些合約,包括一個普通賬戶和一個專門測試可重入漏洞的賬戶。每個合約測試時間為1 min,共測試了三次,計算三次的平均值,結果如表2所示。其中表格第一列列出了ConFuzz測出的漏洞類型,第二、三列分別列出了該類型漏洞的數量以及占漏洞總數的百分比,第四列是該類型漏洞的真陽性率,即ConFuzz 檢測出來的存在該漏洞的合約數除以經驗證所有存在該漏洞的合約數。

表2 ConFuzz漏洞測試結果
可以看到,對于可重入漏洞、無氣發送、Delegatecall 受控漏洞、異常無序、算術上溢、算數下溢這六種類型的漏洞來說,每一個被Confuzz 測出來的漏洞經過人工檢測都是真實存在的,不存在誤報。而對于塊依賴和時間戳依賴漏洞,ConFuzz 報告的漏洞中,分別有2 個和4個是誤報,這兩類漏洞產生漏報的原因是相同的,都是因為將區塊編號或時間戳分配給全局變量,但它們與以太發送過程無關。
為了對比三個工具在速度上的差異,在381個合約中隨機抽樣100個合約,三個工具的執行速度比較如圖2所示。

圖2 三種工具的速度比較
圖2三種工具的速度比較。橫軸代表不同的合約,縱軸代表變異樣本執行的速度,即一分鐘內生成和執行的變異樣本的平均數。為了直觀清晰地看出結果,將合約樣本數量進行遞增排序。由于ContractFuzzer 平均每秒只生成和執行0.1 個測試用例,所以沒有在圖上表現出來。ContractFuzzer 速度明顯偏慢的原因主要有兩個:
(1)ContractFuzzer 維護了一個龐大又復雜的系統,包括一個線上的模糊測試工具和線下的以太坊虛擬機(ethereumvirtual machine,EVM)插樁工具,而Confuzz 不用維護和模擬整個區塊鏈網絡。
(2)ContractFuzzer 的大部分時間花費在對合約的靜態分析構建合約池方面,而Confuzz 不需要進行靜態分析提取函數選擇器。
從圖2 可以看出,對隨機抽樣的100 個合約中的大部分合約來說,ConFuzz 的執行速度比sFuzz快。但是對于某些合約,sFuzz的執行速度比ConFuzz更快。這是因為存在一些小合約,在第一輪的確定性變異階段就可以fuzz 完成,無法進入第二輪的非確定性變異階段。
同時,實驗計算381 個合約的平均執行速度,結果表明,ConFuzz 比sFuzz 執行的速度提高了8.03%。ConFuzz 速度提高的原因主要有兩個方面。
(1)增加了打分機制,使得執行速度快的樣本擁有了更多的havoc 時間,可以變異出更多的執行速度快的樣本。
(2)由于速度慢、代碼覆蓋深度淺的樣本得分低,所以對這些樣本花費的時間更少,就有更多的時間進行有效的樣本變異,執行更多效果好的樣本。
實驗結果表明,Confuzz 在漏洞挖掘方面相較ContractFuzzer 測出的漏洞數量更多、準確率更高、更可靠;在速度上Confuzz 比sFuzz 更快,在相同的時間內可以執行更多的有效種子樣本,更高效。
隨著區塊鏈和智能合約技術的發展,數百萬智能合約被部署在區塊鏈平臺上,以實現分散應用的構建。然而,智能合約存在的安全漏洞對其未來的發展構成了巨大威脅。本文提出了一個基于打分機制的智能合約模糊測試工具ConFuzz。實驗結果表明,ConFuzz 能有效地發現智能合約存在的8種類型的漏洞,是高效、快速、準確度高的智能合約模糊測試工具。
由于ConFuzz 是根據合約的jumpi 指令計算合約分支的,如果一個簡單的合約不含有jumpi指令,ConFuzz 就會跳過而不去測試它,從而無法發現其存在的安全漏洞。未來還會進一步考慮這種情況,使得ConFuzz也能有效地測試簡單的合約。區塊鏈和智能合約仍在不斷地發展中,越來越多的智能合約被部署。因此,智能合約的安全漏洞問題不容忽視,智能合約的未來將專注于解決這些挑戰。