Ethernaut题库闯关连载第16篇。
今天这篇是Ethernaut 题库闯关连载的第16篇,难度等级:较难。
此挑战的合约(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));...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!