• <option id="cacee"><noscript id="cacee"></noscript></option>
  • <table id="cacee"><noscript id="cacee"></noscript></table>
  • <td id="cacee"></td>
  • <option id="cacee"></option>
  • <table id="cacee"></table>
  • <option id="cacee"><option id="cacee"></option></option>
  • <table id="cacee"><source id="cacee"></source></table><td id="cacee"><rt id="cacee"></rt></td>
    <option id="cacee"><option id="cacee"></option></option>
     找回密碼
     立即注冊

    掃一掃,登錄網站

    首頁 自媒體 查看內容
    • 3530
    • 0
    • 分享到

    淺析AMR智能合約批量轉賬溢出漏洞

    2018-7-12 19:12

    來源: bugxio

    日前,互聯網爆出AMR合約存在高危安全風險的交易,通過研究發現,AMR合約存在批量轉賬溢出漏洞:當合約實現批量轉賬功能時,容易在計算通證增加量時發生溢出漏洞,BUGX.IO安全團隊經過研究分析發現,同類漏洞仍在以太坊里面部分存在,以下為漏洞分析過程:


    「原理」

     /**

         * @dev Function is used to perform a multi-transfer operation. This could play a significant role in the Ammbr Mesh Routing protocol.

         *  

         * Mechanics:

         * Sends tokens from Sender to destinations[0..n] the amount tokens[0..n]. Both arrays

         * must have the same size, and must have a greater-than-zero length. Max array size is 127.

         * 

         * IMPORTANT: ANTIPATTERN

         * This function performs a loop over arrays. Unless executed in a controlled environment,

         * it has the potential of failing due to gas running out. This is not dangerous, yet care

         * must be taken to prevent quality being affected.

         * 

         * @param destinations An array of destinations we would be sending tokens to

         * @param tokens An array of tokens, sent to destinations (index is used for destination->token match)

         */

        function multiTransfer(address[] destinations, uint[] tokens) public returns (bool success){

            // Two variables must match in length, and must contain elements

            // Plus, a maximum of 127 transfers are supported

            assert(destinations.length > 0);

            assert(destinations.length < 128);

            assert(destinations.length == tokens.length);

            // Check total requested balance

            uint8 i = 0;

            uint totalTokensToTransfer = 0;

            for (i = 0; i < destinations.length; i++){

                assert(tokens[i] > 0);

                totalTokensToTransfer += tokens[i];

            }

            // Do we have enough tokens in hand?

            assert (balances[msg.sender] > totalTokensToTransfer);

            // We have enough tokens, execute the transfer

            balances[msg.sender] = balances[msg.sender].sub(totalTokensToTransfer);

            for (i = 0; i < destinations.length; i++){

                // Add the token to the intended destination

                balances[destinations[i]] = balances[destinations[i]].add(tokens[i]);

                // Call the event...

                emit Transfer(msg.sender, destinations[i], tokens[i]);

            }

            return true;

        }

    `totalTokensToTransfer += tokens[i];` 這一句溢出,溢出后,totalTokensToTransfer 變小了,從而繞過了`assert (balances[msg.sender] > totalTokensToTransfer);` 的判斷,這樣就能花極少的token , 任意增加目標地址的 token 。

    攻擊者的攻擊行為: 

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

    可以看到這兩個 tokens 值都是 uint256 最大值的一半,兩個加起來剛好溢出變為 0。

     

    「漏洞復現」

    1. 部署AMR 合約

    2. 因為需要攻擊者token 數量大于0,所以先使用管理員賬戶給攻擊者地址充 token。

    "0x14723a09acff6d2a60dcdf7aa4aff308fddc160c",1

     

    使用`balanceOf` 可以查看到:

    0x14723a09acff6d2a60dcdf7aa4aff308fddc160c有balances為1

     

    3. 使用漏洞溢出攻擊

    這里需要兩個地址,一個是攻擊者,另一個為其它地址,這里設置 0 地址就行。

    執行 multiTransfer 就行。

    ["0x14723a09acff6d2a60dcdf7aa4aff308fddc160c","0x0000000000000000000000000000000000000000"],["57896044618658097711785492504343953926634992332820282019728792003956564819968","57896044618658097711785492504343953926634992332820282019728792003956564819968"]

    4. 查看攻擊者余額

    可以看到攻擊者余額已經變得非常大。

     

    「修復方案」

    1. 使用safeMath 即可解決此問題。

    2. 以太坊的大部分合約是以transfer 的形式進行轉賬,此方法也可以避免溢出問題。

    function multiTransfer(address[] recipients, uint256[] amounts) public {

        require(recipients.length == amounts.length);

        for (uint i = 0; i < recipients.length; i++) {

            transfer(recipients[i], amounts[i]);

        }

    }

     

    「深入探索」

    在對以太坊上做進一步探索的時候,我們發現批量轉賬功能或者批量充值功能的實現主要有以下幾種形式:

    1. 合約部署時使用批量充值功能

    此功能在構造函數中實現,只有部署的時候能夠使用,所以不可利用。

    /// @title Gnosis token contract

    /// @author Stefan George -

    contract GnosisToken is StandardToken {


        /*

         *  Token meta data

         */

        string constant public name = "Gnosis Token";

        string constant public symbol = "GNO";

        uint8 constant public decimals = 18;


        /*

         *  Public functions

         */

        /// @dev Contract constructor function sets dutch auction contract address and assigns all tokens to dutch auction.

        /// @param dutchAuction Address of dutch auction contract.

        /// @param owners Array of addresses receiving preassigned tokens.

        /// @param tokens Array of preassigned token amounts.

        function GnosisToken(address dutchAuction, address[] owners, uint[] tokens)

            public

        {

            if (dutchAuction == 0)

                // Address should not be null.

                throw;

            totalSupply = 10000000 * 10**18;

            balances[dutchAuction] = 9000000 * 10**18;

            Transfer(0, dutchAuction, balances[dutchAuction]);

            uint assignedTokens = balances[dutchAuction];

            for (uint i=0; i<owners.length; i++) {

                if (owners[i] == 0)

                    // Address should not be null.

                    throw;

                balances[owners[i]] += tokens[i];

                Transfer(0, owners[i], tokens[i]);

                assignedTokens += tokens[i];

            }

            if (assignedTokens != totalSupply)

                throw;

        }

    }


    2. 管理者調用批量轉賬功能

    function batchTransfer(address[] _to, uint[] _value) checkAccess("currencyOwner) returns (bool) {

            if (_to.length != _value.length) {

                Error(7, tx.origin, msg.sender);

                return false;

            }

            uint totalToSend = 0;

            for (uint8 i = 0; i < _value.length; i++) {

                totalToSend += _value[i];

            }

            ElcoinDb db = _db();

            if (db.getBalance(msg.sender) < totalToSend) {

                Error(8, tx.origin, msg.sender);

                return false;

            }

            db.withdraw(msg.sender, totalToSend, 0, 0);

            for (uint8 j = 0; j < _to.length; j++) {

                db.deposit(_to[j], _value[j], 0, 0);

                Transfer(msg.sender, _to[j], _value[j]);

            }

            return true;

        }

    即使有漏洞,但受到管理者權限控制,所以一般不可利用。

    3. 公開函數中的批量轉賬功能

    function transferMulti(address[] _to, uint256[] _value) public returns (uint256 amount){

            require(_to.length == _value.length);

            uint8 len = uint8(_to.length);

            for(uint8 j; j<len; j++){

                amount += _value[j];

            }

            require(balanceOf[msg.sender] >= amount);

            for(uint8 i; i<len; i++){

                address _toI = _to[i];

                uint256 _valueI = _value[i];

                balanceOf[_toI] += _valueI;

                balanceOf[msg.sender] -= _valueI;

                Transfer(msg.sender, _toI, _valueI);

            }

        }

    我們看到了不少這種形式的寫法,通過`amount += _value[j];` 的增加,溢出后繞過了`require(balanceOf[msg.sender] >= amount);` 的檢測。


    「漏洞影響范圍」

    研究此漏洞原理后,我們使用自研的審計系統"以太坊沖擊波",對以太坊上的合約進行整體監測,發現了以下合約均存在此漏洞。

     

    合約名稱

    地址

    AMMBR (AMR)

    0x96c833e43488c986676e9f6b3b8781812629bbb5

    Beauty Coin (BEAUTY)

    0x623afe103fb8d189b56311e4ce9956ec0989b412

    Beauty Coin (Beauty)

    0xb5a1df09ccaa8197d54839c2c9175ec32b560151

    Car Token (CRT)

    0xdf4b22695eeb4a7a1cf9a42162285ce782b8427a

    KoreaShow

    0x330bebabc9a2a4136e3d1cb38ca521f5a95aec2e

    Pasadena Token (PSDT)

    0x80248bb8bd26f449dea5b4d01faf936075b7111d

    Rocket Coin (XRC)

    0x6fc9c554c2363805673f18b3a2b1912cce8bfb8a

    Sinphonim (SPM)

    0x715423a818f1f9a85c66d81d2809e0a4dadf07f3

    Social Chain (SCA)

    0xb75a5e36cc668bc8fe468e8f272cd4a0fd0fd773

     

    版權申明:本內容來自于互聯網,屬第三方匯集推薦平臺。本文的版權歸原作者所有,文章言論不代表鏈門戶的觀點,鏈門戶不承擔任何法律責任。如有侵權請聯系QQ:3341927519進行反饋。
    相關新聞
    發表評論

    請先 注冊/登錄 后參與評論

      回頂部
    • <option id="cacee"><noscript id="cacee"></noscript></option>
    • <table id="cacee"><noscript id="cacee"></noscript></table>
    • <td id="cacee"></td>
    • <option id="cacee"></option>
    • <table id="cacee"></table>
    • <option id="cacee"><option id="cacee"></option></option>
    • <table id="cacee"><source id="cacee"></source></table><td id="cacee"><rt id="cacee"></rt></td>
      <option id="cacee"><option id="cacee"></option></option>
      妖精视频