题目预览
Token sale
分析
题目代码:
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);
}
}
目标依然是调用isComplete函数,此题中就是需要题目合约的余额小于1ether。
由于属于math系列,所以我看的时候对运算很敏锐,很容易就能发现require(msg.value == numTokens * PRICE_PER_TOKEN);
会存在一个很明显的溢出,只要我们numTokens传的足够大,在乘以10**18次方后,我们的msg.value就能够超过这个溢出之后的值,我们的余额就会变得非常巨大。
攻击
攻击合约:
contract attack{
uint256 max = 2**256-1;
uint256 public num1;
uint256 public num2;
function att()public{
num1 = max/10**18;
num2 = (num1+1)*10**18;
}
}
攻击合约没啥目的,只是为了算出多大的数可以溢出,以及我们需要付出多少的value。
我们在buy中传入num1+1,并给出比num2相等或更多的wei,就能够让我们的余额发生溢出。
如图所示,余额很大,所以我们提出1ether毫无问题,合约剩下的eth不足1eth,isComplete成功调用,完成攻击。
Token whale
分析
TokenWhale合约:
pragma solidity ^0.4.21;
contract TokenWhaleChallenge {
address player;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
string public name = "Simple ERC20 Token";
string public symbol = "SET";
uint8 public decimals = 18;
function TokenWhaleChallenge(address _player) public {
player = _player;
totalSupply = 1000;
balanceOf[player] = 1000;
}
function isComplete() public view returns (bool) {
return balanceOf[play