2024-12-12
*issue*
================================================================================

odos signature can be used for other withdraws to make bad swap on odos for protocol

================================================================================

*issue-contents*

0 CONTENTS

*issue-metadata*

1 METADATA

Number 39
Severity High
Author volodya
Contest Autonomint
Platform Sherlock
*issue-summary*

2 SUMMARY

There is no invalidation that this signature already used in protocol

*issue-root-cause*

3 ROOT CAUSE

In withdraw function signature and odos data passed to cds contract

    function withDraw(
        address toAddress,
        uint64 index,
        bytes memory odosAssembledData,
        bytes memory signature
    ) external payable nonReentrant whenNotPaused(IMultiSign.Functions(1)) {
        // check is _toAddress in not a zero address and isContract address
        if (toAddress == address(0) || isContract(toAddress)) revert Borrow_CantBeContractOrZeroAddress(toAddress);

-->        if (!cds.verify(odosAssembledData, signature)) revert Borrow_NotSignedByEIP712Signer();
        // Get the depositor details

Blockchian/contracts/Core_logic/borrowing.sol#L290

where signature is not being invalidated anywhere which allows to use it again for any other withdraw for that user


    function verify(
        bytes memory odosExecutionData,
        bytes memory signature
    ) external view onlyBorrowingContract returns (bool) {
        return
            _verify(
                FunctionName.BORROW_WITHDRAW,
                0,
                0,
                odosExecutionData,
                signature
            );
    }

    function _verify(
        FunctionName functionName,
        uint256 excessProfitCumulativeValue,
        uint256 nonce,
        bytes memory odosExecutionData,
        bytes memory signature
    ) private view returns (bool) {
        bytes32 digest;
...
        } else if (functionName == FunctionName.BORROW_WITHDRAW) {
            digest = _hashTypedDataV4(
                keccak256(
                    abi.encode(
                        keccak256("OdosPermit(bytes odosExecutionData)"),
                        odosExecutionData
                    )
                )
            );
        }

        address signer = ECDSA.recover(digest, signature);
        bytes32 hashedSigner = keccak256(abi.encodePacked(signer));
        if (hashedSigner == hashedAdminTwo) {
            return true;
        } else {
            return false;
        }
    }

E.x. there are two positions. E.x.there is upside - 1 wrsETH after first withdraw and 2 wrsEth after second withdraw. Target for odos swap is TREASURY from tests. Everything goes normal user uses 1 signature for first withdrawal - 1 wrsETH exchange for 1000 udst to treasury Everything goes normal user uses second signature for second withdrawal - 2 wrsETH exchange for 2000 udst to treasury

Attacker uses first signature for second withdrawal 1 wrsETH exchange for 1000 udst, but upside left - 2 wrsETH - 1 wrsETH=1wrsETH left unaccounting. Which means some holders will not receive their stake which leads to depeging as the point of protocol to catch upside and distribute correctly

*issue-internal-pre-conditions*

4 INTERNAL PRE-CONDITIONS

none

*issue-external-pre-conditions*

5 EXTERNAL PRE-CONDITIONS

none

*issue-attack-path*

6 ATTACK PATH

use odos data from first withdrawal and use it on another withdrawal.

*issue-impact*

7 IMPACT

holders will not receive their stake which leads to depeging as the point of protocol to catch upside and distribute correctly

*issue-poc*

8 POC

*issue-mitigation*

9 MITIGATION

Add nonce to invalidate that signature that already used

================================================================================

LINKS

*issue-links*