# Ethernaut 16: Alien Codex

By [0xbanky](https://paragraph.com/@banky) · 2022-09-09

---

This is my solution to the Alien Codex ethernaut challenge. During experimentation, I found that the EVM prevents exploits like this from happening in current versions. The contract for the problem is as follows

    // 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;
      }
    }
    

Investigation
=============

The objective is to take ownership of the contract. As we can see, the contract inherits from `Ownable`. `Ownable` has one item in storage which is the `address` of the deployer of the contract. Thus, the `_owner` variable will be in the first storage slot. Since an `address` is only 20 bytes, the first storage slot gets packed in with the `bool` , `contact` that is defined after it. Sure enough, checking the storage for the first slot, we get

    await web3.eth.getStorageAt(contract.address, 0)
    "0x000000000000000000000001da5b3fb76c78b6edee6be8f11a1c31ecfb02b272" 
    

Here, we can see that the address that deployed the contract is `da5b3fb76c78b6edee6be8f11a1c31ecfb02b272` and the boolean `contact` is set to `true` which is the first 1. Note that when tightly packing, the EVM stores values from left to right.

The contract can record new values into the `codex` by calling the `record` function. This simply pushes a new value into the array. To remove values from the array, this contract does something interesting with `retract`. Instead of trying to remove the actual value, it just reduces the length of the array. This makes it so that the ABI will throw an error when trying to access values beyond the length. This is all well and good, but there is no check for underflow here which is a potential source for an exploit.

The final function in the contract is `revise`. This simply allows the caller to set any value in the `codex` array.

Solution
========

The key breakthrough to tackling this problem is to understand that storage slots wrap around - similar to unsigned integers. This means that after slot 2^256 - 1, the next slot is slot 0. This means that if we can set a high enough value in the array, the array can be used to effectively write to any slot in the contract.

The first step to take here is to “open” up the array to the entire storage space of the contract. By forcing an underflow by calling `retract` when there are no values, the length of the array gets set to 0xfff…fff. The address of the 0 slot can then be found by simply getting the difference between this and the array slot location and adding 1. Setting this new index with `revise` solves the challenge

---

*Originally published on [0xbanky](https://paragraph.com/@banky/ethernaut-16-alien-codex)*
