sherlock-audit / 2023-04-blueberry-judging

8 stars 5 forks source link

Bauchibred - H IchiLpOracle can be easily manipulated due to the possibility of inflating the LP prices using the math provided in the function #84

Closed sherlock-admin closed 1 year ago

sherlock-admin commented 1 year ago

Bauchibred

high

H IchiLpOracle can be easily manipulated due to the possibility of inflating the LP prices using the math provided in the function

Summary

IchiLpOracle can easily be manipulated

Vulnerability Detail

The IChiLpOracle.getPrice() function's exectution could very easily be manipulated

 /**
     * @notice Return vault token price in USD, with 18 decimals of precision.
     * @param token The vault token to get the price of.
     * @return price USD price of token in 18 decimal
     */
    function getPrice(address token) external view override returns (uint256) {
        IICHIVault vault = IICHIVault(token);
        uint256 totalSupply = vault.totalSupply();
        if (totalSupply == 0) return 0;

        address token0 = vault.token0();
        address token1 = vault.token1();

        // Check price manipulations on Uni V3 pool by flashloan attack
        uint256 spotPrice = spotPrice0InToken1(vault);
        uint256 twapPrice = twapPrice0InToken1(vault);
        uint256 maxPriceDeviation = maxPriceDeviations[token0];
        if (!_isValidPrices(spotPrice, twapPrice, maxPriceDeviation))
            revert Errors.EXCEED_DEVIATION();

        // Total reserve / total supply
        (uint256 r0, uint256 r1) = vault.getTotalAmounts();
        uint256 px0 = base.getPrice(address(token0));
        uint256 px1 = base.getPrice(address(token1));
        uint256 t0Decimal = IERC20Metadata(token0).decimals();
        uint256 t1Decimal = IERC20Metadata(token1).decimals();

        uint256 totalReserve = (r0 * px0) /
            10 ** t0Decimal +
            (r1 * px1) /
            10 ** t1Decimal;

        return (totalReserve * 10 ** vault.decimals()) / totalSupply;
    }
}

As seen above the team have provided a few checks in order to ensure that there no longer exist a price manipulation from a flashloan attack, but this just closes one window as to how the execution of this function could be manipulated.

Other ways exist which and the main aim of this report is to cover these areas. There are tow other wasy that a malicious user tdirectly manipulate the vault.totalSupply()

If/when the large amount of vault share is minted, totalSupply goes up, and the price goes down based on the code:

return (totalReserve * 10 ** vault.decimals()) / totalSupply; which leads to getPrice() returning a low price, which allows the malicious user to over-borrow and never pay back the debt

Also keep it in mind that the user could borrow flashloan, deposit into the vault, and make the IchiVaultracle.so return low price, and make the collaterallized asset under-collateralized and perform malicious liquidation and they withdraw from the vault to burn the share.

Another manipulation path is by exploiting the code:

(uint256 r0, uint256 r1) = vault.getTotalAmounts();

(uint256 r0, uint256 r1) = vault.getTotalAmounts(); which calls the code below (Using the mock vault as a reference)

    /**
     @notice Calculates total quantity of token0 and token1 in both positions (and unused in the ICHIVault)
     @param total0 Quantity of token0 in both positions (and unused in the ICHIVault)
     @param total1 Quantity of token1 in both positions (and unused in the ICHIVault)
     */
    function getTotalAmounts()
        public
        view
        override
        returns (uint256 total0, uint256 total1)
    {
        (, uint256 base0, uint256 base1) = getBasePosition();
        (, uint256 limit0, uint256 limit1) = getLimitPosition();
        total0 = IERC20(token0).balanceOf(address(this)) + base0 + limit0;
        total1 = IERC20(token1).balanceOf(address(this)) + base1 + limit1;
Since the vault use balanceOf directly, the user can transfer the token0 and token1 directly to the vault and inflate the LP price based on the math:
https://github.com/sherlock-audit/2023-02-blueberry-judging/issues/20

Here since the vault use balanceOf directly, the user can transfer the token0 and token1 directly to the vault and inflate the LP price based on the math:


 uint256 totalReserve = (r0 * px0) /
            10**t0Decimal +
            (r1 * px1) /
            10**t1Decimal;

        return (totalReserve * 1e18) / totalSupply;

If r0 and r1 goes up, totalReserve goes up, totalSupply does not change, price is inflated.

Then user can over-borrow by using ICHI LP as collateral, the user can still use withdraw on the vault to get the transferred token0 and token1 back.

Impact

Oracle manipulation in IchiVaultOracle allows user to over-borrow or perform malicious liquidation.

Code Snippet

https://github.com/sherlock-audit/2023-04-blueberry/blob/96eb1829571dc46e1a387985bd56989702c5e1dc/blueberry-core/contracts/oracle/CoreOracle.sol#L68-L78

Tool used

Manual Review

Recommendation

The protocol should not only use spot value to derive the oracle price, the spot value used including the vault share total supply and the r0 and r1amount

(uint256 r0, uint256 r1) = vault.getTotalAmounts();