Blog

This challenge starts with little help from the introduction. What we know is that there is an interface class named Building with just one method. interface Building { function isLastFloor(uint) external returns (bool); } What I know about interfaces is that they are used to more or less force us to build out our contracts (or classes in OO-based languges) with implementations of the functions listed in the interace. In other words, interfaces force or help us to follow a certain standard we need to follow. This is handy when creating more standardized code like ERC-20 …

One of the first hacks I heard about while learning Solidity was a re-entrancy hack. This type of attack is the reason why Ethereum Classic came into existence, after a hard fork undid the 50 million dollar hack of TheDAO . Looking at this level's contract, we need to focus on the following function. function withdraw(uint _amount) public { if(balances[msg.sender] >= _amount) { (bool result,) = msg.sender.call{value:_amount}(""); if(result) { _amount; } balances[msg.sender] -= _amount; } } The dangerous line here is the …

Level 9 of the Ethernaut game contains a contract that receives Ether and makes the biggest donor the next King. The old king receives the money prize and the new king will wait until somebody tries to become the next king. Classic Ponzi game indeed. This is what King Of The Ether did, before getting hacked . In this level, we are asked to prevent someone from becoming the next king. After looking at the contract, the function we should focus on is receive(). receive() external payable { require(msg.value >= prize || msg.sender == owner); king.transfer(msg.value); …

Unlock the vault to pass the level! That's clear enough. When we look at the code of the given contract we can see that a password is set on creation of the contract via the constructor method. Unlocking the vault can only be done if you know the password. The password variable is defined as private but any blockchain developer knows that private only affects the scope of the variable and has nothing to do with making the contents of that variable private or hidden. Any data in your contract is public and can be read by anyone. // SPDX-License-Identifier: …

Level 7 presents us with an empty contract containing nothing more than some ASCII-art. The only hint we get is that some contracts won't accept our money. contract Force {/* MEOW ? /\_/\ / ____/ o o \ /~____ =ø= / (______)__m_m) */} This level probably let's you search around for ways a contract can receive money. You probably know about payable functions and fallback methods, but the contract doesn't seem to contain any of these. I tried logging the full contract ABI on Ethernaut, but it seems to be empty so that's where …

This level zooms in on a special Solidity method called delegatecall () . When deploying the level instance on Ethernaut, we can only work with the Delegation contract, which is the instance we get. The delegatecall() method lets you call a function on another contract while keeping the original data context. Another way to think of it is that you are trusting the called contract with the state of your calling contract. In this level, we need to understand that we will be running the function pwn() of the called contract as if that code was executed inside the calling …

This level zooms in on the concept of overflows and underflows of variables and the risks that come with that. I haven't recently encountered the issues we'll be talking about here, simply because Ethereum 0.8 (the version I've spent most time in) doesn't show the same behaviour as version 0.6 in which Ethernaut has been written. Let's dive in. The hint we get at the top of this level is to look up what an odometer is. An odometer is the milage counter in your car and it will look somewhat like this. Back in the day these meters used to be analog and had a maximum of six …

This level focuses in on the difference between tx.origin and msg.sender , which sometimes get mixed up. Let's take a look at the code in this level first. // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract Telephone { address public owner; constructor() public { owner = msg.sender; } function changeOwner(address _owner) public { if (tx.origin != msg.sender) { owner = _owner; } } } What we see is that the owner is the msg.sender. When calling the changeOwner() function, we can set the owner to another address but only …

This level is all about randomness. When writing solidity code there isn't a native way to generate random numbers. Also keep in mind that all your clever ways to try to generate randomness in your code is publicly visible for all on the blockchain. There are of course solutions like using Chainlink Oracles, that can generate and return truly random numbers for you, but that is outside of the scope of this Ethernaut level. When looking at the code we can see that the coin flip result is being calculated based on some given inputs like a FACTOR variable and the current block number. …

This level of Ethernaut is actually really simple, but shows us how easy some of the early hacks in the Ethereum ecosystem were executed. In earlier versions of the language the constructor would be a function with the same name of the contract. If for example you had a contract named Fallout then your constructor method might have been named function Fallout(). In the constructor Solidity developers will often set the owner to be the creator of the contract, the msg.sender . That way the owner will be the person who created the contract. There's a known hack (dating back …