code-423n4 / 2024-08-superposition-validation

0 stars 0 forks source link

Re-entrancy on safeTransferFrom() function #202

Closed c4-bot-3 closed 1 month ago

c4-bot-3 commented 1 month ago

Lines of code

https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L145 https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L156

Vulnerability details

Impact

Vulnerability Details

OpenZeppelin's ERC721.sol includes callback functions to manage NFTs and prevent them from getting stuck in contracts. For NFT contracts, there exist some implicit external function calls that could be neglected by developers. They include onERC721Received function. The onERC721Received function was designed to check whether the receiver contract can handle NFTs. This function is invoked in the safeTransferFrom() of the OwnershipNFTs contract. Due to this external function call, the reentrancy could happen without being noticed by contract developer.

According to what I said above, the malicious person can abuse the same things and write in the onERC721Received function of his contract to call the safeTransferFrom() function many times in a loop in one transaction.

In the safeTransferFrom() function of the OwnershipNFTs.sol contract, the _onTransferReceived() function is called.

https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L145

    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external payable {
        _transfer(_from, _to, _tokenId);
        _onTransferReceived(msg.sender, _from, _to, _tokenId);
    }

https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L156

    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes calldata /* _data */
    ) external payable {
        _transfer(_from, _to, _tokenId);
        _onTransferReceived(msg.sender, _from, _to, _tokenId);
    }

https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L82

    function _onTransferReceived(
        address _sender,
        address _from,
        address _to,
        uint256 _tokenId
    ) internal {
        // only call the callback if the receiver is a contract
        if (_to.code.length == 0) return;

        bytes4 data = IERC721TokenReceiver(_to).onERC721Received(
            _sender,
            _from,
            _tokenId,

            // this is empty byte data that can be optionally passed to
            // the contract we're confirming is able to receive NFTs
            ""
        );

        require(
            data != IERC721TokenReceiver.onERC721Received.selector,
            "bad nft transfer received data"
        );
    }

POC :

  1. Attacker calls the safeTransferFrom() function.

  2. Due to the lack of Reentrancy Guard adherence, the attacker re-enters the safeTransferFrom() function in onERC721Received before the initial call completes.

  3. This process can be repeated, allowing the attacker to transfer token/NFT more than their allowed.

Impact Details

An attacker can transfer a large amount of tokens/NFTs using reentrancy.

References

https://samczsun.com/the-dangers-of-surprising-code/

https://blog.openzeppelin.com/reentrancy-after-istanbul

https://eips.ethereum.org/EIPS/eip-721

https://medium.com/amber-group/position-exchanges-re-entrancy-loophole-explained-ef176a0fd987

https://solodit.xyz/issues/re-entrancy-issue-for-erc1155-fixed-consensys-bridge-mutual-markdown

https://solodit.xyz/issues/h-03-an-attacker-can-hijack-any-erc1155-token-he-rents-due-to-a-design-issue-in-renft-via-reentrancy-exploitation-code4rena-renft-renft-git

https://www.rareskills.io/post/where-to-find-solidity-reentrancy-attacks

https://blocksecteam.medium.com/revest-finance-vulnerabilities-more-than-re-entrancy-1609957b742f

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

Tools Used

Manual Analysis

Recommended Mitigation Steps

Add a reentrancy guard (nonReentrant())

Assessed type

Reentrancy