本文首发于深刻浅出区块链社区 原文连接:美链BEC合约漏洞技术分析原文已更新,请读者前往原文阅读git
这两天币圈链圈被美链BEC智能合约的漏洞致使代币价值几乎归零的事件刷遍朋友圈。这篇文章就来分析下BEC智能合约的漏洞程序员
咱们先来还原下攻击交易,这个交易能够在这个连接查询到。 我截图给你们看一下: github
攻击者向两个帐号转移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...
。ui
实际上对于这种整数溢出漏洞,最简单的方法是采用 SafeMath 数学计算库来避免。有趣的是BEC智能合约代码中,其实其余的都使用了SafeMath, 而关键的uint256 amount = uint256(cnt) * _value
却没有使用。 心痛程序员,也心痛韭菜。这句代码改成uint256 amount = _value.mul(uint256(cnt));
就能够防止溢出问题3d
因此在作加减乘除的时候请记得必定使用:SafeMath,代码在这里code
溢出补充说明为小专栏订阅用户福利,小专栏的文章内介绍了何时会发生上溢,何时会发生下溢,而且给出了代码事例。 你们可请前往个人小专栏阅读。
☛ 深刻浅出区块链 - 系统学习区块链,打造最好的区块链技术博客。
☛ 个人知识星球为各位解答区块链技术问题,欢迎加入讨论。
☛ 关注公众号“深刻浅出区块链技术”第一时间获取区块链技术信息。