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: 240/246
Findings: 1
Award: $0.14
π Selected for report: 0
π Solo Findings: 0
π Selected for report: HHK
Also found by: 019EC6E2, 0Kage, 0x52, 0xRobocop, 0xTraub, 0xbepresent, 0xepley, 0xfusion, 0xl51, 4lulz, Bahurum, BanPaleo, Bauer, CodeFoxInc, Dug, HollaDieWaldfee, IgorZuk, Lirios, MadWookie, MiloTruck, RedTiger, Ruhum, SaeedAlipoor01988, Shogoki, SunSec, ToonVH, Toshii, UdarTeam, Viktor_Cortess, a3yip6, auditor0517, aviggiano, bearonbike, bytes032, carlitox477, carrotsmuggler, chalex, deliriusz, ernestognw, fs0c, handsomegiraffe, igingu, jasonxiale, kaden, koxuan, latt1ce, m_Rassska, n1punp, nemveer, nowonder92, peanuts, pontifex, roelio, rvierdiiev, shalaamum, shuklaayush, skidog, tank, teddav, top1st, ulqiorra, wait, wen, yac
0.1353 USDC - $0.14
This vulnerability lets attackers receive an additional amount of safETH
tokens and swap them for ETH
with profit. Finally the cost of safETH
will decrease because of underlying assets loosing. It is possible because of different branches in estimation of rETH
asset for the current balance and deposited amount.
Prerequisites: the SafEth
contract has rETH
balance more than 5000 ETH (this is the current max value that can be deposited in the Rocket pool) and weight
!= 0.
The attackers transaction will be consist of:
#1. Take a flashloan with approximately 5000 rETH. It is enough to move the price in the swap pool.
#2. Make a swap in the Uniswap v3 rETH/WETH pool to influence on the tokens rate.
#3. Call stake
function in the SafEth
contract in a loop with amount less than 200 to satisfy the contract conditions:
#3.1 The line #72 computes underlyingValue
with the current assets balances. Letβs look at the derivatives[i].ethPerDerivative(derivatives[i].balance())
call for the safETH
asset.
#3.2 It routes us to the line #211 of the Reth
contract. There are two variants for asset estimation depending on _amount
.
#3.3 The poolCanDeposit
checks that the _amount
satisfy the max and min possible meanings for depositing setting in the rocketDAOProtocolSettingsDeposit
. The current max value is 5000 ETH. Of course it is not correct to send asset balance in the function, which waits for the amount of ETH, but this is not in the scope of the PoC.
#3.4 So we will go to another branch with poolPrice
function (line #215), which asks the current rate of the rETH/WETH pair in the Uniswap v3 pool and receives the manipulated rate.
#3.5 We received a really low estimation for the safETH
asset in the underlyingValue
variable. In the line #81 the preDepositPrice
is calculated - the ratio of underlyingValue
and totalSupply
.
#3.6 The next step is staking of ETH in the derivatives. The corresponding ethAmount
will be calculated depending on weight
in the line #88
#3.7 There is the derivative.deposit
call in the line #91, which routes us in the deposit
function in the Reth
contract.
#3.8 There is the same with 3.4 point check poolCanDeposit
, but the _amount
is less or equal 200 ETH. So we will pass the check and will go to the branch with deposition in the rocketDepositPool
with normal rETH/ETH ratio.
#3.9 There is asset estimation with derivative.ethPerDerivative
for the same ETH amount in the line #92. It will also be estimated in the rocketDepositPool
with normal ratio.
#3.10 Finally the mintAmount
variable will be calculated in the line #98. There will be a ratio between variable totalStakeValueEth
with normal asset estimation and preDepositPrice
with low asset estimation here. Attacker receives more safETH
tokens.
#3.11 Repeat several times.
#4. Swap back tokens.
#5. Return flashloan.
#6. Call the unstake
function safETH
. There are no restrictions for the token amount and the rate will be normal.
#7. Make sure of profitability.
Remix, app.uniswap.org, Etherscan
I suggest just using the internal rate of the derivatives to estimate underlying value in the safETH
and the sfrxEth
derivatives in the same way with the wstETH
.
#0 - c4-pre-sort
2023-03-31T12:26:19Z
0xSorryNotSorry marked the issue as low quality report
#1 - c4-pre-sort
2023-04-04T11:19:42Z
0xSorryNotSorry marked the issue as duplicate of #601
#2 - c4-judge
2023-04-21T16:14:51Z
Picodes marked the issue as satisfactory
#3 - c4-judge
2023-04-21T16:15:29Z
Picodes marked the issue as duplicate of #1125