【区块链】【智能合约】美链攻击分析以及安全库的使用

1.美链攻击过程

美链代币BEC为发行在以太坊上的ERC20代币,其具体合约的代码在该链接中合约代码
向美链发起攻击的交易链接为攻击交易hash

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;

美链攻击的具体流程分为以下四步:
1.首先构造一个_value值,使得_receivers.len() * _value产生向上溢出,结果为一个极小值amount。比如使用_receivers.len()为2,_value值为2**255,那么在上述代码中计算得到的amount值为0。
2.amount,value通过require验证。
3.在msg.sender中减去amount数量的代币。
4.为每个_receivers账户增加value数量的代币。
其中value为一个极大值,相当于对美链的BEC代币进行了增发,对应的_receivers账户可以获取大量BECtoken。

2.solidity中上溢与下溢

在solidity中变量进行+、-、*运算时会产生溢出,如加法运算和乘法运算会产生向上溢出,减法运算产生向下溢出。如2**255变量乘以2,获得的结果为0。具体溢出情况可参考以下合约代码:

pragma solidity 0.4.20;
contract TestFlow {
    uint256 public zero = 0;
    uint256 public max = 2**256 - 1;
    uint256 public mm = 2**255;

    function subUnderFlow() public constant returns (uint) {
        uint256 a =  zero - 1;
        return a;
    }

    function addOverFlow() public constant returns (uint) {
        uint256 a =  max + 1;
        return a;
    }

    function mulOverFlow() public constant returns (uint) {
        uint256 a =  mm * 2;
        return a;
    }
}

3.定义安全库

在对数字进行运算时,要采用安全函数,保证结果正确且不发生溢出。安全的数学运算库的使用如下所示。
第一步:导入SafeMath库文件

pragma solidity >=0.4.22 <0.6.0;
 
/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error
 */
 
library SafeMath {
    /**
     * @dev Multiplies two unsigned integers, reverts on overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }
 
        uint256 c = a * b;
        require(c / a == b);
 
        return c;
    }
 
    /**
     * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
 
        return c;
    }
 
    /**
     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;
 
        return c;
    }
 
    /**
     * @dev Adds two unsigned integers, reverts on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
 
        return c;
    }
 
    /**
     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
     * reverts when dividing by zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}

第二步,引用

pragma solidity >=0.4.22 <0.6.0;
 
import "./safemath.sol";
 
contract jisuan{
    uint a=2;
    uint b=5;
    uint c=8;
    //引入safemath库
    using SafeMath for uint256;
    
    //加法
    function addNum()public view returns(uint d){
        d=a.add(b);
    }
    //减法
    function subNum()public view returns(uint d){
        d=b.sub(a);
    }
    //乘法
    function mulNum()public view returns(uint d){
        d=a.mul(b);
    }
    //除法
    function divNum()public view returns(uint d){
        d=c.div(a);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值