Platform: Code4rena
Start Date: 24/03/2023
Pot Size: $49,200 USDC
Total HM: 20
Participants: 246
Period: 6 days
Judge: Picodes
Total Solo HM: 1
Id: 226
League: ETH
Rank: 144/246
Findings: 2
Award: $21.17
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: monrel
Also found by: 0xRajkumar, 0xfusion, AkshaySrivastav, Bahurum, Brenzee, Cryptor, Dug, Haipls, Koolex, Krace, MiloTruck, RaymondFam, RedTiger, ToonVH, Tricko, Vagner, aga7hokakological, anodaram, bart1e, bin2chen, bytes032, carrotsmuggler, ck, d3e4, giovannidisiena, igingu, juancito, mahdirostami, mert_eren, n33k, nemveer, parsely, pavankv, sashik_eth, shaka, sinarette, ulqiorra, yac
3.4908 USDC - $3.49
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L63-L101
The protocol is vulnerable to the well know inflation attack/first deposit bug. The attacker can steal assets from other user's stakes.
Reference cases:
Overview of the Inflation Attack Fist deposit bug
The share calculation uses the ERC20 balance of the derivates in the derivates pool. And attacker can transfer ERC20 tokens to inflate the balance. So that underlyingValue&preDepositPrice will be inflated. And the mint amount mintAmount
will be deflated.
// Getting underlying value in terms of ETH for each derivative for (uint i = 0; i < derivativeCount; i++) underlyingValue += (derivatives[i].ethPerDerivative(derivatives[i].balance()) * derivatives[i].balance()) / 10 ** 18; uint256 totalSupply = totalSupply(); uint256 preDepositPrice; // Price of safETH in regards to ETH if (totalSupply == 0) preDepositPrice = 10 ** 18; // initializes with a price of 1 else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply; .... // mintAmount represents a percentage of the total assets in the system uint256 mintAmount = (totalStakeValueEth * 10 ** 18) / preDepositPrice; _mint(msg.sender, mintAmount);
Steps to attack:
Once the contracts has been deployed, the attacker mints a small shares.
Then the attacker does a plain underlying token transfer to the derivate contract, artificially inflating the derivatives[i].balance() value.
Due to the above steps, during the next legitimate user deposit, the mintAmount value for the user will become less than 1 and essentially be rounded down to 0 by Solidity. Hence the user gets 0 share against his deposit and the SafETH entire supply is held by the Attacker.
The Attacker can then simply unstake his SafETH balance for the entire underlying token balance of the entire protocol.
Manual Review
Mint a same amount of SafETH to ZERO address on the first stake.
#0 - c4-pre-sort
2023-04-02T10:43:05Z
0xSorryNotSorry marked the issue as low quality report
#1 - c4-pre-sort
2023-04-04T12:49:03Z
0xSorryNotSorry marked the issue as duplicate of #715
#2 - c4-judge
2023-04-21T14:57:09Z
Picodes marked the issue as satisfactory
#3 - c4-judge
2023-04-24T21:39:21Z
Picodes changed the severity to 3 (High Risk)
🌟 Selected for report: RaymondFam
Also found by: 7siech, LeoGold, Phantasmagoria, SunSec, adeolu, anodaram, aviggiano, chaduke, d3e4, eyexploit, jasonxiale, juancito, koxuan, mojito_auditor, n33k, neumo, rotcivegaf, yac
17.681 USDC - $17.68
https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L88
User loses eth dust to SafETH contract.
In stake function, eth amount deposited to each derviative is calculated as
uint256 ethAmount = (msg.value * weight) / totalWeight;
becasue of the divsion, all the ethAmount
sums up may not equal msg.value. Thus leaves some eth dust inside SafETH contract.
Manual Review
refund dust eth at the end of stake function.
#0 - c4-pre-sort
2023-04-02T11:45:55Z
0xSorryNotSorry marked the issue as low quality report
#1 - c4-pre-sort
2023-04-04T16:26:10Z
0xSorryNotSorry marked the issue as duplicate of #455
#2 - c4-judge
2023-04-24T20:54:32Z
Picodes marked the issue as satisfactory