Blur Exchange contest - Lambda's results

An NFT exchange.

General Information

Platform: Code4rena

Start Date: 11/11/2022

Pot Size: $36,500 USDC

Total HM: 5

Participants: 62

Period: 3 days

Judge: berndartmueller

Id: 181

League: ETH

Blur Exchange

Findings Distribution

Researcher Performance

Rank: 15/62

Findings: 1

Award: $612.43

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: 0xdeadbeef0x

Also found by: KingNFT, Koolex, Lambda, Trust, V_B, adriro, bin2chen, datapunk, hihen, philogy, rotcivegaf, wait

Labels

bug
3 (High Risk)
satisfactory
upgraded by judge
duplicate-96

Awards

612.4275 USDC - $612.43

External Links

Lines of code

https://github.com/code-423n4/2022-11-non-fungible/blob/8eaeb007b81d3c89ecf6a5dc2a67eecbe94cefaf/contracts/Exchange.sol#L161 https://github.com/code-423n4/2022-11-non-fungible/blob/8eaeb007b81d3c89ecf6a5dc2a67eecbe94cefaf/contracts/Exchange.sol#L209

Vulnerability details

Impact

The internalCall modifier ensures that public functions can only be called from another public function and not directly. It is implemented like that:

modifier internalCall() { require(isInternal, "This function should not be called directly"); _; }

The modifier setupExecution sets isInternal such that the calls work within all functions that have this modifier:

modifier setupExecution() { remainingETH = msg.value; isInternal = true; _; remainingETH = 0; isInternal = false; }

However, at the end of execute and bulkExecute, there is a _returnDust() call, which transfers ETH to the caller and therefore gives him the possibility to reenter into the contract. Because isInternal is still true at this point, this can be used to directly call functions with an isInternal modifier (i.e., the ones that should not be directly callable).

Proof of Concept

Bob calls execute (from a smart contract) to execute an order. Within _returnDust(), some ETH is transferred back to the smart contract, which triggers his receive function. In there, he can now execute all functions with an isInternal modifier, making the modifier useless. For instance, he can directly call _execute, which should not be possible (as this would be a private function, but was marked public with the modifier such that the delegatecalls work).

Add reentrancy guard protection to setupExecution. Note that the normal reentrancy variable (that is also used for _execute) cannot be set, otherwise this call would revert. Instead, a more advanced scheme is needed with multiple variables.

#0 - c4-judge

2022-11-17T10:21:22Z

berndartmueller marked the issue as duplicate of #96

#1 - c4-judge

2022-11-17T10:21:29Z

berndartmueller changed the severity to 3 (High Risk)

#2 - c4-judge

2022-12-06T14:02:45Z

berndartmueller marked the issue as satisfactory

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