美鏈BEC合約漏洞技術分析

本文首發於深刻淺出區塊鏈社區 原文連接:美鏈BEC合約漏洞技術分析原文已更新,請讀者前往原文閱讀git

這兩天幣圈鏈圈被美鏈BEC智能合約的漏洞致使代幣價值幾乎歸零的事件刷遍朋友圈。這篇文章就來分析下BEC智能合約的漏洞程序員

漏洞攻擊交易

咱們先來還原下攻擊交易,這個交易能夠在這個連接查詢到。 我截圖給你們看一下: github

攻擊者向兩個帳號轉移57896044618...000.792003956564819968個BEC,至關於BEC憑空進行了一個巨大的增發,幾乎致使BEC價格瞬間歸零。 下面咱們來分析下這個攻擊過程。數組

合約漏洞分析

咱們先來看看BEC智能合約的代碼, BEC在合約中加入一個批量轉帳的函數,它的實現以下:函數

function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
    uint cnt = _receivers.length;
    uint256 amount = uint256(cnt) * _value;
    require(cnt > 0 && cnt <= 20);
    require(_value > 0 && balances[msg.sender] >= amount);

    balances[msg.sender] = balances[msg.sender].sub(amount);
    for (uint i = 0; i < cnt; i++) {
        balances[_receivers[i]] = balances[_receivers[i]].add(_value);
        Transfer(msg.sender, _receivers[i], _value);
    }
    return true;

這個函數的做用是,調用者傳入若干個地址和轉帳金額,在通過一些條件檢查以後,對msg.sender的餘額進行減操做,對每個對每個傳入的地址進行加操做,以實現BEC的轉移。 問題出在 uint256 amount = uint256(cnt) * _value; 這句代碼,當傳入值_value過大時(接近uint256的取值範圍的最大值),uint256 amount = uint256(cnt) * _value計算時會發生溢出,致使amount實際的值是一個很是小的數(此時amount再也不是cnt * _value的實際值),amount很小,也使得後面對調用者餘額校驗可正常經過(即require(_value > 0 && balances[msg.sender] >= amount)語句經過)。學習

咱們來結合實際攻擊交易使用的參數來分析一下:區塊鏈

batchTransfer的參數_value值爲16進制的800000000000000000000...,參數_receivers數組的大小爲2,相乘以後恰好可超過uint256所能表示的整數大小上限,引起溢出問題amount實際的值爲0,後面的轉帳操做實際上msg.sender的餘額減0, 而對兩個帳號進行了加16進制的800000000000000000000...,最終的結果是至關於增發了2 * 16進制的800000000000000000000...ui

實際上對於這種整數溢出漏洞,最簡單的方法是採用 SafeMath 數學計算庫來避免。有趣的是BEC智能合約代碼中,其實其餘的都使用了SafeMath, 而關鍵的uint256 amount = uint256(cnt) * _value卻沒有使用。 心痛程序員,也心痛韭菜。這句代碼改成uint256 amount = _value.mul(uint256(cnt));就能夠防止溢出問題3d

因此在作加減乘除的時候請記得必定使用:SafeMath,代碼在這裏code

溢出補充說明

溢出補充說明爲小專欄訂閱用戶福利,小專欄的文章內介紹了何時會發生上溢,何時會發生下溢,而且給出了代碼事例。 你們可請前往個人小專欄閱讀。

深刻淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術博客。

☛ 個人知識星球爲各位解答區塊鏈技術問題,歡迎加入討論。

☛ 關注公衆號「深刻淺出區塊鏈技術」第一時間獲取區塊鏈技術信息。

相關文章
相關標籤/搜索