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
Rank: 55/92
Findings: 3
Award: $66.50
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Jeiwan
Also found by: 0xdeadbeef0x, 9svR6w, JTJabba, Lambda, Trust, arcoun, banky, bin2chen, bitbopper, c7e7eff, clems4ever, datapunk, fs0c, hihen, imare, immeas, perseverancesuccess, ronnyx2017, satoshipotato, unforgiven, wait
5.596 USDC - $5.60
GiantSavETHVaultPool#batchDepositETHForStaking() and GiantMevAndFeesPool#batchDepositETHForStaking() No detection of _stakingFundsVault is legal, you can pass malicious _savETHVaults to steal ETH
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.
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
🌟 Selected for report: 0xdeadbeef0x
44.2926 USDC - $44.29
GiantSavETHVaultPool#bringUnusedETHBackIntoGiantPool() burn lpToken to send eth back,but GiantSavETHVaultPool no #receive() method to accept eth, will fail
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"); }
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
🌟 Selected for report: ladboy233
Also found by: 0xdeadbeef0x, SaeedAlipoor01988, bin2chen, immeas, minhtrng
16.6097 USDC - $16.61
ETHPoolLPFactory#rotateLPTokens() Wrong use of "24 ether", should use variable maxStakingAmountPerValidator, resulting in StakingFundsVault's lpToken.totalSupply() may be greater than 4 eth
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**/ }
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