zoukankan      html  css  js  c++  java
  • 美链BEC合约漏洞技术分析

    最新内容会更新在主站深入浅出区块链社区
    原文链接:美链BEC合约漏洞技术分析

    这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈。这篇文章就来分析下BEC智能合约的漏洞

    漏洞攻击交易

    我们先来还原下攻击交易,这个交易可以在这个链接查询到。
    我截图给大家看一下:

    攻击者向两个账号转移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...

    实际上对于这种整数溢出漏洞,最简单的方法是采用 SafeMath 数学计算库来避免。有趣的是BEC智能合约代码中,其实其他的都使用了SafeMath, 而关键的uint256 amount = uint256(cnt) * _value却没有使用。
    心痛程序员,也心痛韭菜。这句代码改为uint256 amount = _value.mul(uint256(cnt));就可以防止溢出问题

    所以在做加减乘除的时候请记得一定使用:SafeMath,代码在这里

    溢出补充说明

    Solidity最大可以处理256位数字, 最大值为 2**256 - 1, 对(2**256 - 1) 加1的结果会溢出归0。2**255 乘2也同样会溢出归0。
    对无符号类型最小值是零,对零做减1会得到 (2**256 - 1)。

    我们用一段代码验证一下:

    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;
        }
    }
    
    

    合约部署和运行,大家可请前往我的小专栏阅读。

    知识星球深入浅出区块链做好的区块链技术问答社区,欢迎来提问,作为星球成员福利,成员可加入区块链技术付费交流群。
    深入浅出区块链 - 系统学习区块链,打造最好的区块链技术博客。

  • 相关阅读:
    2981 大整数加法
    1160 矩阵的最大值(指针专题)
    1159 最大的两个数(指针专题)
    1127 矩阵乘积
    1126 布尔矩阵的奇偶性
    1125 上三角矩阵的判断
    1124 两个有序数组合并
    1123 最佳校友
    1122 小明的调查作业
    1121 电梯
  • 原文地址:https://www.cnblogs.com/tinyxiong/p/8949683.html
Copyright © 2011-2022 走看看