曲速未來 :以太坊智能合約編碼安全之Call注入區(qū)塊鏈
區(qū)塊鏈安全咨詢公司曲速未來表示:Solidity作為一種用于編寫以太坊智能合約的圖靈完備的語言,除了常見語言特性以外,還提供了調(diào)用/繼承其他合約的功能。在call、delegatecall、callcode三個函數(shù)來實現(xiàn)合約之間相互調(diào)用及交互。
前言
區(qū)塊鏈安全咨詢公司 曲速未來 表示:Solidity作為一種用于編寫以太坊智能合約的圖靈完備的語言,除了常見語言特性以外,還提供了調(diào)用/繼承其他合約的功能。在call、delegatecall、callcode三個函數(shù)來實現(xiàn)合約之間相互調(diào)用及交互。正是因為這些靈活各種調(diào)用,也導致了這些函數(shù)被合約開發(fā)者“濫用”,甚至“肆無忌憚”提供任意調(diào)用“功能”,導致了各種安全漏洞及風險。
上述代碼就是一個典型的存在call注入問題直接導致重入漏洞的demo。
2016年7月,The DAO被攻擊者使用重入漏洞取走了所有代幣,損失超過60億,直接導致了eth的硬分叉,影響深遠。
2017年7月20日,Parity Multisig電子錢包版本1.5 的漏洞被發(fā)現(xiàn),使得攻擊者從三個高安全的多重簽名合約中竊取到超過15萬ETH ,其事件原因是由于未做限制的 delegatecall 函數(shù)調(diào)用了合約初始化函數(shù)導致合約擁有者被修改。
2018年6月16日,有人在先知大會上提到了一種新的攻擊場景——call注?,主要介紹了利用對call調(diào)用處理不當,配合一定的應用場景的一種攻擊手段。
接著于 2018年6月20日,ATN代幣團隊發(fā)布《ATN抵御黑客攻擊的報告》,報告指出黑客利用call注入攻擊漏洞修改合約擁有者,然后給自己發(fā)行代幣,從而造成 ATN 代幣增發(fā)。
Solidity 的三種調(diào)用函數(shù)
在Solidity中,call函數(shù)簇可以實現(xiàn)跨合約的函數(shù)調(diào)用功能,其中包括call、delegatecall和callcode三種方式。
以下是Solidity中call函數(shù)簇的調(diào)用模型:
這些函數(shù)提供了靈活的方式與合約進行交互,并且可以接受任何長度、任何類型的參數(shù),其傳入的參數(shù)會被填充至32字節(jié)最后拼接為一個字符串序列,由EVM解析執(zhí)行。
在函數(shù)調(diào)用的過程中,Solidity中的內(nèi)置變量msg會隨著調(diào)用的發(fā)起而改變,msg保存了調(diào)用方的信息包括:調(diào)用發(fā)起的地址,交易金額,被調(diào)用函數(shù)字符序列等。
三種調(diào)用方式的異同點
call: 最常用的調(diào)用方式,調(diào)用后內(nèi)置變量msg的值會修改為調(diào)用者,執(zhí)行環(huán)境為被調(diào)用者的運行環(huán)境(合約的 storage)。
delegatecall: 調(diào)用后內(nèi)置變量msg的值不會修改為調(diào)用者,但執(zhí)行環(huán)境為調(diào)用者的運行環(huán)境。
callcode: 調(diào)用后內(nèi)置變量msg的值會修改為調(diào)用者,但執(zhí)行環(huán)境為調(diào)用者的運行環(huán)境。
delegatecall濫用問題
delegatecall: 調(diào)用后內(nèi)置變量msg的值不會修改為調(diào)用者,但執(zhí)行環(huán)境為調(diào)用者的運行環(huán)境。
原理
在智能合約的開發(fā)過程中,合約的相互調(diào)用是經(jīng)常發(fā)生的。開發(fā)者為了實現(xiàn)某些功能會調(diào)用另一個合約的函數(shù)。比如下面的例子,調(diào)用一個合約A的test()函數(shù),這是一個正常安全的調(diào)用。
但是在實際開發(fā)過程中,開發(fā)者為了兼顧代碼的靈活性,往往會有下面這種寫法:
這將引起任意 public 函數(shù)調(diào)用的問題:合約中的delegatecall的調(diào)用地址和調(diào)用的字符序列都由用戶傳入,那么完全可以調(diào)用任意地址的函數(shù)。
除此之外,由于delegatecall的執(zhí)行環(huán)境為調(diào)用者環(huán)境,當調(diào)用者和被調(diào)用者有相同變量時,如果被調(diào)用的函數(shù)對變量值進行修改,那么修改的是調(diào)用者中的變量。
call 安全問題
call: 最常用的調(diào)用方式,調(diào)用后內(nèi)置變量msg的值會修改為調(diào)用者,執(zhí)行環(huán)境為被調(diào)用者的運行環(huán)境。
call注入是一種新的攻擊場景,原因是對call調(diào)用處理不當,配合一定的應用場景的一種攻擊手段。
call 注入原理
call 調(diào)用修改 msg.sender 值
通常情況下合約通過call來執(zhí)行來相互調(diào)用執(zhí)行,由于call在相互調(diào)用過程中內(nèi)置變量msg會隨著調(diào)用方的改變而改變,這就成為了一個安全隱患,在特定的應用場景下將引發(fā)安全問題。
外部用戶通過call函數(shù)再調(diào)用合約函數(shù):
高度自由的 call 調(diào)用
在某些應用場景下,調(diào)用函數(shù)可以由用戶指定;下面是call函數(shù)的調(diào)用方式:
從上面可以看出,call函數(shù)擁有極大的自由度:
1.對于一個指定合約地址的call調(diào)用,可以調(diào)用該合約下的任意函數(shù)
2.如果call調(diào)用的合約地址由用戶指定,那么可以調(diào)用任意合約的任意函數(shù)
為了便于理解,可以將智能合約中的call函數(shù)類比為其他語言中的eval函數(shù),call函數(shù)相當于給用戶提供了隨意調(diào)用合約函數(shù)的入口,如果合約中有函數(shù)以msg.sender作為關(guān)鍵變量,那么就會引發(fā)安全問題。
call 函數(shù)簇調(diào)用自動忽略多余參數(shù)
call函數(shù)簇在調(diào)用函數(shù)的過程中,會自動忽略多余的參數(shù),這又額外增加了call函數(shù)簇調(diào)用的自由度。下面的例子演示call自動忽略多余參數(shù):
例子中test()函數(shù)僅接收一個uint256的參數(shù),但在callFunc()中傳入了三個參數(shù),由于call自動忽略多余參數(shù),所以成功調(diào)用了test()函數(shù)。
callcode 安全問題
callcode: 調(diào)用后內(nèi)置變量msg的值會修改為調(diào)用者,但執(zhí)行環(huán)境為調(diào)用者的運行環(huán)境。
由于callcode同時包含了call和delegatecall 的特性,通過上文對call和delegatecall的安全問題進行了分析和舉例,可以得出的結(jié)論是call和delegatecall存在的安全問題將同時存在于callcode中,這里不再進行詳細的分析。
總結(jié)
針對文中所提到的安全隱患,區(qū)塊鏈安全咨詢公司 曲速未來 建議:
1.call、callcode、delegatecall調(diào)用的自由度極大,并且call會發(fā)生msg值的改變,需要謹慎的使用這些底層的函數(shù);同時在使用時,需要對調(diào)用的合約地址、可調(diào)用的函數(shù)做嚴格的限制。
2.call與callcode調(diào)用會改變msg的值,會修改msg.sender為調(diào)用者合約的地址,所以在合約中不能輕易將合約本身的地址作為可信地址。
3.delegatecall與callcode會拷貝目標代碼到自己的環(huán)境中執(zhí)行,所以調(diào)用的函數(shù)應該做嚴格的限制,避開調(diào)用任意函數(shù)的隱患。
4.智能合約在部署前必須通過嚴格的審計和測試。
本文內(nèi)容由 曲速未來安全咨詢公司編譯,轉(zhuǎn)載請注明。 曲速未來提供包括主鏈安全、交易所安全、交易所錢包安全、DAPP開發(fā)安全、智能合約開發(fā)安全等相關(guān)區(qū)塊鏈安全咨詢服務。
1.TMT觀察網(wǎng)遵循行業(yè)規(guī)范,任何轉(zhuǎn)載的稿件都會明確標注作者和來源;
2.TMT觀察網(wǎng)的原創(chuàng)文章,請轉(zhuǎn)載時務必注明文章作者和"來源:TMT觀察網(wǎng)",不尊重原創(chuàng)的行為TMT觀察網(wǎng)或?qū)⒆肪控熑危?br>
3.作者投稿可能會經(jīng)TMT觀察網(wǎng)編輯修改或補充。