近年來以太坊獲得了極大的歡迎,從2016年1月的平均每日交易1萬增加到2020年1月的平均50萬。同樣,智能合約開始發揮更大的價值,使它們成為攻擊者的目標,結果用戶成為攻擊的受害者,損失了數百萬美元。為了應對這些攻擊,學術界和工業界都提出了許多工具來掃描智能合約中的漏洞,然后再將其部署到區塊鏈上。但是,大多數這些工具僅專注于檢測漏洞而不是攻擊,更不用說量化或追蹤被盜資產的數量。在本文中介紹了Horus,該工具具有基于邏輯驅動和圖驅動的交易分析功能對智能合約攻擊自動檢測和分析。Horus提供了一種快速的方法來量化和追蹤以太坊區塊鏈中被盜資產的流量。本研究對直到2020年5月部署在以太坊上的所有智能合約進行大規模分析,在野發現了1,888個受攻擊的智能合約和8,095個易受攻擊的交易。最后,還通過對Uniswap和Lendf.me攻擊進行深入分析,證明了工具的實用性。

01

Introduction

以太坊率先在區塊鏈上引入了圖靈完備智能合約的概念,從而徹底改變了數字資產的交易方式,這些是跨區塊鏈執行和存儲的程序。但是由于區塊鏈的防篡改性質,一旦部署智能合約就無法再對其進行修改。在撰寫本文時,以太坊的市值超過420億美元,使其成為市場上第二有價值的加密貨幣,最有價值的以太坊智能合約WETH持有價值超過20億美元的ether。此外,以太坊在過去的四年中從2016年1月的每日平均交易1萬增長到2020年1月的平均50萬。價值和知名度的增長會引起濫用,并且缺乏管理機構也導致了一些攻擊者開始利用易受攻擊的智能合約竊取資金。因此,在過去的幾年中,已經出現了許多研究工作和工具來識別智能合約漏洞,但是大多數這些工具僅專注于分析智能合約的字節碼,而不是其交易或活動。只有少數人利用事務來檢測攻擊,而大多數要么需要修改以太坊客戶端,要么需要編寫大型而復雜的攻擊檢測腳本。此外,所有這些工具都不允許在檢測到被盜資產后直接追蹤。

在這項工作中介紹了Horus,這是一個能夠根據歷史區塊鏈數據自動檢測和分析智能合約攻擊的框架。除了檢測攻擊之外,該框架還提供了量化和追蹤以太坊賬戶中被盜資產流的方法。該框架在不修改以太坊客戶端的情況下重放交易,并將其執行編碼為邏輯fact。然后使用Datalog查詢來檢測攻擊,從而使該框架易于擴展以檢測新攻擊。通過將檢測到的交易加載到圖形數據庫中,并執行交易圖形分析來追蹤被盜資金。使用Horus進行了一次縱向研究,涵蓋了從2015年8月到2020年5月的整個以太坊區塊鏈歷史,包括超過300萬個智能合約。正在研究的基本研究問題之一是,這些年來的努力是否減少了在野的攻擊。為了量化該問題的答案,首先調查攻擊是否持續發生或是否偶爾出現。盡管大多數眾所周知的攻擊都具有可觀的貨幣價值,但想知道規模較小但持續不斷的攻擊是否會更頻繁地發生并且仍然未被發現。工具的代碼和數據可從https://github.com/christoftorres/Horus 公開獲得。

02

The Horus Framework

在本節中提供有關Horus框架的設計和實現的詳細信息,Horus使對以太坊智能合約的攻擊進行縱向研究的過程自動化。該框架具有從歷史數據中檢測和分析智能合約攻擊的功能。而且,該框架還提供了追蹤以太坊賬戶中被盜資產流的方法。后者對于研究攻擊者的行為特別有用。下圖概述了Horus的體系結構。該框架組織為EAT(提取,分析和追蹤)模式的,包括三個不同階段:

(1)提取:提取階段將交易的列表作為輸入,從中提取與執行相關的信息并將其存儲為Datalog。

(2)分析:分析階段將一組Datalog關系查詢作為輸入,這些查詢共同識別對提取的Datalog的攻擊。

(3)追蹤:追蹤階段檢索通過分析獲得的攻擊者帳戶列表,并獲取與這些帳戶相關的所有交易(包括正常交易,內部交易和代幣轉移)。之后,創建一個圖形數據庫,該數據庫捕獲了來自這些賬戶的資金流(以太幣和代幣)。此外,可以用標記帳戶列表來擴充數據庫,以增強對被盜資產的追蹤。

A.提取

提取器的作用是向以太坊客戶端請求交易清單的執行追蹤,并將其轉換為反映其執行語義的邏輯關系。執行追蹤由已執行的EVM指令的有序列表組成。該列表中的每個記錄都包含諸如已執行的操作碼,程序計數器,調用堆棧深度和當前堆棧值之類的信息。不幸的是,執行追蹤無法直接從歷史區塊鏈數據中獲取,它們只能在合約執行期間記錄下來。

基于Go的以太坊客戶端(Geth)通過debug_traceTransaction和debug_traceBlockByNumber函數提供了調試功能,這能夠重播任何給定的過去事務或塊的執行,并檢索其執行追蹤。通過遠程程序調用(RPC, Remote Procedure Call)請求執行追蹤。修改Geth以加快檢索執行追蹤的過程的局限性在于,用戶不能使用Geth的默認版本,而必須使用修改后的版本,并且每次發布新版本的Geth時,都需要進行更改。本研究決定不修改Geth,而是決定提高通過RPC檢索執行追蹤的速度。注意到執行追蹤包含許多與分析無關的信息,Geth允許注入用JavaScript編寫的執行追蹤程序。通過這種機制,可以減小執行追蹤的大小并提高執行速度,而無需實際修改Geth。例如,JavaScript代碼從執行追蹤中刪除了當前程序計數器、剩余gas和指令的gas成本。而且,代碼并沒有返回與每個執行指令有關的整個堆棧和內存的完整快照,而是僅返回與該執行指令相關的堆棧元素和內存切片。

上面代碼顯示了提取器通過迭代執行追蹤的每個記錄并對相關信息進行編碼而生成的Datalog fact列表。盡管大多數fact與低級EVM操作(例如調用)有關,但其他fact與高級別操作有關。例如,erc20轉移fact是指在轉移代幣時發出的ERC-20代幣事件“ Transfer”,其中contract表示代幣合約的地址,而from和to分別表示代幣的發送者和接收者。重要的是要注意,通過修改提取器,分析器和追蹤器,可以輕松地修改或擴展此列表以支持與本文提出的方法不同的研究。除了使用默認類型數字和符號外,還定義了自己的三種新類型:160位值的Address,EVM操作碼集的Opcode 和256位堆棧值的Value。

動態污點分析:提取器利用動態污點分析來追蹤指令之間的數據流。然后,安全專家可以使用數據流fact來檢查數據是否從一條指令流向另一條指令。污點是通過源引入的,然后在整個執行過程中傳播,最后檢查它是否流入接收器。源表示可能引入不可信數據的指令(例如CALLDATALOAD或CALLDATACOPY),而接收器表示敏感位置的指令(例如CALL或SSTORE)。本研究實現了自己的動態污點分析引擎。引擎循環遍歷每條執行的指令并檢查執行的指令是否為源,然后引擎根據定義的語義通過標記受影響的堆棧值,內存區域或存儲位置來引入污點,使用遵循LIFO邏輯的數組結構實現了堆棧。內存存儲使用Python字典實現,該字典將內存和存儲地址映射到值。污點傳播在字節級別執行(請參見上圖中的示例)。

執行命令:諸如Parity錢包破解之類的攻擊是由兩個按特定順序執行的交易組成的。為了檢測這種多事務攻擊,框架通過三元組o =(b,t,s)對多事務進行總編碼,其中b是塊數,t是事務索引,s是執行步驟。執行步驟是一個簡單計數器,在事務執行開始時將其重置,并且它的值在每條已執行的指令之后增加。執行步驟與交易索引綁定,而交易索引與區塊編號綁定,因此,框架能夠準確識別跨多個交易以及整個區塊鏈歷史記錄的任何指令的執行順序。

B.分析

工具的第二階段使用Datalog引擎來分析給定的Datalog關系和查詢列表是否與任何先前提取的Datalog fact相匹配。這些Datalog查詢可識別惡意交易,這些交易通過利用給定漏洞成功對智能合約進行了具體攻擊。框架使用Souffleé作為其Datalog引擎。Soufflé將Datalog關系和查詢編譯為高度優化的C ++可執行文件。在下文中,提供了數據日志查詢,用于檢測重入、Parity錢包破解、整數溢出、未處理的異常和短地址攻擊。盡管存在許多智能合約漏洞,但在這項工作中,重點關注被NCC Group列為前十名的智能合約漏洞,并且可以提取被盜的以太幣或代幣數量或鎖定。

重入(Reentrancy):每當合約調用另一個合約,并且在適當更新原始合約中的狀態之前,被調用合約都會回調原始合約(即重入調用),就會發生重入。通過識別源自同一調用者并調用同一被調用者的循環調用來檢測重入(參見上面代碼)。檢查兩個成功的調用(即結果為1)是否共享相同的交易哈希,調用者、被調用者、ID和分支,其中第二個調用的調用深度比第一個調用的調用深度高。然后,檢查是否有兩個存儲操作具有與第一個調用相同的調用深度,其中第一個操作是SLOAD并發生在第一個調用之前,而第二個操作是SSTORE并發生在第二個調用之后。

Parity錢包破解(Parity wallet hacks):在本文中,專注于檢測兩個Parity錢包破解。這兩種破解都是由于錯誤的訪問控制實施而導致攻擊者將自己設置為所有者,從而使他們能夠執行關鍵行動,例如資金轉移或合約破壞。通過檢查是否存在兩個事務t1和t2都包含相同的發送者和接收者來檢測第一種Parity錢包破解,其中t1輸入的前4個字節與initWallet函數的函數簽名(即e46dcfeb)匹配,以及前4個t2輸入的字節與execute函數的函數簽名(即b61d27f6)匹配(請參見上面代碼)。然后,檢查是否存在一個call,該調用是t2的一部分,并且在t之后執行t2(即block1 <block2; block1 = block2,index1 <index2)。

以與第一個相似的方式檢測第二種Parity錢包破解,除了在這種情況下,檢查t2的輸入是否匹配kill函數的函數簽名(即cbf0b0c0),并且t2包含selfdestruct(參見清上面代碼)。

整數溢出(Integer Overflflows):通過檢查來自CALLDATALOAD或CALLDATACOPY opcode的數據是否流入arithmetic運算來檢測整數溢出,該算術結果與EVM返回的結果不匹配。之后,檢查算術運算的結果是否流過SSTORE storage操作和發生erc20_transfer,其中的amount是算術計算中使用的兩個操作數之一(請參見上面代碼)。請注意,在此工作中僅著重于檢測與ERC-20 代幣相關的整數溢出,因為已識別出代幣智能合約過去常常是整數溢出的受害者。

未處理異常(Unhandled Exception):默認情況下,智能合約執行的內部調用可能僅會取消回退由那些失敗的調用引起的狀態更改。開發人員有責任檢查每個調用的結果并執行適當的異常處理。但是,許多開發人員忘記或決定忽略此類例外的處理,導致資金沒有轉移給合法所有者。通過檢查操作碼為“ CALL”的調用是否失敗(即結果為0)且mount大于零且結果未在某種條件下使用的情況(參見上面代碼)來檢測未處理的異常。

短地址(Short Address):ERC-20的transfer和transferFrom函數將目標地址和給定數量的代幣作為輸入。在執行期間,如果未將事務參數正確編碼為32個字節的塊,則EVM將在交易輸入的末尾添加尾隨零,從而將輸入字節向左移幾個零,因此不希望增加代幣數被轉移。但是,攻擊者可以通過生成以結尾的零結尾的地址并忽略這些零來利用這一fact,然后讓另一方(例如,Web服務)發出調用,以調用transfer / transferFrom包含攻擊者格式錯誤的地址。通過首先檢查事務輸入的前4個字節是否匹配transfer的函數簽名(即a9059cbb)或transferFrom的函數簽名(即23b872dd)來檢測短地址攻擊。然后,對于函數transfer,檢查輸入小于68(即4個字節的函數簽名,32個字節的目標地址和32個字節的數量),并進行函數傳遞檢查輸入的長度是否小于100(即4個字節的函數簽名,32個字節的地址 ,32個字節的目標地址和32個字節的數量),最后檢查是否發生了erc20傳輸(請參見上面代碼)。

C.追蹤

最后階段是追蹤從攻擊者帳戶到帶有標簽的帳戶(例如交易所)等被盜資產(例如以太幣)。追蹤通過從已經通過數據日志分析確定的惡意交易中提取發件人地址和時間戳開始。發件人地址被推定為屬于攻擊者的帳戶。之后,追蹤器使用Etherscan的API為每個發件人地址檢索其所有正常交易,內部交易和代幣轉移,并將其加載到Neo4j圖形數據庫中。依靠Etherscan等第三方服務來檢索正常交易,內部交易和代幣轉移,因為默認的以太坊節點不提供現成的此功能。帳戶被編碼為頂點,而交易則被編碼為這些頂點之間的有向邊。區分三種類型的帳戶:攻擊者帳戶,未標記的帳戶和標記的帳戶。每種帳戶類型都包含一個地址。帶標簽的帳戶包含一個類別(例如,交易所)和標簽(例如,Kraken 1)。從Etherscan大量的帶標簽帳戶5中獲取類別和標簽,總共下載了5,437個標簽,屬于204個類別。區分三種不同類型的交易:普通交易,內部交易和代幣交易。每種交易類型都包含交易值,交易哈希和交易日期。代幣交易包含代幣名稱,代幣符號和小數位數。事務可以向后或向前加載。向前加載交易能夠追蹤攻擊者將其贓款發送至何處,而向后加載交易能夠追蹤攻擊者從何處接收其資金。

從加載交易者時的攻擊者帳戶開始,然后遞歸加載屬于同一交易的相鄰帳戶的交易,最多允許給定的躍點數,不會為交易量超過1,000的帳戶加載交易。這是為了避免通過混合服務,交換或游戲智能合約的交易使圖形數據庫膨脹。此外,當向后加載事務時,僅加載發生在攻擊時間戳之前的事務,而當向前加載事務時,僅加載發生在攻擊時間戳之后的事務。最后,在完成所有交易后,安全專家可以使用Neo4j自己的圖形查詢語言Cypher查詢圖形數據庫,以追蹤被盜資金的流向。顯然追蹤僅在一定程度上有效,因為混合服務和交換阻止了進一步的追蹤。但是,追蹤對于研究攻擊者是否將其資金發送到混合器或交易所以及確定正在使用的服務以及擴展的范圍仍然很有用。

03

Evaluation

數據集:使用以太坊ETL框架來檢索每個已部署至區塊10 M的智能合約的交易清單。總共收集了697,373,206筆交易和3,362,876份合約。收集到的合約的部署時間戳記為2015年8月7日至2020年5月4日。過濾掉了沒有交易的合約,并刪除了fas限制為21,000(即不執行代碼)的交易。此外,跳過了2016年拒絕服務攻擊中的所有事務,因為它們會導致執行時間延長。應用這些過濾器后,最終獲得了1,234,197個智能合約的最終數據集,其中包括371,419,070筆交易。在提取階段,Horus在最終數據集中生成了大約700GB的Datalog fact。

實驗設置:所有實驗都是使用一臺具有64 GB內存的計算機和一個Intel?Core?i7-8700 CPU(具有12個主頻為3.2 GHz的內核)運行的,運行64位Ubuntu 18.04.5 LTS。此外使用了Geth 1.9.9版,Soufflé1.7.1版和Neo4j 4.0.3版。

上表總結了本研究結果:發現了1,888個被攻擊的合約和8,095個對抗性交易。從這些合約中,有46次使用了重入攻擊,Parity錢包被黑客破解有600例,整數溢出攻擊有125例,未處理的異常攻擊有1,068例,短地址攻擊的受害者有55例。對于Parity錢包破解,發現大多數人是在第一種破解中遭到攻擊的。還觀察到,大多數容易受到整數溢出影響的合約都受到整數下溢的攻擊。

04

Analysis

在本節中,將通過對評估結果的分析以及對最近的Uniswap和Lendf.me事件的案例研究,來證明Horus在檢測和分析現實世界中的智能合約攻擊中的實用性。

A.攻擊的數量和頻率

上圖描述了每日攻擊的每周平均數與每日部署的每周平均數相比。每周部署合約的高峰期是在2017年底,并且在此高峰期之前發生的每周攻擊量最大。而且,大多數攻擊似乎發生在同一天的群集中。懷疑攻擊者會在區塊鏈中掃描類似的易受攻擊合約,并同時利用它們。攻擊中的前三個峰值對應于DAO和Parity錢包破解,而最后一個峰值對應于最近的Uniswap / Lendf.me黑入。

上圖描述了在評估過程中衡量的每種漏洞類型的惡意交易的發生。雖然重入攻擊似乎偶爾會發生,但其他類型的漏洞(如未處理的異常)卻被相當連續地觸發。總體而言,隨著時間的推移,發現越來越少的合約成為短地址攻擊和整數溢出的受害者,這表明智能合約在過去幾年中變得更加安全,但是,也看到智能合約仍然容易受到眾所周知的漏洞(例如重入)的攻擊和未處理的異常,盡管可以使用自動化安全工具。上圖還說明了每筆對抗交易中被盜(重入和Parity錢包破解 1)或被鎖定(未處理的異常和Parity錢包破解 2)的美元金額。通過在攻擊時將一個以太幣的價格乘以通過Datalog查詢提取的以太幣來計算USDamount。不提供用于短地址攻擊和整數溢出的USD數量,因為這些攻擊涉及被盜的ERC-20 代幣,并且無法獲得這些代幣的歷史價格。可以看到,就以太坊被盜而言,DAO hack和第一個Parity錢包破解仍然是破壞力最大的兩種攻擊,分別價值94,812,885美元和107,773,036美元。為了方便讀者,標記了DAO攻擊或兩個Parity錢包破解等著名事件,以證明Horus能夠檢測到它們。

B.Uniswap和Lendf.me事件的取證分析

Uniswap:2020年4月18日,攻擊者能夠從Uniswap的ETH-imBTC流動資金池中抽出大量以太幣。他們有意選擇imBTC代幣,因為它實現了ERC777標準,這將使他們能夠注冊回調函數,從而對Uniswap進行重入攻擊。攻擊者將從購買用于ETH的imBTC代幣開始。之后,他們將在同一筆交易中將購買的imBTC代幣的一半交換回ETH。但是,后者將觸發攻擊者在攻擊之前注冊的回調函數,從而使他們能夠控制并回調Uniswap合約,以在更新轉換率之前將imBTC令牌的剩余半數交換為ETH。因此,攻擊者可以以更高的轉換率交易第二批imBTC代幣。有趣的是,Uniswap知道此漏洞,并且在攻擊發生的前一年就已公開披露。

使用Horus提取并分析了當天進行的所有交易,確定了總共525個對Uniswap進行再入攻擊的交易,累計利潤為1,278 ETH(232,239.46 USD)。攻擊開始于世界標準時間00:58:19,大約在3.5小時后世界標準時間04:22:58結束。上圖描繪了攻擊的時間表,顯示了攻擊者投資的以太幣數量以及他們每筆交易的凈利潤,看到凈利潤會隨著時間下降。單筆交易的最高利潤約為9.79 ETH(1,778.72 USD),而最低利潤為0.01 ETH(2.73 USD)。攻擊者通過購買大約80 ETH的代幣來開始攻擊,然后逐漸下降到1 ETH。此外,看到利潤主要與攻擊者正在投資(即用于購買imBTC代幣的)以太幣數量有關。還看到有時會出現一些波動,攻擊者在投資相同數量的以太時會獲得更多利潤。這可能是由于在攻擊過程中其他參與者在Uniswap上交易了imBTC,因此影響了匯率。在最后一步中,使用Horus的追蹤功能追蹤了攻擊者帳戶的整個以太流,最多5跳。交易圖分析顯示,攻擊者在不同的交易所上交換了大約702 ETH(被盜資金的55%)的代幣:Uniswap上的589 ETH上的WETH,DAI,USDC,BAT和MKR,31 ETH上的Compound和82 ETH在1inch.exchange。后者對于取證特別有用,因為1inch.exchange可以追蹤在其平臺上執行的交易的IP地址,這在使攻擊者匿名時很有用。

Lendf.me:2020年4月19日,攻擊者耗盡了Lendf.me的所有流動資金池。與Uniswap黑客類似,攻擊者利用Lendf.me交易imBTC的fact,并可以注冊一個回調函數以執行重入攻擊。攻擊者首先將x個數量的imBTC令牌存入Lendf.me的流動資金池。接下來,仍然在同一事務中,他們將存入另一個金額y,但是,這一次觸發了攻擊者注冊的回調函數,該函數將從Lendf.me撤回先前存放的x代幣。交易結束時,攻擊者在imBTC代幣合約上的imBTC余額將為x-y,但Lendf.me合約上的imBTC余額將為x + y,從而將其在Lendf.me上的imBTC余額增加x,而無需實際存款。與Uniswap相似,這里的問題是用戶的余額僅在代幣傳輸后才更新,因此更新基于傳輸前的數據,因此忽略了兩者之間的任何更新。

使用Horus提取并分析了當天收集的所有交易,確定了總共46條針對Lendf.me進行重入攻擊的交易,以及19條使用被盜的imBTC代幣借用其他代幣的交易。上圖左側顯示了攻擊者在攻擊過程中存放的imBTC代幣數量,以及攻擊者通過借入其他代幣獲得的USD數量。右側顯示了攻擊者從Lendf.me借入的USD代幣數量。攻擊者從12個不同的代幣中借入,價值25,244,120.74美元,其中1031萬美元僅來自借入WETH。攻擊者在世界標準時間00:58:43發起了攻擊,并于2小時后在世界標準時間02:12:11停止了攻擊。他們開始存儲少量的imBTC,并隨著時間的推移將其數量增加到291.35 imBTC。借閱開始于世界標準時間01:22:27,結束于世界標準時間03:30:42。最后,使用Horus跟蹤攻擊者帳戶中最多3個躍點的代幣流。發現攻擊者最初在ParaSwap,Compound,Aave和1inch.exchange上用部分被盜代幣交換了其他代幣。但是,大約在10小時后的UTC時間14:16:52,攻擊者開始將所有竊取的代幣發送回Lendf.me的管理員帳戶(0xa6a6783828ab3e4a9db54302bc01c4ca73f17efb)。然后,Lendf.me將所有代幣移動到恢復帳戶(0xc88fcc12f400a0a2cebe87110dcde0dafd2 9f148)中,然后用戶可以在其中恢復其代幣。

05

Conclusion

在過去的幾年中,業界已經提出了許多用于以太坊智能合約的自動漏洞檢測工具。這就導致了一個問題,即智能合約的安全性是否已經提高。在本文中介紹了可擴展工具Horus的設計和實現,該框架用于執行有關智能合約攻擊的檢測,分析和追蹤的縱向研究。分析了2015年8月至2020年5月的交易,確定了8,095起攻擊以及1,888個易受攻擊的合約。分析表明,盡管整數溢出之類的攻擊的攻擊次數似乎有所減少,但盡管有大量新的智能合約安全工具,但仍存在未處理的異常和可重入攻擊。最后,還對最近的Uniswap和Lendf.me事件進行了深入分析。