LSD Network - Stakehouse contest - wait's results

A permissionless 3 pool liquid staking solution for Ethereum.

General Information

Platform: Code4rena

Start Date: 11/11/2022

Pot Size: $90,500 USDC

Total HM: 52

Participants: 92

Period: 7 days

Judge: LSDan

Total Solo HM: 20

Id: 182

League: ETH

Stakehouse Protocol

Findings Distribution

Researcher Performance

Rank: 86/92

Findings: 3

Award: $44.41

🌟 Selected for report: 0

🚀 Solo Findings: 1

Awards

11.192 USDC - $11.19

Labels

bug
3 (High Risk)
satisfactory
duplicate-251

External Links

Lines of code

https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/GiantSavETHVaultPool.sol#L29-L60 https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/GiantMevAndFeesPool.sol#L28-L53

Vulnerability details

Impact

Attacker can take away all eth in the pools.

Proof of Concept

Both GiantSavETHVaultPool and GiantMevAndFeesPool provide a function - batchDepositETHForStaking to deposit ETH from pool to vault for staking.

The main logic is:

for (uint256 i; i < numOfSavETHVaults; ++i) { uint256 transactionAmount = _ETHTransactionAmounts[i]; // As ETH is being deployed to a savETH pool vault, it is no longer idle idleETH -= transactionAmount; SavETHVault savETHPool = SavETHVault(_savETHVaults[i]); require( liquidStakingDerivativeFactory.isLiquidStakingManager(address(savETHPool.liquidStakingManager())), "Invalid liquid staking manager" ); // Deposit ETH for staking of BLS key savETHPool.batchDepositETHForStaking{ value: transactionAmount }( _blsPublicKeys[i], _stakeAmounts[i] ); }

It will check the vault by the liquidStakingManager address, and then send ETH to the vault by calling batchDepositETHForStaking.

Attacker can deploy a mock vault contract (M) which implements following two functions:

  1. function isLiquidStakingManager() returns the correct liquidStakingManager address.
  2. functoin batchDepositETHForStaking(bytes[], uint256[]) payable to receive ETH.

Then the attacker can call batchDepositETHForStaking of the pools with the mock vault contract M, and ETH in pools will be sent to M directly.

Tools Used

n/a

We need check the vault addresses passed to batchDepositETHForStaking, not to check the liquidStakingManager returned by the vault contract.

An easy way to do this is to register all newly created valid vault contracts in a trusted contract like the liquidStakingDerivativeFactory(LSDNFactory), and then check within the batchDepositETHForStaking to see if vault is in the registry.

#0 - c4-judge

2022-11-21T16:27:19Z

dmvt marked the issue as duplicate of #36

#1 - c4-judge

2022-11-29T15:42:46Z

dmvt marked the issue as satisfactory

#2 - C4-Staff

2022-12-21T05:40:16Z

JeeberC4 marked the issue as duplicate of #36

#3 - liveactionllama

2022-12-22T08:44:08Z

Duplicate of #251

Findings Information

🌟 Selected for report: aphak5010

Also found by: arcoun, datapunk, unforgiven, wait, yixxas

Labels

bug
2 (Med Risk)
partial-50
satisfactory
duplicate-98

Awards

33.2194 USDC - $33.22

External Links

Lines of code

https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/GiantPoolBase.sol#L69-L90

Vulnerability details

Impact

Anyone can exchange ETH for any token in the pool at a ratio of 1:1

Proof of Concept

The main logic of withdrawLPTokens function in GiantPoolBase is:

// Burn giant LP from user before sending them an LP token from this pool lpTokenETH.burn(msg.sender, amount); // Giant LP tokens in this pool are 1:1 exchangeable with external savETH vault LP token.transfer(msg.sender, amount);

The function doesn't check what the token passed in is, and calls token.transfer(msg.sender, amount); directly after eth lp is burnt.

If there is a token T with higher price than eth in the pool, then an attacker can pass in the address of the token T as a lpToken to swap ETH for T.

Tools Used

n/a

Register all LPTokens in a global trusted contract (e.g. LSDNFactory - liquidStakingDerivativeFactory), and check the passed in lpToken addresses in the registry.

#0 - c4-judge

2022-11-21T17:32:00Z

dmvt marked the issue as duplicate of #98

#1 - c4-judge

2022-11-30T12:32:20Z

dmvt marked the issue as satisfactory

#2 - c4-judge

2022-11-30T12:32:25Z

dmvt marked the issue as partial-50

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