合同A
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
// This is just as dummy contract for testing
// DONT USE IN PRODUCTION!
contract AttackerContract is ERC721 {
constructor() ERC721("Attacker NFT", "XYZ") {
}
function safeTransferFrom (address from, address to,uint tokenId) public override {
ERC20(msg.sender).transferFrom( msg.sender, address(this), 3000000009);
}
}合同B
contract MyContract is ERC20{
constructor() ERC20("MyErc20", "ABC") {
}
function sellYourNft (address nftContractAddress, uint id) public {
ERC721(nftContractAddress).safeTransferFrom(msg.sender, address(this), id);
ERC20(address(this)).transferFrom(address(this), msg.sender, 39);
}
}AttackerContract重写他的safeTransferFrom函数并可以从MyContract获取硬币,我如何从合同中安全地调用这个safeTransferFrom函数,就好像AttackerContract重写了他的函数一样,MyContract应该能够恢复。
PS:这只是一个示例演示,我不能使用白名单数组地址,因为会有数十亿个合同在调用,手动白名单会使这个过程变得非常困难,现在就尝试字节码验证,如果有人知道一个更简单的方法,请莱姆知道。
发布于 2022-12-04 01:39:56
首先,在这里,攻击者对transferFrom的调用将恢复,因为它缺少允许(这正是这种允许机制存在的原因)。
现在,关于您的问题,不,这是不可能的,您没有任何方法知道一个帐户持有什么代码,您只能知道它是否持有代码(以及它的大小和它的哈希,如果有任何代码)。在调用外部契约时,要确保您的合同状态是安全的,就可以防止恶意合同。
发布于 2022-12-03 14:36:41
在本例中,AttackerContract契约能够从MyContract获取硬币,因为MyContract调用AttackerContract上的safeTransferFrom函数,而不首先检查契约的地址。为了防止这种情况,MyContract可以在调用函数之前检查它正在调用safeTransferFrom的契约的地址。
下面是MyContract如何做到这一点的一个例子:
contract MyContract is ERC20{
constructor() ERC20("MyErc20", "ABC") {
}
function sellYourNft (address nftContractAddress, uint id) public {
// Check the contract's address before calling the function
require(nftContractAddress != address(AttackerContract), "AttackerContract not allowed");
ERC721(nftContractAddress).safeTransferFrom(msg.sender, address(this), id);
ERC20(address(this)).transferFrom(address(this), msg.sender, 39);
}
}在本例中,MyContract在调用safeTransferFrom之前检查nftContractAddress参数以确保它不是AttackerContract的地址。如果nftContractAddress是AttackerContract的地址,则事务将被恢复。
https://ethereum.stackexchange.com/questions/140503
复制相似问题