paint-brush
How to Solve the Ethernaut Game's Level 5: Tokenby@kamilpolak
3,533 reads
3,533 reads

How to Solve the Ethernaut Game's Level 5: Token

by Kamil PolakJanuary 27th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In challenge 5 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. To win this challenge we need to trigger an overflow or underflow. The overflow is a situation when an integer (signed integer) reaches its byte size. The next element added will return the first variable element. If you subtract 1 from a variable that is 0, it will change the value to 255. There are two options to use Openppelin to use all the mathematical operators.

Coin Mentioned

Mention Thumbnail
featured image - How to Solve the Ethernaut Game's Level 5: Token
Kamil Polak HackerNoon profile picture

In challenge 5 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.

Let's first look at the given smart 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];
  }
}


This is a simple contract that allows to transfer and check the current balance of the contract. In the constructor, we can specify the total supply and assign it to a person who deployed the contract.


To hack this contract first you need to understand the concept of integer underflow and overflow. The overflow is a situation when uint (unsigned integer) reaches its byte size. Then the next element added will return the first variable element.


In the case of underflow, if you subtract 1 from a uint8 that is 0, it will change the value to 255.

Let me explain with an example. Note: The hardhat console library is necessary to log to the console in Remix.


pragma solidity ^ 0.6.0 ;

import "hardhat/console.sol";

contract Test {
    constructor () public  {
        uint8 small = 0;
        decrease--;

        uint8 large = 255;
        increase++;
        console.log(small); // prints 255
        console.log(large); // prints 0
    }
}


If you run this code in Remix, be sure to use compiler version 0.6. As you can see we have a variable named decrease with value a 0. If we subtract 1 from that variable we end up with 255.


If you want to know more about integer underflow and overflow I have an additional article you can read: Integer Overflow and Underflow in Solidity


Let's move to our smart contract. To win this challenge we need to trigger an overflow or underflow. Keep in mind that we received 20 tokens.



All we need to do is:

  • transfer 21 (more than 20) tokens to another address,
  • this will cause an underflow, setting our balance to 255


To execute transfer the function you need to take some real contract address. You can pick a one from Etherscan.io


How to prevent underflow and overflow in Solidity?

There are two options. The first is to use OpenZeppelin's SafeMath library that automatically checks for overflows in all the mathematical operators. The second one is to use 0.8 Solidity version where overflow and underflow will cause a revert.


Also Published Here