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.