SWC智能合约漏洞库

SWC-128/利用区块gas限制的DoS攻击

部署智能合约或调用智能合约中的函数时,根据完成这些合约需要多少计算量,执行这些操作 始终需要一定数量的gas。以太坊网络指定了区块gas限制上限,并且区块中包含的所有交易的 总和不能超过该阈值。

在中心化应用程序中无害的编程模式,当执行功能的成本超过区块限制时,也可能会导致智能合约 中的服务拒绝。例如修改大小未知的数组,当数组变大后,就会导致拒绝服务的情况。

CWE漏洞分类

CWE-400:不受控制的资源消耗

整改方案

建议谨慎使用可能随时间而增长很大的数组。应避免在整个数据结构中循环的操作。

如果必须遍历未知大小的数组,则应计划它可能占用多个块,因此需要进行多个交易。

参考文献

示例合约

dos_address.sol

pragma solidity ^0.4.25;

contract DosGas {

    address[] creditorAddresses;
    bool win = false;

    function emptyCreditors() public {
        if(creditorAddresses.length>1500) {
            creditorAddresses = new address[](0);
            win = true;
        }
    }

    function addCreditors() public returns (bool) {
        for(uint i=0;i<350;i++) {
          creditorAddresses.push(msg.sender);
        }
        return true;
    }

    function iWin() public view returns (bool) {
        return win;
    }

    function numberCreditors() public view returns (uint) {
        return creditorAddresses.length;
    }
}

dos_address.yaml

description: DoS Gas Limit reached when trying to empty the array of addresses for winning the game
issues:
- id: SWC-128
  count: 1
  locations:
  - bytecode_offsets:
      '0x53aef779087c1829c3990fbf300aaafe4ccbd3328e8b6a630c7484b8c921aa8e': [408]
    line_numbers:
      dos_address.sol: [10]

dos_number.sol

pragma solidity ^0.4.25;

contract DosNumber {

    uint numElements = 0;
    uint[] array;

    function insertNnumbers(uint value,uint numbers) public {

        // Gas DOS if number > 382 more or less, it depends on actual gas limit
        for(uint i=0;i<numbers;i++) {
            if(numElements == array.length) {
                array.length += 1;
            }
            array[numElements++] = value;
        }
    }

    function clear() public {
        require(numElements>1500);
        numElements = 0;
    }

    // Gas DOS clear
    function clearDOS() public {

        // number depends on actual gas limit
        require(numElements>1500);
        array = new uint[](0);
        numElements = 0;
    }

    function getLengthArray() public view returns(uint) {
        return numElements;
    }

    function getRealLengthArray() public view returns(uint) {
        return array.length;
    }
}

dos_number.yaml

description: DoS Gas Limit in array empty and optionally in for loop
issues:
- id: SWC-128
  count: 1
  locations:
  - bytecode_offsets: {}
    line_numbers:
      dos_number.sol: [29]

dos_simple.sol

pragma solidity ^0.4.25;

contract DosOneFunc {

    address[] listAddresses;

    function ifillArray() public returns (bool){
        if(listAddresses.length<1500) {

            for(uint i=0;i<350;i++) {
                listAddresses.push(msg.sender);
            }
            return true;

        } else {
            listAddresses = new address[](0);
            return false;
        }
    }
}

dos_simple.yaml

description: DoS Gas Limit reaches when try to empty the array of addresses
issues:
- id: SWC-128
  count: 1
  locations:
  - bytecode_offsets: {}
    line_numbers:
      dos_simple.sol: [16]