My Avatar

毕竟话少

业精于勤荒于嬉,行成于思毁于随!

智能合约审计-整数溢出

2020年1月15日 星期三, 发表于 合肥

如果你对本文有任何的建议或者疑问, 可以在 这里给我提 Issues, 谢谢! :)

描述:变量在参与运算的过程中,运算结果超出了变量类型所能表示的范围,导致实际存储的计算结果出错

核心问题:非预期的整数溢出将导致智能合约运行出错,影响合约的可靠性和安全性

基础知识

整数溢出的分类

整数上溢

整数下溢

整数的分类

有符号数(int)

无符号数(uint)

Solidity中的整数类型

int8/int16/int24/…/int256(int8表示-127~127)

uint8/uint16/uint24/…/uint256(uint8表示0~255)

漏洞合约分析

pragma solidity ^0.4.24;

contract IntOverflow{

    function addNumber(uint a, uint b) public constant returns (uint){
        uint c;
        c = a+b;
        return c;
    }

}

漏洞点:由于这里a、b的数值类型为uint256,a、b的最大值为2^256-1,当超过这个最大值即回到起点0从新开始,所以输出c值存在整数溢出

BTCR下溢增持漏洞分析

function distributeBTR(address[] address) onlyOwner {
    for (uint i = 0; i < addresses.length; i++){
        balances[owner] -= 2000 * 10**8;
        balances[address[i]] += 2000 * 10**8;
        Transfer(owner, addresses[i], 2000 * 10**8);
    }
}

漏洞点:通过在distributeBTR函数中调用onlyOwner管理员向指定的用户列表地址进行批量打款,这里就存在一个减法下溢漏洞,当balances[owner]小于2000 * 10**8的时候,这个时候balances[owner]就为负数,但是在uint数的表示范围之内,balances[owner]值就是一个超级大的数,管理员可以通过这个漏洞对自己的balances进行增持。

整数溢出分析

漏洞预防

require()/assert()/revert()

直接调用SafeMath函数

using safeMath for uint256

SafeMath库

pragma solidity ^0.4.24;

library SafeMath {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b);

    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b > 0); 
    uint256 c = a / b;

    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a);
    uint256 c = a - b;

    return c;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a);

    return c;
  }


  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0);
    return a % b;
  }
}