LooksRare Aggregator contest - ktg's results

An NFT aggregator protocol.

General Information

Platform: Code4rena

Start Date: 08/11/2022

Pot Size: $60,500 USDC

Total HM: 6

Participants: 72

Period: 5 days

Judge: Picodes

Total Solo HM: 2

Id: 178

League: ETH

LooksRare

Findings Distribution

Researcher Performance

Rank: 67/72

Findings: 1

Award: $36.34

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

36.3434 USDC - $36.34

Labels

bug
downgraded by judge
grade-b
QA (Quality Assurance)
sponsor acknowledged
edited-by-warden
Q-20

External Links

Lines of code

https://github.com/code-423n4/2022-11-looksrare/blob/main/contracts/ERC20EnabledLooksRareAggregator.sol#L34-L36

Vulnerability details

Impact

  • A user can buy NFT for free in edge cases.
  • A user can withdraw all stuck tokens.

Proof of Concept

Currently the function to buy NFT with ERC20 tokens in file ERC20EnabledLooksRareAggregator.sol is implemented like this:

function execute( TokenTransfer[] calldata tokenTransfers, ILooksRareAggregator.TradeData[] calldata tradeData, address recipient, bool isAtomic ) external payable { if (tokenTransfers.length == 0) revert UseLooksRareAggregatorDirectly(); _pullERC20Tokens(tokenTransfers, msg.sender); aggregator.execute{value: msg.value}(tokenTransfers, tradeData, msg.sender, recipient, isAtomic); }

This is TokenTransfer struct, which contains ERC20 currency and amount the buyer deposit for buying NFT.

struct TokenTransfer { uint256 amount; // ERC20 transfer amount address currency; // ERC20 transfer currency }

Function execute will call _pullERC20Tokens and transfer ERC20 token from the caller to the aggregator. However, the tradeData.order.currency is the one used for purchase NFT, not tokenTransfer.currency, and there is no checking if these 2 currencies actually match.

struct TradeData { ... BasicOrder[] orders; // Orders to be executed by the marketplace .... } struct BasicOrder { .... address currency; // The order's currency, address(0) for ETH ... }

This can lead to user can buy NFT for free or withdraw all stuck tokens:

  • Suppose there are some token A stuck in aggregator (and enough to buy some NFT)

  • The buyer create tradeData.order with token A but input tokenTransfer.currency as token B

  • He then call execute and receive NFT without paying (since the amount of token A stuck in aggregator pay for him), and receive full token B refund.

Tools Used

Manual source code review.

I recommend checking inputs between transferData and tokenTransfer to make sure that tokenTransfer's tokens must contain all tokens from transferData.orders.

#0 - Picodes

2022-11-21T14:03:37Z

I guess this is the current implementation to allow for maximal flexibility when integration exchanges.

Also:

  • all tokens are refunded to the originator at the end of execute so it's not any issue to send incorrect tokens
  • there shouldn't be any stuck funds on the contract, otherwise the finding is correct everyone can use them, or then can be freely withdraw as shown by #277

#1 - c4-judge

2022-11-21T14:04:27Z

Picodes changed the severity to QA (Quality Assurance)

#2 - 0xhiroshi

2022-11-24T12:26:41Z

If any ERC20 tokens are sent to the contract by accident that are not for trades, we have decided it's free for all.

#3 - c4-sponsor

2022-11-24T12:27:02Z

0xhiroshi marked the issue as sponsor acknowledged

#4 - c4-judge

2022-12-11T13:17:30Z

Picodes marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter