Detailed Walkthrough

First, notice that LibraryContract modifies the state at slot 0. Moreover, it allows external parties to replace storedTime with any other 32 byte variable.

Hint: What if we replaced slot 0 with a contract address?

uint storedTime;

function setTime(uint _time) public {

storedTime = _time;

}

Second, notice you can invoke setTime from Preservation.sol through the delegatecall in setFirstTime .

This means that you can modify slot 0 in Preservation.sol, i.e. change the address of timeZone1Library !

Hint: What if you can repoint timeZone1Libary to a malicious contract that modifies other state variables in Preservation.sol?

Part I — Create a malicious contract

In this first part, let’s create the malicious contract that timeZone1Libary will repoint toward.

Notice that Preservation.sol stores owner address at slot 2. Let’s create a malicious contract that has the same storage layout:

contract BadLibraryContract {

address public timeZone1Library; // SLOT 0

address public timeZone2Library; // SLOT 1

address public owner; // SLOT 2

uint storedTime; // SLOT 3

...

2. Create a setTime function inside BadContract which updates slot 2 with your wallet address.

function setTime(uint _time) public {

owner = msg.sender;

}

Note: it is important to use the same function name as in LibraryContract because Preservation.sol invokes functions by name:

bytes4(keccak256(“setTime(uint256)”));

3. Deploy BadLibraryContract to Ropsten in Remix, and save its instance address. Then, calculate the uint(address) to derive the input variable for:

setFirstTime(uint _timeStamp)

Part II — Update timeZone1Library to the malicious contract

In Remix, access your level instance. Invoke setFirstTime with the converted uint(address) . Double check that timeZone1Library is now your malicious contract address.

Part III — Gain Ownership