EigenLayer Contest - bin2chen's results

Enabling restaking of staked Ether, to be used as cryptoeconomic security for decentralized protocols and applications.

General Information

Platform: Code4rena

Start Date: 27/04/2023

Pot Size: $90,500 USDC

Total HM: 4

Participants: 43

Period: 7 days

Judge: GalloDaSballo

Id: 233

League: ETH

EigenLayer

Findings Distribution

Researcher Performance

Rank: 13/43

Findings: 1

Award: $1,443.93

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: juancito

Also found by: MiloTruck, Ruhum, SpicyMeatball, bin2chen, evmboi32, pontifex, sashik_eth, volodya, yjrwkk

Labels

bug
3 (High Risk)
satisfactory
upgraded by judge
duplicate-205

Awards

1443.9307 USDC - $1,443.93

External Links

Lines of code

https://github.com/code-423n4/2023-04-eigenlayer/blob/5e4872358cd2bda1936c29f460ece2308af4def6/src/contracts/core/StrategyManager.sol#L574-L576

Vulnerability details

Impact

++i is placed in the wrong place, resulting in indicesToSkip not working properly

Proof of Concept

in slashQueuedWithdrawal() We can specify indicesToSkip to skip certain strategies

The code is as follows:

    function slashQueuedWithdrawal(address recipient, QueuedWithdrawal calldata queuedWithdrawal, IERC20[] calldata tokens, uint256[] calldata indicesToSkip)
        external
        onlyOwner
        onlyFrozen(queuedWithdrawal.delegatedAddress)
        nonReentrant
    {
...
        uint256 strategiesLength = queuedWithdrawal.strategies.length;
        for (uint256 i = 0; i < strategiesLength;) {
            // check if the index i matches one of the indices specified in the `indicesToSkip` array
            if (indicesToSkipIndex < indicesToSkip.length && indicesToSkip[indicesToSkipIndex] == i) {
                unchecked {
                    ++indicesToSkipIndex;
                }
            } else {
                if (queuedWithdrawal.strategies[i] == beaconChainETHStrategy){
                     //withdraw the beaconChainETH to the recipient
                    _withdrawBeaconChainETH(queuedWithdrawal.depositor, recipient, queuedWithdrawal.shares[i]);
                } else {
                    // tell the strategy to send the appropriate amount of funds to the recipient
                    queuedWithdrawal.strategies[i].withdraw(recipient, tokens[i], queuedWithdrawal.shares[i]);
                }
                unchecked { //<--------@audit ++i,Should be at the outermost part of the loop
                    ++i;
                }
            }
        }
    }    

The above code ++i is placed inside the else is wrong, it should be placed outside the for most which currently causes, actually cannot be skipped. Because in the if block, the index i of the loop is not increased, and the next one is still the same strategies[i]

The correct one should be after the loop

Tools Used

    function slashQueuedWithdrawal(address recipient, QueuedWithdrawal calldata queuedWithdrawal, IERC20[] calldata tokens, uint256[] calldata indicesToSkip)
        external
        onlyOwner
        onlyFrozen(queuedWithdrawal.delegatedAddress)
        nonReentrant
    {
...
        uint256 strategiesLength = queuedWithdrawal.strategies.length;
        for (uint256 i = 0; i < strategiesLength;) {
            // check if the index i matches one of the indices specified in the `indicesToSkip` array
            if (indicesToSkipIndex < indicesToSkip.length && indicesToSkip[indicesToSkipIndex] == i) {
                unchecked {
                    ++indicesToSkipIndex;
                }
            } else {
                if (queuedWithdrawal.strategies[i] == beaconChainETHStrategy){
                     //withdraw the beaconChainETH to the recipient
                    _withdrawBeaconChainETH(queuedWithdrawal.depositor, recipient, queuedWithdrawal.shares[i]);
                } else {
                    // tell the strategy to send the appropriate amount of funds to the recipient
                    queuedWithdrawal.strategies[i].withdraw(recipient, tokens[i], queuedWithdrawal.shares[i]);
                }
-              unchecked { 
-                   ++i;
-               }
            }
+           unchecked { 
+               ++i;
+           }            
        }
    }    

Assessed type

Loop

#0 - c4-pre-sort

2023-05-09T13:09:23Z

0xSorryNotSorry marked the issue as duplicate of #205

#1 - c4-judge

2023-06-08T12:23:27Z

GalloDaSballo changed the severity to 3 (High Risk)

#2 - c4-judge

2023-06-08T12:24:13Z

GalloDaSballo marked the issue as satisfactory

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