LSD Network - Stakehouse contest - bin2chen'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: 55/92

Findings: 3

Award: $66.50

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

5.596 USDC - $5.60

Labels

bug
3 (High Risk)
partial-50
satisfactory
duplicate-251

External Links

Lines of code

https://github.com/code-423n4/2022-11-stakehouse/blob/4b6828e9c807f2f7c569e6d721ca1289f7cf7112/contracts/liquid-staking/GiantSavETHVaultPool.sol#L48-L52

Vulnerability details

Impact

GiantSavETHVaultPool#batchDepositETHForStaking() and GiantMevAndFeesPool#batchDepositETHForStaking() No detection of _stakingFundsVault is legal, you can pass malicious _savETHVaults to steal ETH

Proof of Concept

The security check of #batchDepositETHForStaking() only detects the incoming parameters calling _savETHVaults[i].liquidStakingManager() We can pass in a malicious contract, which has the method liquidStakingManager() to return a normal LiquidStakingManager contract address to pass the security check

function batchDepositETHForStaking( address[] calldata _savETHVaults, uint256[] calldata _ETHTransactionAmounts, bytes[][] calldata _blsPublicKeys, uint256[][] calldata _stakeAmounts ) public { ... //***@audit The malicious savETHPool.liquidStakingManager() returns a normal liquidStakingManager to skip the security detection***// require( liquidStakingDerivativeFactory.isLiquidStakingManager(address(savETHPool.liquidStakingManager())), "Invalid liquid staking manager" ); savETHPool.batchDepositETHForStaking{ value: transactionAmount }( //***@audit steal eth***// _blsPublicKeys[i], _stakeAmounts[i] );

Malicious contracts such as:

contract BadETHVaults{ function liquidStakingManager() external (ILiquidStakingManager) { return ILiquidStakingManager("0x???"); //*** normal LiquidStakingManager address***// } function batchDepositETHForStaking(bytes[] calldata _blsPublicKeyOfKnots, uint256[] calldata _amounts) external payable { //*** empty ***// } //** other withdraw eth function***/ }

Note: GiantMevAndFeesPool#batchDepositETHForStaking() has the same problem.

Tools Used

contract GiantSavETHVaultPool is StakehouseAPI, GiantPoolBase { ... function batchDepositETHForStaking( address[] calldata _savETHVaults, uint256[] calldata _ETHTransactionAmounts, bytes[][] calldata _blsPublicKeys, uint256[][] calldata _stakeAmounts ) public { ... - require( - liquidStakingDerivativeFactory.isLiquidStakingManager(address(savETHPool.liquidStakingManager())), - "Invalid liquid staking manager" - ); + LiquidStakingManager liquidStakingManager= savETHPool.liquidStakingManager(); + require( + liquidStakingDerivativeFactory.isLiquidStakingManager(address(liquidStakingManager)), + "Invalid liquid staking manager" + ); + require( + address(savETHPool) == address(liquidStakingManager.savETHVault()), + "Invalid savETHPool" + );
contract GiantMevAndFeesPool is ITransferHookProcessor, GiantPoolBase, SyndicateRewardsProcessor { ... function batchDepositETHForStaking( address[] calldata _stakingFundsVault, uint256[] calldata _ETHTransactionAmounts, bytes[][] calldata _blsPublicKeyOfKnots, uint256[][] calldata _amounts ) external { ... StakingFundsVault sfv = StakingFundsVault(payable(_stakingFundsVault[i])); - require( - liquidStakingDerivativeFactory.isLiquidStakingManager(address(sfv.liquidStakingNetworkManager())), - "Invalid liquid staking manager" - ); + LiquidStakingManager liquidStakingManager= sfv.liquidStakingManager(); + require( + liquidStakingDerivativeFactory.isLiquidStakingManager(address(liquidStakingManager)), + "Invalid liquid staking manager" + ); + require( + address(sfv) == address(liquidStakingManager.stakingFundsVault()), + "Invalid StakingFundsVault" + ); sfv.batchDepositETHForStaking{ value: _ETHTransactionAmounts[i] }( _blsPublicKeyOfKnots[i], _amounts[i] ); } }

#0 - c4-judge

2022-11-21T21:26:31Z

dmvt marked the issue as duplicate of #36

#1 - c4-judge

2022-11-29T15:44:14Z

dmvt marked the issue as satisfactory

#2 - c4-judge

2022-11-29T15:44:28Z

dmvt marked the issue as partial-50

#3 - C4-Staff

2022-12-21T05:40:16Z

JeeberC4 marked the issue as duplicate of #36

#4 - C4-Staff

2022-12-22T08:18:34Z

liveactionllama marked the issue as not a duplicate

#5 - C4-Staff

2022-12-22T08:18:45Z

liveactionllama marked the issue as duplicate of #251

Findings Information

🌟 Selected for report: 0xdeadbeef0x

Also found by: bin2chen, datapunk, hihen, koxuan

Labels

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

Awards

44.2926 USDC - $44.29

External Links

Lines of code

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

Vulnerability details

Impact

GiantSavETHVaultPool#bringUnusedETHBackIntoGiantPool() burn lpToken to send eth back,but GiantSavETHVaultPool no #receive() method to accept eth, will fail

Proof of Concept

GiantSavETHVaultPool#bringUnusedETHBackIntoGiantPool() -> SavETHVault#burnLPToken() -> msg.sender.call{value: _amount}("") but SavETHVault no receive()

contract SavETHVault is Initializable, ETHPoolLPFactory, ReentrancyGuard { ... function burnLPToken(LPToken _lpToken, uint256 _amount) public nonReentrant returns (uint256) { (bool result,) = msg.sender.call{value: _amount}(""); //****audit GiantSavETHVaultPool need #receive() to accept eth require(result, "Transfer failed"); }

Tools Used

contract GiantSavETHVaultPool is StakehouseAPI, GiantPoolBase { ... + /// @notice Allow the contract to receive ETH + receive() external payable {} }

#0 - c4-judge

2022-11-21T21:36:11Z

dmvt marked the issue as duplicate of #74

#1 - c4-judge

2022-11-30T11:52:39Z

dmvt marked the issue as satisfactory

#2 - c4-judge

2022-11-30T11:52:53Z

dmvt marked the issue as partial-50

Findings Information

🌟 Selected for report: ladboy233

Also found by: 0xdeadbeef0x, SaeedAlipoor01988, bin2chen, immeas, minhtrng

Labels

bug
2 (Med Risk)
partial-25
satisfactory
duplicate-132

Awards

16.6097 USDC - $16.61

External Links

Lines of code

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

Vulnerability details

Impact

ETHPoolLPFactory#rotateLPTokens() Wrong use of "24 ether", should use variable maxStakingAmountPerValidator, resulting in StakingFundsVault's lpToken.totalSupply() may be greater than 4 eth

Proof of Concept

use "24 eth " ,must use maxStakingAmountPerValidator

abstract contract ETHPoolLPFactory is StakehouseAPI { function rotateLPTokens(LPToken _oldLPToken, LPToken _newLPToken, uint256 _amount) public { ... require(_amount + _newLPToken.totalSupply() <= 24 ether, "Not enough mintable tokens"); //***@audit use 24 eth ,must use maxStakingAmountPerValidator***//
contract StakingFundsVault is Initializable, ITransferHookProcessor, StakehouseAPI, ETHPoolLPFactory, SyndicateRewardsProcessor, ReentrancyGuard { ... function _init(LiquidStakingManager _liquidStakingNetworkManager, LPTokenFactory _lpTokenFactory) internal virtual { .... maxStakingAmountPerValidator = 4 ether; //***@auit maxStakingAmountPerValidator = 4 eth ,not 24 eth**/ }

Tools Used

abstract contract ETHPoolLPFactory is StakehouseAPI { function rotateLPTokens(LPToken _oldLPToken, LPToken _newLPToken, uint256 _amount) public { ... - require(_amount + _newLPToken.totalSupply() <= 24 ether, "Not enough mintable tokens"); + require(_amount + _newLPToken.totalSupply() <= maxStakingAmountPerValidator, "Not enough mintable tokens");

#0 - c4-judge

2022-11-21T21:36:38Z

dmvt marked the issue as duplicate of #118

#1 - c4-judge

2022-11-30T13:20:34Z

dmvt marked the issue as satisfactory

#2 - c4-judge

2022-11-30T13:21:03Z

dmvt marked the issue as partial-25

#3 - C4-Staff

2022-12-21T05:49:13Z

JeeberC4 marked the issue as duplicate of #132

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