Ethernaut Series - 05 (Token)

Ethernaut Series - 05 (Token)

·

2 min read

Concept

The emphasis of this level is on the concept of overflow and underflow which is a concern for contracts written in solidity version <0.8.

Basically, there are different types of integer data type. For example, uint256, int256, uint8, int8. Each of these types have a range of numbers that they can store which ranges from 0 to 2^n -1. So this range for respective types will be:

  • uint8: from 0 to 255

  • uint16: from 0 to 65,535

  • uint32: from 0 to 4,294,967,295

  • uint256: from 0 to 1.157920892373162e+77

The catch is that, there were no checks in solidity versions < 0.8 which is why, when a subtraction operation was performed where the value of a respective data type were to go below 0, for example 0-1, then it would translate to type(uint256).max;.

A SafeMath library was also created for the very purpose to provide functions which implement these checks by themselves. However, following solidity version >0.8, we do not need to worry about this since solidity implements these checks itself.


Code

The code provided to us is as follows:

// 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];
    }
}

As we can see, the transfer() function is of interest here. When we will make a transfer to any contract with a value greater than our balance, the variable storing this value will underflow, thus bringing the value of our balance to type(uint256).max.


Proof-Of-Concept

To do so, we simply open the console and execute the following command:

await contract.transfer("0xE0D7c84bb170C27C1388c97EC1e78a8bD5E24fE3", 21)

p.s. you can use any address.

This marks the completion of our level.

Did you find this article valuable?

Support Mrigendra's Blog by becoming a sponsor. Any amount is appreciated!