The goal of this level is for you to hack the basic token contract below.

You are given 20 tokens to start with and you will beat the level if you somehow manage to get your hands on any additional tokens. Preferably a very large amount of tokens.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Token {
    mapping(address => uint256) balances;
    uint256 public totalSupply;

    constructor(uint256 _initialSupply) public {
        balances[msg.sender] = totalSupply = _initialSupply;
    }

    function transfer(address _to, uint256 _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 (uint256 balance) {
        return balances[_owner];
    }
}

First, we need to get an instance for the challenge:

  1. After connecting our Metamask wallet, click on “Get New Instance”:

    alt text

  2. After approving the transaction, the contract address will be shown in the browser’s javascript console:

    alt text

As the challenge description says, we are given 20 tokens and we need to gather a large amount of them. The transfer function takes a uint256 as an argument and takes that amount of tokens from the sender and sends them to the specified address. Logically, it first checks that the sender has enough balance… using this check:

balances[msg.sender] - _value >= 0

Sounds good, right? Sadly (or luckily!), the EVM has underflows and overflows. So, if we send 21 as the amount to transfer, the EVM will perform 20 - 21 = -1 == 2^256 - 1, which is greater than 0, passing the require check. But we cannot set the target address to our address; otherwise, we would stay still. The solution is to write any other address as the transfer destination. It does not need to be a real one nor controlled by us:

cast send 0x0bAE5c3950ee11ca661Ca3b47bA202cDFcB03208 "transfer(address,uint256)" 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 21 --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY

Now we can verify that it worked:

cast call 0x0bAE5c3950ee11ca661Ca3b47bA202cDFcB03208 "balanceOf(address)" 0x12c5Da011f95E229Ba45f732e8f79608444D76b9 --rpc-url $SEPOLIA_RPC_URL

alt text

And this completes the challenge :D

alt text