赞
踩
实际上整形溢出并不仅仅是在智能合约中出现问题,在其他的地方也有出现。只不过我感觉我好像没咋遇到过。。。还是我太菜了。。
学习参考:
underflow-overflow
Integer Overflow and Underflow
整形溢出其实还是比较常见的,尤其是编程入门学的基本就是C语言,C语言就有这样的问题。但是自己主要还是一直在接触PHP和Python,因此对于整形溢出就没那么敏感了。
一个简单的例子:
pragma solidity <=0.9.0;
contract test1 {
uint public number=2**256-1;
function add(uint num) public {
number+=num;
}
}
uint即uint256,最大的位数是256位,所能表示的最大的整数是2^256-1。那么如果在已经表示最大的情况下又加了1呢?
成功出现了溢出,导致uint256从2^256+1溢出到了0。
原理非常的简单,那么具体该怎么利用呢?看一下ctfwiki的这个例子:
pragma solidity ^0.4.21; contract TokenSaleChallenge { mapping(address => uint256) public balanceOf; uint256 constant PRICE_PER_TOKEN = 1 ether; function TokenSaleChallenge(address _player) public payable { require(msg.value == 1 ether); } function isComplete() public view returns (bool) { return address(this).balance < 1 ether; } function buy(uint256 numTokens) public payable { require(msg.value == numTokens * PRICE_PER_TOKEN); balanceOf[msg.sender] += numTokens; } function sell(uint256 numTokens) public { require(balanceOf[msg.sender] >= numTokens); balanceOf[msg.sender] -= numTokens; msg.sender.transfer(numTokens * PRICE_PER_TOKEN); } }
注意这里的PRICE_PER_TOKEN = 1 ether
,单位换算如下:
assert(1 wei == 1);
assert(1 gwei == 1e9);
assert(1 ether == 1e18);
注意buy的函数:
require(msg.value == numTokens * PRICE_PER_TOKEN);
虽然这里的单位是1 ether,但是要知道它前面的类型是uint256,本地试试:
uint public price = 1 ether;
因此就会发现,这里的numTokens * PRICE_PER_TOKEN
存在溢出问题。要么要怎么溢出呢?这是在buy函数里,msg.value是随消息发送的 wei 的数量。因此这里是要花最少的前,买更多的Token。因此这里的numTokens取 2**256//1**18+1
,这样就可以成功以低价买到超过的Tokens,然后再sell出去,很nice。
整形下溢出就同理了,之前的重入攻击也已经遇到过了,也确实这个下溢出经常配合重入攻击来使用。
看一下ctfwiki的例子:
contract Bank {
mapping(address => uint256) public balanceOf;
...
function withdraw(uint256 amount) public {
require(balanceOf[msg.sender] - amount >= 0);
balanceOf[msg.sender] -= amount;
msg.sender.send.value(amount)();
}
}
这个例子我一开始也没看出来到底有什么问题,主要还是php和python的那种数据没有大小限制和类型限制的那种思想太根深蒂固了。
关键在于这里:balanceOf[msg.sender] - amount >= 0
。
要知道二者都是uint类型,因此无论怎么减,得到的肯定也还是uint,因此一定是>=0的,只不过会发生下溢出。因此这里其实就是无限取款了。
正确的写法:
require(balanceOf[msg.sender] >= amount)
看来还是要多注意这些,感觉自己特别容易写出这种有问题的代码。。。
整数溢出漏洞可以使用 SafeMath 库来防御,当发生溢出时会回滚交易。
学习了一波Integer Overflow and Underflow,接下来再去刷2个题目加深一下印象。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。