13 - Gatekeeper One

type conversion and gasleft()

Ethernaut Level13: Gatekeeper Onearrow-up-right

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

Goal of this level

  • call enter successfuly without revert

What you should know

  • Type Casting (see below)

  • gaseleft()

  • bitwise & operation

Type Casting

byte

1) When casted to bigger type

bytes20 -> bytes32

2) When casted to smaller type

bytes20 -> bytes8

-> discards lower-order bits

uint

1) When casted to bigger type

2) When casted to smaller type

-> discards higher-order bits

Solution

gateThree

This value satisfies all three conditions.

-> Because of 3rd condition, we will do bitwise & operation.

gateTwo

Because the minimum amount of a transaction is 21,000 gas, we will just add 3k more gas on it (3k here is just an arbitrary number considering the rest of the operations) and loop it until it passes the condition of gateTwo.

Done! 😎

Last updated