Two Contracts, One Bug

Summary:

A critical vulnerability was identified in both Async Art’s NFTAuction and SuperRare’s SuperRareAuctionHouse contracts. The former had approximately ~30k at risk, while the latter faced a potential loss of ~430k. Funds in both protocols remain secure. I reached out to Async through Discord and SuperRare via the SEAL 911 service.

Root Causes:

1. Doesn’t account for non-standard NFTs deviating from the ERC-721 specification.

2. Lacks the ability to differentiate between auctions.

3. Absence of validation ensuring that the currency in a bid matches the currency in the auction.

Async Art’s Vulnerability & Exploit:

Observations:

1. In Async’s NFTAuction contract, a seller can create an auction with a custom NFT and subsequently withdraw that NFT during the auction’s duration, then start another auction using the same NFT. This action results in the previous auction being superseded.

2. A bidder can bid on an NFT without it being actively auctioned. The contract doesn’t check the currency provided by the bidder during bid acceptance, necessitating sellers to be cautious when accepting bids.

My observations made me wonder if it would be possible to drain the contract of its ETH/ERC20s and it turns out that one can. Let’s see how.

One can use a custom NFT and valueless ERC20 to drain the NFTAuction contract of all its ETH. One does this by creating a sale using a valueless ERC20, an ERC20 one created, as the token, and a custom NFT one created as the NFT for sale. After the transaction to create the sale finishes one bids on his own NFT. The valueless ERC20s are sent to the contract and one is recorded as the highest bid. The sale price is greater than one’s bid. The bid price matches the amount one wants to withdraw from the NFTAuction contract. After the bid transaction finishes one calls the create sale function. Now the modifier should prevent one from doing this and in a standard NFT contract it would, however, the custom NFT one created shows one as the owner of the NFT. This allows one to pass new values to the sale. This time one sets the token to address(0) which is ETH. One also sets the buyNow price to the bid price. When the create sale function sees that the highestBid matches the buy now price it sends the bid price to one and the custom NFT.

After confirming this exploit with a Proof of Concept (PoC), I notified Async. Their team, leveraging my PoC, successfully secured ~30k worth of ETH, considering the NFTAuction is non-upgradable.

SuperRare’s Vulnerability & Exploit:

Upon reviewing SuperRare’s code, I noticed striking similarities to the aforementioned Async vulnerability.

Observations:

Instead of creating a valueless ERC20 one has to use an approved ERC20. This is important since this is the crux of the exploit. Fortunately, SuperRare uses its own RARE token which one can easily acquire. Instead of placing a bid and then creating an auction one converts an offer to an auction via convertOfferToAuction().

Once the offer is converted to an auction one can call the configureAuction() passing in similar parameters as one did when calling convertOfferToAuction() except one passes ETH as currency instead of RARE. This overwrites the previous auction created by the convertOfferToAuction() call but doesn’t overwrite the bid created in convertOfferToAuction(). When the auction ends one calls endAuction() and since endAuction() doesn’t verify that the currency in the bid matches the currency in the auction one receives the balance of ETH in SuperRareBazaar. Three addresses are used for this exploit; bidder, exploiter, and exploiter1.

Exploit Flow:

  1. Operator creates custom NFT and mints to exploiter address.

  2. From the bidder’s address, the Operator places an offer on said NFT using the SuperRare token as currency.

  3. From the exploiter’s address, the operator converts the offer to an auction. This creates the first auction. The custom NFT ignores the transferFrom call since it comes from SuperRareBazaar.

  4. The operator transfers the NFT from exploiter to exploiter1.

  5. From exploiter1 he configures the auction using similar parameters except he uses ETH instead of SuperRare’s RARE token as currency. This overwrites the previous auction but doesn’t overwrite the bid that was created when the offer was converted to an auction.

  6. Once the auction ends the operator calls endAuction() from any address he owns and receives about ~211.16 ETH or $315,881. This leaves the contract with about ~0.000749ETH or $1.25.

After validating this vulnerability using a local PoC and noticing the contract was active with ~500k at risk, I reached out to SuperRare. Despite initial communication challenges, the SEAL 911 service provided the necessary bridge to connect with SuperRare’s team. They promptly rectified the vulnerability and deployed the necessary fixes.

Links To Reports:

AsyncArt:

SuperRare:

Subscribe to ayeslick
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.