Ethernaut Level 3 Coin Flip [Foundry-Hardhat]

Ethernaut Level 3 Coin Flip [Foundry-Hardhat]

ยท

3 min read

The Ethernaut-Solutions repository contains the solutions using Foundry and Hardhat.

This level shows a weakness in pseudo-randomness in smart contracts.

Objectives

  • Guess the correct outcome of a coin flip 10 times in a row

    If the guess is wrong, the counter resets. To exploit the contract, we have to look at the source of randomness used in flipping the coin.


Analysis

Randomness in computer systems, and especially in Ethereum, is difficult to achieve. Ethereum Blockchain is a deterministic Turing machine, meaning there is no randomness involved. To generate randomness, developers often rely on block properties such as block number, blockhash, timestamp, etc. These variables may look random, but they can be exploited if the inputs are known. This is very much possible due to the public nature of blockchain. Also, miners and validators can, to some extent, manipulate these values, especially the timestamp.

Take a look at the level 3 contract CoinFlip. There is only one function, flip(), that accepts your guess as a boolean. The contract keeps track of consecutive guesses in the consecutiveWins state variable. consecutiveWins is increased by 1 for each correct guess and resets to zero if your guess is wrong.

Let's go through the flip() function and evaluate how the side is determined.

The first line is the source of randomness that uses blockhash and block.number.

uint256 blockValue = uint256(blockhash(block.number - 1));

blockValue is calculated using block.number-1 i.e. previous blockhash. This is deterministic. Information about the block can be easily accessed.

uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;

blockValue is divided by FACTOR to get coinFlip. If the value of coinFlip is 1, then side will be set to true; otherwise, it will be set to false. The value of FACTOR is available in the contract. Since we already have all the required inputs, we can calculate the value of side easily. We can create a contract that will do the same calculation and guess the value of side.


Exploit

Let's create a contract that will hack the level.

Go to the Remix IDE and create the following contract.

On line 16, put the instance address in place of PUT_INSTANCE_ADDRESS_HERE. You can get the instance address by typing instance in the browser console. The contract simulates the exact coin flipping logic.

Call hack() 10 times. The function will submit the calculated guess directly to the level's instance. This will always increase consecutveWins counter in the level's instance because the function sends only correct guesses.

Make sure to call the function at least 10 times.

Submit the instance.

Level passed!!!๐Ÿ˜„


Key Takeaways

Generating randomness on Ethereum is difficult. All the data on Ethereum is public so anyone can easily guess the random value and hack your contract.

You can use Oracles as the source of randomness. Oracles are applications that source, verify, and transmit external information (i.e. information stored off-chain) to smart contracts running on the blockchain.

The following are common use-cases for oracles in Ethereum:

  • Retrieving financial data

  • Generating verifiable randomness

  • Getting outcomes for events

  • Automating smart contracts

The Ethernaut-Solutions repository contains the solutions using Foundry and Hardhat.

Solution using Foundry:-

Solution using Hardhat:-

More Levels

Did you find this article valuable?

Support Chirag Patil by becoming a sponsor. Any amount is appreciated!

ย