我是刚接触过稳健性的人,但我多次读到应该避免使用tx.origin
&应该使用msg.sender
。在solidity 页面中有一个给出的演示。上面写着:-
不要使用tx.origin进行授权。假设你有这样的钱包合同:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
address owner;
constructor() {
owner = msg.sender;
}
function transferTo(address payable dest, uint amount) public {
// THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin
require(tx.origin == owner);
dest.transfer(amount); // .transfer is a global variable
}
}
现在有人骗你把以太送到这个攻击钱包的地址:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
interface TxUserWallet {
function transferTo(address payable dest, uint amount) external;
}
contract TxAttackWallet {
address payable owner;
constructor() {
owner = payable(msg.sender);
}
receive() external payable {
TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance); // **LINE 1**
}
}
现在,我想知道第1行将如何从TxUserWallet
中抽走全部资金。我认为transfer()
是一个全局变量,它将在攻击钱包的dest
中传递要处理的数量。.transfer()
将如何触发合同TxAttackWallet
的receive()
函数。其次,在TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
行中,为什么我们要将它写成TxUserWallet(msg.sender)
,比如为什么我们在合同名称之后添加(msg.sender),以及通过编写msg.sender.balance
传递什么值?
发布于 2022-08-31 10:21:43
接收功能由接收eth触发。
该行中的msg.sender是易受攻击的钱包/合同的地址。钱包名是该类型契约的实例或接口,它需要该地址来实例化它以与其交互。
msg.sender.balance正在从易受攻击的契约中获得平衡,所以攻击契约可以知道它能从易受攻击的契约中转移多少。
该行调用易受攻击契约的transferTo函数,传递攻击者控制的to
地址,以及易受攻击契约的整个余额的amount
。
钱包合同试图限制它的transferTo被任何人使用,而不是它的所有者,方法是确保只有它的所有者可以用tx.origin而不是msg.sender调用该函数。
tx.origin将永远保持不变。即启动交易链的EOA。msg.sender不保持不变,在本例中,当攻击契约调用transferTo函数时,将更改为攻击契约地址。
如果攻击契约的所有者被诱骗在攻击契约上发起事务,则攻击契约可以调用易受攻击契约上的transferTo函数,而易受攻击合同的检查仍然会结束它来自其所有者的检查,因为它使用tx.origin作为检查。它将允许转移。
如果它使用msg.sender进行检查,它将“看到”该函数不是由所有者直接调用的,而是由合同调用的,因此不允许传输,因为攻击契约地址不是易受攻击的合同所有者。
对于要降级的攻击场景,易受攻击的契约需要一个回退/接收函数,这样就可以为其提供资金并取得平衡。是的,可以用强制发送来代替,但那是愚蠢的。
https://ethereum.stackexchange.com/questions/134714
复制相似问题