IOP _ ThunderNFT 34955 - [Smart Contract - Critical] Nfts of type may be stolen by updating an order
Submitted on Sun Sep 01 2024 19:18:04 GMT-0400 (Atlantic Standard Time) by @SimaoAmaro for IOP | ThunderNFT
Report ID: #34955
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/ThunderFuel/smart-contracts/tree/main/contracts-v1/thunder_exchange
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
The ThunderExchange contract supports depositing nfts of erc115 type, which was also confirmed by the team on discord. It's possible to place an order of just 1 amount of a certain NFT, update it to an amount of the balance of the ThunderExchange of the given erc1155 NFT and then cancel it, stealing all the nfts of the corresponding collection and sub id of the ThunderExchange.
Vulnerability Details
ThunderExchange::place_order(), allows specifying a sell order of any amount.
ThunderExchange::update_order(), when the side is Sell, does not perform any validation. All validation of the order is performed in StrategyFixedPriceSale::_validate_updated_order(), which does not check the amount. Thus, it's possible to modify the amount of the sell order without sending more erc1155 NFTs to the ThunderExchange.
The full flow, given in the POC is:
Place a sell order of an erc1155 nft with an amount of 1.
Update the sell order to an amount equal to the balance of the given nft in the
ThunderExchange.Cancel the order and receive all the corresponding nft balance.
Impact Details
All erc1155 nft given by the specified collection and token id are stolen from the ThunderExchange.
References
https://github.com/ThunderFuel/smart-contracts/blob/main/contracts-v1/thunder_exchange/src/main.sw#L124
Proof of concept
Proof of Concept
To run a proof of concept, the exchange was modified to allow a maker of type Contract, as Sway tests do not support pranking an EOA.
Additionally, 2 new contracts were created, the user contract simulating the attacker and a erc1155 contract, simulating an erc1155 token.
The full changes were pushed to a github repository which can be shared with the team if requested.
The main test file is the following:
The user contract is:
The erc1155 is the same as the erc721, but the mint function had the checks removed to allow more than 1 coin per token id:
Last updated
Was this helpful?