作者:啟明星辰ADLab

近日,啟明星辰ADLab使用最新上線的智能合約監控系統發現了大量以太坊智能合約的攻擊事件。在眾多攻擊案例中,有些漏洞成因或攻擊模式少有研究涉及,也出現了一些比較隱蔽的攻擊鏈。本文將對這些攻擊案例進行詳細分析。

使用Oraclize服務的疏忽

為了將區塊鏈技術應用到線下,例如將飛機延誤險、數字貨幣兌換等業務上鏈,區塊鏈需要具有訪問鏈外數據的能力。但是如果智能合約直接從外部服務獲取數據,由于網絡延遲,節點處理速度等各種原因,會導致每個結點獲取的數據不同,使區塊鏈的共識機制失效。

現有的解決方案是使用第三方發送區塊鏈的交易,交易會同步到每個節點,從而保證數據的一致性。Oraclize是一個預言機,為以太坊等區塊鏈提供數據服務,它獨立于區塊鏈系統之外,是一個中心化的第三方。Oraclize可以提供的數據訪問服務包括隨機數、URL訪問、IPFS等。Oraclize的架構如圖所示:

Oraclize不是鏈上直接可以調用的函數,而是一個鏈外的實體。為了抓取外部數據,以太坊智能合約需要發送一個查詢請求給Oraclize,當Oraclize監聽到鏈上有相關請求時,立即對互聯網上的資源發起訪問,然后調用合約中的回調函數__callback將查詢結果返回區塊鏈。

例如,用美元兌換以太幣的智能合約的數據查詢語句如下:

監聽到請求后,Oraclize會訪問URL獲得查詢結果,然后調用__callback的函數,Oraclize返回的數據通過__callback函數參數傳回智能合約。上圖中函數調用的參數[3]中的“3334312e3533”即為當時的匯率:1ETH = $341.53,隨后智能合約會根據這個查詢結果進行后續的邏輯處理。

  • 攻擊案例:SIGMA (0x03AF37073258B08FfFF303e9E07E8a0B7bfc4fd9)

SIGMA合約使用了Oraclize服務查詢匯率。該合約的__callback回調函數如下:

由于__callback函數中存在整數溢出,導致owner的代幣余額被下溢成一個很大的值,導致代幣增發。從代幣份額排名可以看出攻擊者的賬戶地址為0x2ef045a75b967054791c23ab93fbc52cc0a35c80,而該地址并不是創建合約的賬戶地址(0xC7e92D8997359863a8F15FE87C0812D7A3a8F770)。

跟蹤Transactions,發現0xC7e92D8997359863a8F15FE87C0812D7A3a8F770調transfer_ownership將合約的owner設置為0x2ef045a75b967054791c23ab93fbc52cc0a35c80。

針對這個漏洞是否使用SafeMath就可以解決了呢?答案是否定的。在Oraclize調用__callback之前,有用戶對查詢函數的調用,而且這個調用花費以太幣。

使用SafeMath的情況下,發生溢出的事務會回滾,但本例中能夠回滾的只有Oraclize對__callback函數調用的事務,而之前用戶花費以太幣發生的事務則無法回滾。這個現象的根本原因是Oraclize是一個獨立的實體,導致邏輯上應該完整的一個操作被分割成了兩個事務。因此,通過Oraclize與鏈下數據交互時只能更加小心,代碼編寫需要更加謹慎。

龐氏代幣合約漏洞

以太坊智能合約中混雜進了不少龐氏騙局合約,他們向投資者承諾,如果你向某合約投資一筆以太坊,它就會以一個高回報率回贈你更多的以太幣,然而高回報只能從后續的投資者那里源源不斷地吸取資金以反饋給前面的投資者。

攻擊案例:ETHX( 0x1c98eea5fe5e15d77feeabc0dfcfad32314fd481)

ETHX是一個典型的龐氏代幣合約。該合約可以看成虛擬幣交易所,但只有ETH和ETHX (ERC20 token)交易對,每次交易,都有5%的token分配給整個平臺的已有的token持有者,因此token持有者在持幣期間,將會直接賺取新購買者和舊拋售者的手續費。從ETHX合約代碼可以看出,該合約對transferFrom函數進行了擴展,transferFrom函數首先進行allowance限額判定,然后調用了自定義的transferTokens函數來完成轉賬。

在transferTokens函數中,當to賬戶地址不等于合約地址,由于事先對from賬戶額度進行了安全檢查,因此后面對from賬戶的balance運算不會產生溢出。

當to賬戶地址等于合約地址時,則調用sell函數,sell函數中由于代碼編寫失誤,錯誤的將from寫成msg.sender,對msg.sender的額度進行了減法操作,而在減法操作前沒有進行安全檢查,因此存在溢出漏洞。

為了完成對這個溢出漏洞的攻擊,攻擊者需要2個賬戶A、B,其中A賬戶代幣余額不為0,B賬戶代幣為0。

  • A賬戶調用approve給B授權一部分轉賬額度,假設授權額度為1;
  • B賬戶調用transferFrom,從A賬戶轉1單位代幣到智能合約;transferFrom調用sell函數時觸發整數溢出,即0-1=2^255。B賬戶在余額為0的情況下獲得了最大額度的token。

在ETHX合約攻擊鏈中,攻擊者使用了兩個賬戶地址,分別為:0x423b1404f51a2cdae57e597181da0a4ca4492f30

0x17a6e289e16b788505903cc7cf966f5e33dd1b94

首先,0x17a6e289e16b788505903cc7cf966f5e33dd1b94調用approve給0x423b1404f51a2cdae57e597181da0a4ca4492f30授權轉賬額度,參數value=1。

然后,0x423b1404f51a2cdae57e597181da0a4ca4492f30調用transferFrom方法,從賬戶0x17a6e289e16b788505903cc7cf966f5e33dd1b94向ETHX合約地址0x1c98eea5fe5e15d77feeabc0dfcfad32314fd481?轉移1個Token。

調用前,balance(0x423b1404f51a2cdae57e597181da0a4ca4492f30)=0。調用后,溢出后balance(0x423b1404f51a2cdae57e597181da0a4ca4492f30)=2^255。

監控平臺顯示已經被攻擊的同類代幣合約如下表:

SafeMath使用不當

以太坊虛擬機EVM定義無符號整數為uint256,可以表示一個256位的大整數,但并沒有提供溢出的檢測機制。OpenZeppline是一個第三方智能合約庫,實現了一套SafeMath庫來檢測溢出。其代碼如下:

SafeMath使用內建的require或assert來檢查運算是否發生溢出,如果發生了溢出,require和assert中包含的代碼會使該事務回滾。但有些開發者不能完全理解SafeMath模版代碼,導致合約代碼中仍然存在漏洞。

  • 攻擊案例:UCN (0x6EF5B9ae723Fe059Cac71aD620495575d19dAc42)

UCN(http://www.saveunicoins.com/Unicorn/index.html)是一個智能合約DApp應用。合約代碼在SafeMath庫中注釋assert語句,因此SafeMath函數等同于直接進行算術運算,沒有任何安全檢查。并且在transferFrom函數中,注釋中聲明sub函數是安全的,不知道這是開發人員的疏忽還是故意留下的后門。

由于sub函數等同于算術運算,balances[_from] = balances[_from].sub(_value); 存在整數下溢漏洞,可以使得賬戶余額變成一個極大值。

  • 攻擊案例:EMVC(0xd3F5056D9a112cA81B0e6f9f47F3285AA44c6AAA)

EMVC(http://crypto7.biz/)合約代碼在SafeMath庫中使用了一個自定義的assert來代替內建的assert。在assert函數中,如果參數assertion為false則直接return,并沒有進行異常處理。因此SafeMath函數等同于直接進行算術運算,沒有任何安全檢查。

攻擊者可以使用transfer函數設置任意賬戶余額為任意值。

總結

當智能合約要實現更多功能時,代碼會相應變得更加復雜,與ERC20標準代碼的差異也越來越大,因而潛在的漏洞面貌更加多樣。為了保證智能合約的安全,除遵循安全開發原則、按照“Check Lists”進行基線檢查外,還需要實施更深入細致的審計。


啟明星辰積極防御實驗室(ADLab)

ADLab成立于1999年,是中國安全行業最早成立的攻防技術研究實驗室之一,微軟MAPP計劃核心成員。截止目前,ADLab通過CVE發布Windows、Linux、Unix等操作系統安全或軟件漏洞近400個,持續保持國際網絡安全領域一流水準。實驗室研究方向涵蓋操作系統與應用系統安全研究、移動智能終端安全研究、物聯網智能設備安全研究、Web安全研究、工控系統安全研究、云安全研究。研究成果應用于產品核心技術研究、國家重點科技項目攻關、專業安全服務等。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/685/