Canto Dex Oracle contest - Chom's results

Execution layer for original work.

General Information

Platform: Code4rena

Start Date: 07/09/2022

Pot Size: $20,000 CANTO

Total HM: 7

Participants: 65

Period: 1 day

Judge: 0xean

Total Solo HM: 3

Id: 159

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 10/65

Findings: 2

Award: $249.68

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Chom

Also found by: 0xSmartContract, Jeiwan, SinceJuly, V_B, cccz, linmiaomiao

Labels

bug
2 (Med Risk)
sponsor disputed

Awards

1303.145 CANTO - $210.46

External Links

Lines of code

https://github.com/code-423n4/2022-09-canto/blob/65fbb8b9de22cf8f8f3d742b38b4be41ee35c468/src/Swap/BaseV1-periphery.sol#L490-L508

Vulnerability details

Impact

Hackers can deploy tokens with respective names as the stable ones to impersonate the stable token. Then hackers can get profit from the malicious price oracle.

Proof of Concept

string memory symbol = ctoken.symbol(); if (compareStrings(symbol, "cCANTO")) { underlying = address(wcanto); return getPriceNote(address(wcanto), false); } else { underlying = address(ICErc20(address(ctoken)).underlying()); // We are getting the price for a CErc20 lending market } //set price statically to 1 when the Comptroller is retrieving Price if (compareStrings(symbol, "cNOTE")) { // note in terms of note will always be 1 return 1e18; // Stable coins supported by the lending market are instantiated by governance and their price will always be 1 note } else if (compareStrings(symbol, "cUSDT") && (msg.sender == Comptroller )) { uint decimals = erc20(underlying).decimals(); return 1e18 * 1e18 / (10 ** decimals); //Scale Price as a mantissa to maintain precision in comptroller } else if (compareStrings(symbol, "cUSDC") && (msg.sender == Comptroller)) { uint decimals = erc20(underlying).decimals(); return 1e18 * 1e18 / (10 ** decimals); //Scale Price as a mantissa to maintain precision in comptroller }

If hackers or malicious admin deploy a non-stable token but has "cNOTE", "cUSDT", or "cUSDC" as symbols, these tokens will act as a stable token while in fact, it isn't.

Use fixed address whitelisting instead for example if (address(ctoken) == cUSDC_address) ... where cUSDC_address is an immutable variable set on the constructor.

#0 - tkkwon1998

2022-09-08T20:38:31Z

The warden is saying that malicious parties could deploy a token with the same name to impersonate other tokens, but that these tokens will use the same pricing methodology as the token it is impersonating.

However, as this is an open EVM, anyone could deploy any token name with any underlying price method. I fail to see how this would be an issue, since everything is open source and users can see what they are doing.

#1 - 0xean

2022-09-14T20:04:19Z

What is the benefit the sponsor is trying to achieve by comparing a non unique string compared to a unique address?

While everything is open source, it does seem like this is a pretty bad design choice when compared to the alternative solutions.

#2 - nivasan1

2022-10-11T03:50:21Z

@0xean, the design choice presented here prevents from having multiple dependencies in the initialization of the oracle. Furthermore, the tokens that are referenced here must be supported by governance, so to override the actual prices would require a >51% voting power. As such, even if the exploit exists it is essentially impossible. As such, we do not believe that this is a high / med -risk issue.

#3 - 0xean

2022-10-13T00:30:44Z

Will downgrade to M as there are several external factors for this to become an issue.

Lines of code

https://github.com/code-423n4/2022-09-canto/blob/65fbb8b9de22cf8f8f3d742b38b4be41ee35c468/src/Swap/BaseV1-periphery.sol#L524-L593 https://github.com/code-423n4/2022-09-canto/blob/65fbb8b9de22cf8f8f3d742b38b4be41ee35c468/src/Swap/BaseV1-core.sol#L45

Vulnerability details

Impact

Using an average of 8 periods, each period covering 30 minutes may cause the price to be extremely delayed. Hackers can profit from these delays.

In crypto, the price can +100% in just 30 minutes. Imagine volatility of 8 * 30 = 240 minutes = 4 hours. Hackers can profit a lot from these delays. Moreover, if the market crash just like UST, the liquidator can't liquidate assets in time due to extremely delayed price, causing bad debt.

Proof of Concept

uint public periodSize = 1800;

Every 30 minutes one observation will be stored.

... uint price = IBaseV1Pair(pair).quote(address(token), decimals, 8); ... for(uint i; i < 8; ++i) { uint token0TVL = assetReserves[i] * (prices[i] / decimals); uint token1TVL = unitReserves[i]; // price of the unit asset is always 1 LpPricesCumulative += (token0TVL + token1TVL) * 1e18 / supply[i]; } uint LpPrice = LpPricesCumulative / 8; // take the average of the cumulative prices ...

Many functions in BaseV1-periphery use an average of 8 periods = 240 minutes = 4 hours which is ridiculously long.

Reduce periodSize to 5 minutes

#0 - nivasan1

2022-09-09T19:39:08Z

The Pricing in the lending market is meant to be as resistant to large swings in volatility as possible to protect suppliers in each cToken market, changing to a shorter period size leaves the possibility of attackers manipulating prices through flash-loans over time. Also the period size can be changed through governance in the case that the community decides to decrease the TWAP.

#1 - 0xean

2022-09-12T14:55:23Z

This is a design tradeoff on the "correct" time for the TWAP, hard to see it as a critical vulnerability. Downgrading to QA. Warden has no QA report, so this will stand as theirs.

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