智能合約中的那些後門漏洞

智能合約的概念可以追溯到1994年,由Nick Szabo提出,但直到2008年纔出現採用智能合約所需的區塊鏈技術,而最終於2013年,作爲以太坊智能合約系統的一部分,智能合約首次出現。

智能合約包含了有關交易的所有信息,只有在滿足要求後纔會執行結果操作,智能合約和傳統紙質合約的區別在於智能合約是由計算機生成的,因此,代碼本身解釋了參與方的相關義務,與此同時,用戶可以根據規則開發自己想要的智能合約。

而隨着智能合約普及,合約的安全問題也引起衆多合約開發者和安全研究人員的關注,比較典型的就是隨之建立的DASP Top10

近期,筆者在對一些智能合約進行代碼審計時發現有很多合約存在可疑的後門漏洞,具備特殊權限的地址用戶(合約的owner)或合約賬號具備控制用戶資產的權限,可對任意用戶的資產進行銷燬操作,本文將對此進行簡要分析。

函數漏洞

1.burn()

合約地址:

https://etherscan.io/address/0x705051bbfd9f287869a412cba8bc7d112de48e69#code

利用條件:合約的owner權限

漏洞代碼:

漏洞分析:如上圖所示,在智能合約中提供了burn函數,該函數主要用於銷燬其它地址的token,當要銷燬的token數量小於目標賬戶所擁有的token值時就可以成功銷燬目標賬戶的token,且這裏的地址能指定爲任意用戶的地址,所以只要我們能夠調用該函數即可通過賦予_ from爲任意地址賬戶,_ unitAmout爲任意數量(不超過from賬戶擁有的數量)就可以銷燬_from賬戶的代幣,下面我們再來看一下此處對於函數調用者身份限定的修飾器—onlyOwner。

由以上代碼可知,當函數的調用者爲合約的owner地址賬戶時可以銷燬任意地址用戶的代幣,甚至將其歸0。

2.burnFrom()

合約地址:

https://etherscan.io/address/0x365542df3c8c9d096c5f0de24a0d8cf33c19c8fd#code

利用條件:合約的owner,同時mintingFinished爲"False"

漏洞代碼:

漏洞分析:如上圖所示,合約中的burnFrom函數用於銷燬代幣,但是該函數只能被合約的owner調用,而且由於地址參數可控,故合約的owner可以操控任意地址用戶的代幣,銷燬任意地址用戶任意數量的代幣(數量小於等於用戶代幣總量),由於該函數被canMint修飾,所以查看一下該修飾器。

之後,通過"Read Contract"來查看當前mintingFinished的值:

從圖可以看到mintingFinished爲"False",即滿足canMint修飾器條件,所以,此時的burnFrom函數可被合約的owner調用來操控任意用戶的代幣。

3.burnTokens

合約地址:

https://etherscan.io/address/0x662abcad0b7f345ab7ffb1b1fbb9df7894f18e66#code

利用條件:合約的owner權限

漏洞代碼:

漏洞分析:如上圖所示,burnTokens用於銷燬用戶的代幣,由於銷燬的地址參數、銷燬的代幣數量都可控,所以合約的調用者可以銷燬任意用戶的代幣,但是該函數只能被合約的ICO地址用戶調用,下面跟蹤一下該賬戶看看其實現上是否可以。

從上面可以看到,合約在初始化是對icoContract進行了賦值,下面通過etherscan.io中的readcontract溯源一下:

之後,再次進入icoContract中跟蹤是否可以成功調用:

從代碼中可以看到burnTokens(關於修飾器的跟蹤分析與之前類似,這裏不再贅述):

這裏的cartaxiToken即爲之前的合約地址:

同時,發現存在調用的歷史記錄:

https://etherscan.io/tx/0xf5d125c945e697966703894a400a311dc189d480e625aec1e317abb2434131f4

4.destory()

合約地址:

https://etherscan.io/address/0x27695e09149adc738a978e9a678f99e4c39e9eb9#code

利用條件:合約的owner權限

漏洞代碼:

如上圖所示,在智能合約當中提供了destory函數,用於銷燬目標賬戶的代幣,在該函數當中增加了對msg.senderaccountBalance的判斷,從整個邏輯上可以看到主要有兩種銷燬途徑:

  • 途徑一:合約的owner賦予allowManuallyBurnTokens爲"true"的條件下,地址賬戶自我銷燬自己的代幣;
  • 途徑二:無需allowManuallyBurnTokens爲"true"的條件,合約的owner銷燬任意地址用戶的代幣。

自然,途徑一自我銷燬代幣合情合理,但是途徑二卻導致合約的owner可以操控任意地址用戶的代幣,例如:銷燬地址用戶的所有代幣,導致任意地址用戶的代幣爲他人所操控,這自然不是地址用戶所期望的。

5.destroyTokens()

合約地址:

https://etherscan.io/address/0xf7920b0768ecb20a123fac32311d07d193381d6f#code

利用條件:Controller地址賬戶

漏洞代碼:

如上圖所示,destroyTokens函數用於銷燬代幣,其中地址參數可控,在函數中只校驗了銷燬地址賬戶的代幣是否大於要銷燬的數量以及當前總髮行量是否大於要銷燬的數量,之後進行更新代幣總量和地址賬戶的代幣數量,不過該函數有onlyController修飾器進行修飾,下面看以下該修飾器的具體內容:

之後,通過ReadContract可以看到該controller的地址:

之後在Etherscan中可以查看到該地址對應的爲一個地址賬戶,故而該地址賬戶可以操控原合約中的任意地址用戶的代幣:

6.destroyIBTCToken

合約地址:

https://etherscan.io/address/0xb7c4a82936194fee52a4e3d4cec3415f74507532#code

利用條件:合約的owner

漏洞代碼:

如上圖所示,合約中的destroyIBTCToken是用於銷燬IBTCToken的,但是由於該函數只能被合約的owner調用,而且要銷燬的地址參數to可控,所以合約的owner可以傳入任意用戶的地址作爲參數to,之後銷燬任意地址賬戶的代幣,onlyOwner修飾器如下所示:

7.melt()

合約地址:

https://etherscan.io/address/0xabc1280a0187a2020cc675437aed400185f86db6#code

利用條件:合約的owner

漏洞代碼:

漏洞分析:如上圖所示,合約中的melt函數用於銷燬代幣的token,且該函數只能被合約的CFO調用,同時由於地址參數dst可控,故合約的CFO可以銷燬任意地址用戶的代幣,onlyCFO修飾器代碼如下所示:

onlyCFO修飾器中的_cfo由構造函數初始化:

8.Sweep()

合約地址:

https://etherscan.io/address/0x4bd70556ae3f8a6ec6c4080a0c327b24325438f3#code

利用條件:合約的owner,同時mintingFinished爲"False"

漏洞代碼:

如上圖所示,合約中的sweep函數用於轉發代幣,該函數只能被合約的owner調用,在L167行優先通過allowance進行授權操作代幣的操作,之後調用transferFrom函數,並在transferFrom函數中做了相關的減法操作,由此抵消授權操作代幣:

之後,緊接着又調用了_transfer函數:

在transfer函數中,判斷轉賬地址是否爲空、進行轉賬防溢出檢查、進行轉賬操作,通過以上邏輯可以發現由於sweep中的地址參數 _ from_to可控,而且該函數只能被合約的owner調用,所以合約的owner可以通過該函數操控任意用戶的balance,並且將其轉向任意用戶的地址或者自己的地址。

9.zero_fee_transaction

合約地址:

https://etherscan.io/address/0xD65960FAcb8E4a2dFcb2C2212cb2e44a02e2a57E#code

利用條件:合約的owner

漏洞代碼:

漏洞分析:在智能合約中常見的轉賬方式大致有兩種:一種是直接轉賬,例如常見的Transfer函數,該函數有兩個參數,一個指定代幣接受的地址,另一個爲轉賬的額度,例如:

另一種爲授權其他用戶代爲轉賬,這裏的其他用戶類似於一箇中介/媒介的作用,其他用戶可以對授權用戶授予的資金額度進行操作,常見的也是Transfer函數,不過參數個數不同而已,其中有三個參數,一個爲代爲轉賬的地址,一個爲接受代幣的地址,一個爲接受代幣的數量,例如:

瞭解了常見的兩種轉賬方式,下面我們回過頭來看一下漏洞代碼:

可以看到在函數zero_fee_transaction中進行了以下判斷:

  1. 判斷當前代爲轉賬的額度是否大於當前轉賬的數量
  2. 判斷當前轉賬的數量是否大於0
  3. 防溢出檢查

可以發現這裏未對當前函數調用者是否具備授權轉賬進行檢查(暫時忽略onlycentralAccount修飾器)以及授權額度進行檢查,只對轉賬額度以及是否溢出進行了檢查,顯然這裏是存在問題的,而且該函數沒有修飾詞進行修飾,故默認爲public,這樣一來所有人都可以調用該函數,在這裏我們能看到在不管修飾器onlycentralAccount的情況下,我們可以傳遞任意地址賬戶爲from、任意地址賬戶爲to、以及任意數量(需要小於from地址賬戶的代幣數量),之後即可無限制的從from地址賬戶轉代幣到to賬戶,直到from地址的代幣數量歸0。

下面,我們看一下onlycentralAccount修飾器對於函數調用者的身份限定:

之後,搜索central_account發現central_account由函數set_centralAccount進行賦值操作,此處的修飾器爲onlyOwner:

之後查看onlyOwner修飾器可以看到此處需要msg.sender爲owner,即合約的owner,在構造函數中進行初始化:

小結

智能合約主要依託於公鏈(例如:以太坊)來發行代幣並提供代幣的轉賬、銷燬、增發等其它邏輯功能,但用戶的代幣理應由用戶自我進行控制(通過交易增加或減少),並由用戶自我決定是否銷燬持幣數量,而不是由合約的owner或其他特殊的地址賬戶進行操控。

本文轉自Seebug,原文地址:https://paper.seebug.org/1300/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章