H4t4way's Blog

Penetration Tester | OSCP | eWPT | Burpsuite Certified | CNSS

Web3

Fallback Ethernaut Challenge

Introduction

The Ethernaut is a Web3/Solidity based wargame inspired by overthewire.org, and played in the Ethereum Virtual Machine. Each level is a smart contract that needs to be 'hacked'.
Before you start playing this Ethernaut challenge, you need to understand a few things. First, this challenge is about first becoming the owner of the smart contract in question. Only the owner of this contract can do things like withdraw money from the contract. So study the contract and look for possible ways to become its owner.

The second part of this challenge is to withdraw all the money from the contract. We will see how to do that by interacting with a contract's ABI (Application Binary Interface).

The Challenge

Analyze The Code

The first thing we can do is to get a new istance of the smart contract. It is important to know that when we press the Get New Istance button, we are not the principal of the contract. Openzeppelin will deploy the contract and thus is the owner of the contract.
Now Let's jump to analyze the code and try to understand it.

Every smart contract start with the pragma directive that specify the version of the compiler that will execute the code.

After that we can see that a Solidity library called safeMath.solhas been imported .
Open Zeppelin provides a whole set of smart contract libraries like safeMath allow us to safely perform mathematical operations in smart contracts.

Let's take some information about the contract and other data of the challenge. If we open our dev console in the browser, we can call a function to retrieve data.
With the first command, player we identify ourselves as our address, which is connected to the Ethernaut webiste..
After that , with contract and contract.address we can interact and see the abi and the address of the contract.
In final we can retrive who is the owner of the contract with the await js function.
Note (Contract address and onwer address are different, of course as the smart contract har his properly address, and the owenr addres is who deployed the contract and is the owner).

The Vulnerability

Let's see now how we can be the owner of the contract and how can withdraw money from that.

If we read the code, we see a function called contribute that is payable, which means that you can send money to this function.
The first requirement is that the amount of money sent to this contract cannot be too much, it must be < than 0.001 Ether.
After the request, we set our internal "database" of contribution allocation by adding the value that the msg.sender sent to the contribution function. After the require functions we are setting our internal "databse" of contribution mapping, adding the value that the msg.sender sent to the contribution function What's interesting here is the if statement, which says that if the amount of the contribution from the sender or the person performing the contribute function is greater > than the amount of the contribution from the owner, then the sender of the transaction that called the function becomes the owner of the contract.
Bug:
It is possible to call the contribute function many times to get a larger contribution from the owner.

After that there is something very interesting, in the final of the contract there is a function without mane that is payable and external.
This function is very special and is the fallback function.
The fallback function in Solidity is called when you send a transaction to a contract and you do not specify the name of the function or you make a mistake, this function is called. In the fallback function, the value we send to this function must be greater than 0. If the sender of this transaction has more than 0 contribution tokens/money in the mapping data structure (our dictionary), we can become the owner.

How to be the owner of the contract? We need to be sure to have some amount of contribution on the contract.


As we can see with the ABI of the contract with js, by calling the contract.contribution function, we can see that the player (us) has no contribution to the mapping data structure (our dictionary). So we need to contribute and send some money to the contract to fulfil one of the requirements of the fallback function.

Here we can maybe write a smart contract to interact with it, or we can use the dev console and play with the ABI structure and send some money to the contract.
What we do here, we call the function contribute and send 1 wei, so the status of the contrast will change, our contribution will be greater than 0, so the requirement is met.
We can see also on etherscan that the transaction was confirmed and we send 1 wei. Now we need to send some money to the contract, where so also the first requirement/condition of the fallback function will be fulfilled and we can become the owner of the contract. When we call the sendTransaction function in our dev console to send money, we do not call any function of the contract, so the fallback function is executed.
As we can see the result, before to sending the transaction, the owner of the contract was other than us(the player), now, after the transaction, we are the owner of the contract and we have completed the first step of the challenge.
In the second step, we have to withdraw all the balance of the contract to 0. We know that the withdraw function can only be called by the owner since we are now the owner, we can do it.

We can use await getBalance(contract.address) function to retrive the balance of the contract. Now we call the withdraw function, and when the transaction is confirmed we can see that we have stolen all the money of the contract.

Conslusion

In this first challenge of the Ethernaut Web3/Solidity wargame, we learned about ownership, about importing libraries, and most importantly about the fallback function. Now we just need to submit the task and complete the instance.