code-423n4 / 2024-01-curves-findings

1 stars 0 forks source link

Attacker can frontrun token subject's setNameAndSymbol() call with a zero amount withdraw() call to deny token subject from using a custom name and symbol #927

Closed c4-bot-9 closed 9 months ago

c4-bot-9 commented 10 months ago

Lines of code

https://github.com/code-423n4/2024-01-curves/blob/516aedb7b9a8d341d0d2666c23780d2bd8a9a600/contracts/Curves.sol#L465

Vulnerability details

Impact

The mint() function is used to deploy an ERC20 token for token subjects. This function can only be called by the token subject themselves. But another way to deploy an ERC20 token without the token subject's permission is through the withdraw() function. Passing 0 as the value for parameter amount allows anyone to create an ERC20 token with the default name and symbol (with the counter appended to it).

For the case where a regular user or famous individual (influencer or celebrity) wants an ERC20 token with a custom name and symbol, they can do so by calling setNameAndSymbol() and calling mint() thereafter. The issue here is that an attacker can frontrun the setNameAndSymbol() transaction with a zero amount withdraw() call. This would make the user devoid of using a custom name and symbol. This would have a negative social impact on the Curves platform if the individual is famous, which would cause them to migrate away from the platform. This case is also true for a regular user except that the user won't be having many followers to influence.

Additionally, even if a token subject is not using the Curves platform currently (i.e. has not initiated a curve) but will in the future, the ERC20 token can still be deployed by the attacker early on. When the token subject onboards the platform, the individual realises they cannot have a custom name and symbol. It makes sense for this kind of attack to be targeted on famous individuals or organizations with known public addresses.

This issue has been marked as Medium-severity since:

  1. An important feature of the protocol is rendered useless/ineffective.
  2. The Curves protocol relies on the core concept of SocialFi and the social impact caused by this attack negatively affects the Curves protocol
  3. The gas required to perform this kind of attack on all users is extremely cheap since the Form network is used (see fees here).
  4. It is a one time attack for each user (since each user can only have one ERC20 token), thus making it easier for the attacker to execute.

Proof of Concept

Here is the whole process:

First, let's see how much gas fees would it take for the attacker to target this attack on all users.

Let's assume the active users on the Curves protocol are 500 (based on current DefiLlama friend.tech data). Out of those, 100 use the custom name and symbol feature.

Gas fee on Form network currently = 1.24 gwei (see here)

Imgur

From the tests, we can see a withdraw() function call costs 153428 gas.

Imgur

Fees = 153428 (gas) 1.24 (gwei) 100 (users) = 19025072 gwei = 0.019025072 ETH (use Ethereum Unit Converter)

Therefore, for 100 users who use the custom token name and symbol feature, the fees required would be 0.019025072 ETH (currently only 50$). Note that this is only the fees required for one attacker. There will be more users who could deploy ERC20 tokens without requiring the attacker's involvement.

Coded POC

This POC demonstrates that a token subject alice gets frontrun by bob (a regular user or attacker), which makes alice devoid of using a custom name and symbol for her ERC20 token.

Here is how to run this POC:

File: testNameAndSymbolIssue.t.sol
01: // SPDX-License-Identifier: MIT
02: pragma solidity ^0.8.7;
03: 
04: import {Curves} from "../contracts/Curves.sol";
05: import {CurvesERC20Factory} from "../contracts/CurvesERC20Factory.sol";
06: import {FeeSplitter} from "../contracts/FeeSplitter.sol";
07: import {Test} from "forge-std/Test.sol";
08: import {console} from "forge-std/console.sol";
09: 
10: contract testNameAndSymbolIssue is Test {
11: 
12:     // Contract instances
13:     Curves curves;
14:     CurvesERC20Factory factory;
15:     FeeSplitter fs;
16: 
17:     // Fee destinations
18:     address public protocolFeeDestination = makeAddr("protocolFeeDestination");
19:     address public referralFeeDestination = makeAddr("referralFeeDestination");
20:  
21:     // Token subject
22:     address public alice = makeAddr("alice");
23: 
24:     // Attacker
25:     address public bob = makeAddr("bob");
26: 
27:     function setUp() public {
28:         factory = new CurvesERC20Factory();
29:         fs = new FeeSplitter();
30:         curves = new Curves(address(factory), address(fs));
31:     }
32: 
33:     function testSetupFees() public {
34:         // 20% - Protocol fees
35:         // 20% - Subject fees
36:         // 10% - Referral fees
37:         // 50% - Holder fees
38:         curves.setMaxFeePercent(1e18);
39:         curves.setProtocolFeePercent(2e17, protocolFeeDestination); 
40:         curves.setExternalFeePercent(2e17, 1e17, 5e17);
41:         vm.prank(alice);
42:         curves.setReferralFeeDestination(alice, referralFeeDestination);
43:     }
44: 
45:     function testBuyFirstCurveToken() public {
46:         vm.prank(alice);
47:         curves.buyCurvesToken(alice, 1);
48:     }
49: 
50:     function testCustomNameAndSymbolAttack() public {
51:         testSetupFees();
52:         fs.setCurves(Curves(address(curves)));
53:         
54:         // Attacker bob frontruns alice
55:         vm.prank(bob);
56:         curves.withdraw(alice, 0);
57: 
58:         // Alice cannot set new name or symbol anymore nor create a new token
59:         vm.prank(alice);
60:         vm.expectRevert();
61:         curves.setNameAndSymbol(alice, "AliceRocks", "AR");
62:     }
63: }

Attack confirmation

Imgur

Tools Used

Manual Review

Recommended Mitigation Steps

Disable 0 value withdraw() calls, which allows this attack to occur. For this, check if amount parameter passed is 0 or not.

Assessed type

DoS

c4-pre-sort commented 10 months ago

raymondfam marked the issue as insufficient quality report

c4-pre-sort commented 10 months ago

raymondfam marked the issue as duplicate of #339

c4-judge commented 9 months ago

alcueca marked the issue as not a duplicate

c4-judge commented 9 months ago

alcueca marked the issue as duplicate of #339

c4-judge commented 9 months ago

alcueca marked the issue as satisfactory