# Ethernaut 16: Alien Codex **Published by:** [0xbanky](https://paragraph.com/@banky/) **Published on:** 2022-09-09 **URL:** https://paragraph.com/@banky/ethernaut-16-alien-codex ## Content 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; } } InvestigationThe 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 getawait 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.SolutionThe 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 ## Publication Information - [0xbanky](https://paragraph.com/@banky/): Publication homepage - [All Posts](https://paragraph.com/@banky/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@banky): Subscribe to updates - [Twitter](https://twitter.com/0xbanky): Follow on Twitter