How to Solve the First Task of the Ethernaut Game

Written by kamilpolak | Published 2022/01/20
Tech Story Tags: solidity | smart-contracts-solidity | solidity-hack | hack-solidity | smart-contracts | smart-contract-security | ethernaut | software-development

TLDRThe aim of the Ethernaut game is to reduce the balance of the contract to 0.001 ether. To take ownership we need to use the 'contribute' function to reach a balance higher than 1000 ethers. The owner's address is different from than the player's address. To send the transaction you need to confirm your operation in MetaMask and pay some small gas. Once the transaction will be executed you should see confirmation as above. So we can verify that we contributed to the contract and claim all funds.via the TL;DR App

In this article, I will walk you through how to solve the first task of the Ethernaut game.

The aim of the task is to :

  • claim ownership of the contract

  • reduce the balance of the contract to 0

Let's start with the analysis of the contract that we need to hack.

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

Looking at the constructor we can see that contribution of the owner was set to 1000 ethers. This means that if we want to take ownership of the contract we need to call the contribute function until we reach a balance higher than 1000 ethers.

Considering that we cannot send more than 0.001 ether in one call it will take a lot of time.

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

Another way to take ownership of the contract is to use the receive fallback function. The fallback function is executed if none of the other functions match the function identifier or no data was provided with the function call.

Note that only one unnamed function can be assigned to a contract and it is executed whenever the contract receives plain ether without any data. To receive ether and add it to the total balance of the contract, the fallback function must be marked payable.

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

As you can see, to take ownership we need to meet to conditions: msg.value > 0 && contributions[msg.sender] > 0

After that, we can call withdraw function to claim all funds.

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

Before let's check who is the owner of the contract.

As you can see the owner's address is different from than player's address.

Now we can send some amount of ether to the contract. Note, you cannot send more than 0.001 ether.

To send the transaction you need to confirm your operation in MetaMask and pay some small gas. Once the transaction will be executed you should see confirmation as above.

We can also verify that we contributed to the contract.

Without going into details the length:3 is the confirmation. So now we need to fulfill the second condition of the fallback function. To do that we need to call the function and send some value.

Since this is a fallback function we used the specific function sendTransaction

After that, we can check the contract owner. As you can see now the ownership was assigned to the player's address. So we claimed the ownership!

Now we can withdraw ethers. Before we will check the current balance.

Let's call the withdraw function to get all ethers.

When you check the contract balance you will see that it is 0. So we achieved the second goal.

First published here.


Written by kamilpolak | I am a huge enthusiast of cryptocurrency and blockchain technology.
Published by HackerNoon on 2022/01/20