EigenLayer Contest - evmboi32'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: 16/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#L536-L579

Vulnerability details

Impact

Users can avoid getting their queuedWithdrawal slashed because of the wrong implementation.

Proof of Concept

Let's take a look at the following code snippet from StrategyManager#slashQueuedWithdrawal.

// keeps track of the index in the `indicesToSkip` array
uint256 indicesToSkipIndex = 0;

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;
        }
    }
}

Now let's say we want to skip only the first strategy because it always reverts on withdraw. We will do this be calling slashQueuedWithdrawal with indicesToSkip = [0]. If we follow the code we can see that in the first iteration i=0 and indicesToSkipIndex=0. We enter the if part since the condition is true (indicesToSkip[0] == 0). This will increase the indicesToSkipIndex to 1.

Now in second iteration we have indicesToSkipIndex = 1 and i = 0. The if part is not true in this iteration so we enter the else part of the conditional statement and essentially try to withdraw from the strategy[0] that we wanted to skip.

User can set such an array of strategies when queueing withdrawal that withdrawing from the first strategy always fails. This way his queued withdrawal cannot get slashed.

Tools Used

Put the ++i statement outside of else part.

// keeps track of the index in the `indicesToSkip` array
uint256 indicesToSkipIndex = 0;

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

DoS

#0 - c4-pre-sort

2023-05-09T13:09:19Z

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:23:53Z

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