Ethernaut Lvl 5 Token Walkthrough: How to abuse arithmetic underflows and overflows

This is a in-depth series around Zeppelin team’s smart contract security puzzles. I’ll give you the direct resources and key concepts you’ll need to solve the puzzles 100% on your own.

This levels requires you to grow your contract’s 20 tokens to even more tokens.


Integer Overflow and Underflows

Like C and C++, Solidity is a lower level coding language that doesn’t have failsafes for handling storage limitations. This is different than what Ruby and Python developers might be used to.

Ethereum’s smart contract storage slot are each 256 bits, or 32 bytes. Solidity supports both signed integers, and unsigned integers uint of up to 256 bits.

This means your arithmetic operations are prone to underflow and overflow errors, when your numbers flow under or over the allocated bits of storage.

Note: The largest possible uint256 is equal to 115792089237316195423570985008687907853269984665640564039457584007913129639935- hopefully sufficient to represent what you need

Here’s a visualization of the code snippet above:

This makes contracts that handle arithmetic operators on their own vulnerable. In general, we inherit math operators from the safemath.sol library.


Detailed Walkthrough

  1. Notice Telephone.sol’s changeOwner function checks if (tx.origin != msg.sender). Seems like we can successfully trigger this function with scenario 3:

2. Create a phone contract, Telephony to pose as Contract A. Instantiate Contract B, your Telephone.sol, inside Telephony:

contract Telephony {
Telephone public phone = Telephone(YOUR_INSTANCE_ADDR_HERE);
//TODO...
}

3. Create a changeOwner function inside Telephony that calls the changeOwner function in Telephone, i.e. play the game of Telephone.

function changeOwner(address _owner) public {
phone.changeOwner(_owner);
}

4. Notice await contract.owner() in console now indicate your user wallet is the owner!