Ethernaut 题库闯关 #16 — Preservation

Ethernaut题库闯关连载第16篇。

今天这篇是Ethernaut 题库闯关连载的第16篇,难度等级:较难。

挑战#16:Preservation

此挑战的合约(Preservation)利用一个库来存储两个不同时区的时间。构造函数为每个要存储的时间创建两个库的实例。 我们的目标是获取合约的所有权。

Preservation 合约的源代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.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) 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;
  }
}

在查看解题思路之前,可以先自己想一想,自己会怎么做?

要完成本关,我们需要了解delegatecall 的用法,知道delegatecall 的执行上下文,以及了解不同的数据类型是如何转换的。

研究合约

合约本身很小,但挑战的复杂性相当高,但很有趣, 先看下LibraryContract.sol的代码:

// Simple library contract to set the time
contract LibraryContract {
    // stores a timestamp
    uint256 storedTime;

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

它有一个uint256 storedTime状态变量和一个setter函数setTime,用用户的输入更新状态变量,相当简单和直接。

Preservation主合约的代码不重复贴了,它有五个不同的状态变量,让我们进行一下说明,了解我们如何能获得它的所有权。

  • address public timeZone1Library第一个时区库的地址
  • address public timeZone2Library 第二个时区库的地址
  • address public owner 所有者的地址
  • uint256 storedTime 由两个时区库中的一个存储的时间。
  • bytes4 constant setTimeSignature 时区库中setTime函数的签名。这不是一个真正的状态变量,因为有 "constant "(常量)这个关键字

合约的constructor使用两个address类型的输入参数来设置两个库的地址,并将所有者设置为msg.sender

合约有两个不同的函数:

  • 函数setFirstTime(uint256 _timeStamp) public
  • 函数setSecondTime(uint256 _timeStamp) public

它们的功能相同,只是在两个不同的时区库上执行相同的代码,让我们看看其中一个的代码:


function setFirstTime(uint256 _timeStamp) public {
    timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Ethernaut CTF
Ethernaut CTF
信奉 CODE IS LAW.