19 - Alien Codex

storage layout

Ethernaut Level19: Alien Codexarrow-up-right

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

import '../helpers/Ownable-05.sol';

contract AlienCodex is Ownable {

  bool public contact;
  bytes32[] public codex;

  modifier contacted() {
    assert(contact);
    _;
  }
  
  function make_contact() public {
    contact = true;
  }

  function record(bytes32 _content) contacted public {
    codex.push(_content);
  }

  function retract() contacted public {
    codex.length--;
  }

  function revise(uint i, bytes32 _content) contacted public {
    codex[i] = _content;
  }
}

Goal of this level

  • claim ownership

What you should know before

Solution

chevron-rightKey to solve this problem 🔑hashtag
  • owner is located at slot0. So will store player address to slot0 (owner and contact are packed into slot0)

  • codex[i] is located at keccak256(1) + i

We will exploit arithmetic underflow here.

Storage has 2**256 slots (slot 0 ~ slot 2**256-1).

Inital value of codex.length is 0.

So when we call retract() this will cause arithmetic overflow, making the value of codex.length 2**256 - 1.

Now solidity thinks of codex as an array with 2**256 - 1 elements which lets us access any slot of storage.

codex[0] is located at slot keccak256(1).

codex[i] is at slot keccak256(1) + i, so we will find i that satisfies keccak256(1) + i === 2**256.

So i should be

Since uint256 variable cannot store 2**256, we subtract keccak256(1) from 2**256 - 1 and add 1 back.

Done! 😎

Last updated