Skip to content

Latest commit

 

History

History
105 lines (79 loc) · 6.16 KB

015.md

File metadata and controls

105 lines (79 loc) · 6.16 KB

Kind Aqua Ostrich

High

Order validation and manipulation will cause that attackers front-run or replay orders, manipulating older proposals that shouldn't be active anymore in PredictDotLoan.sol

Summary

The contract PredictDotLoan.sol validates orders by checking conditions like token IDs, side, fee rates, etc., but doesn't validate that the exchangeOrder is fresh or that the proposal is still valid. Attackers could front-run or replay orders, manipulating older proposals that shouldn't be active anymore.

Root Cause

In the context of the PredictDotLoan contract, orders are processed through the _acceptOffer and _fillOrder functions, which are critical to the protocol’s matching of lenders and borrowers. If these orders are not validated thoroughly, attackers can manipulate them to their advantage. Take the following code: https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L221-L236 Here are a few critical areas that can be manipulated or exploited:

  1. Order mismatch and TokenID manipulation: If the token IDs in the order and the proposal are not properly validated, an attacker could manipulate the tokenID to access unintended assets.
  2. Collateral manipulation: By manipulating collateral amounts in a way that is not properly validated, the attacker may submit orders that under-collateralize the loan or create over-fulfilled loans where they take more than the legitimate value of the loan.
  3. Order replay attacks: If orders are reused or not properly canceled after execution, attackers could replay old orders and drain liquidity or collateral from the protocol without providing additional value.

An attacker exploits the tokenID mismatch in the _acceptOffer function, which checks the exchangeOrder.tokenId against the derived positionId. The validation here is only a simple revert, but an attacker might attempt to bypass it or manipulate the positionId.

Internal pre-conditions

Order manipulation via TokenID mismatch:

  1. The protocol uses specific tokenIDs to track collateral positions. The positionId is derived from the proposal and linked to collateral held by a user.

Order replay attack: If orders are not properly canceled or marked as fulfilled after they are executed, an attacker could replay old orders and execute them multiple times. An attacker replays a previously fulfilled order to drain liquidity or over-claim loan amounts.

  1. A user submits a legitimate loan offer, and the order is processed by the system.
Order memory originalOrder = Order({
  	  tokenId: validPositionId,
    side: Side.SELL,
    makerAmount: 1 ether,
    takerAmount: 0.9 ether,
    feeRateBps: 50
});

External pre-conditions

No response

Attack Path

Order manipulation via TokenID mismatch:

  1. The attacker crafts an order with a manipulated tokenId that matches the positionId of another user. By doing so, they could potentially drain collateral tied to another user’s loan position.
  2. The attacker submits the following order:
Order memory attackOrder = Order({
    tokenId: victimPositionId,  // Matches another user's position ID
    side: Side.SELL,
    makerAmount: 1 ether,        // Amount offered
    takerAmount: 0.1 ether,      // Minimal amount they need to pay
    feeRateBps: 100              // Arbitrary fee rate
});
  1. The _fillOrder function processes this order because the attacker manipulated the tokenId to match a legitimate positionId. The attacker is able to withdraw collateral from the victim’s loan position or gain access to it in a fraudulent manner.

Order replay attack:

  1. The attacker, having obtained the hash of the original order, resubmits the exact same order after it has already been fulfilled. Since the system doesn’t properly track or mark the order as fulfilled, it processes the order again, transferring the loan amount or collateral twice.
  2. The attacker effectively receives the same loan twice or gains access to the collateral again, which should have been locked after the first execution.

Impact

In order manipulation via TokenID mismatch the attacker successfully claims another user's collateral. This would severely undermine trust in the protocol, as users could lose their collateral without their knowledge. Over time, this could drain liquidity from the protocol, causing systemic issues as legitimate users are unable to claim their collateral or loans. In order replay attack the attacker can claim twice the amount they are entitled to. Over time, this could lead to a significant loss of funds for the protocol. If not mitigated, replay attacks could lead to multiple instances of double-spending or over-claiming, quickly draining liquidity and collateral from the protocol, potentially resulting in systemic collapse.

PoC

No response

Mitigation

Ensure that each Order has a unique identifier (nonce or timestamp) and that orders are tracked across the system to prevent replay attacks. After an order is fulfilled, it should be marked as "completed" to prevent reuse or replaying.

mapping(bytes32 orderHash => bool isFulfilled);

function _fillOrder(Order memory order) internal {
    bytes32 orderHash = keccak256(abi.encode(order));
    require(!isFulfilled[orderHash], "Order already fulfilled");
    isFulfilled[orderHash] = true;
    // Continue processing...
}

Use nonces for proposals and orders to ensure that they can only be used once. After the order is fulfilled or canceled, increment the nonce to prevent replays.

mapping(address => uint256 nonce);

function submitOrder(Order memory order) external {
    require(order.nonce == nonce[msg.sender], "Invalid nonce");
    nonce[msg.sender]++;
    // Process order...
}

Implement robust integrity checks for positionId and tokenId to ensure that they are not manipulated. For instance, hash the positionId with other user-specific data (e.g., address, salt) to ensure the tokenID cannot be tampered with.

bytes32 validPositionId = keccak256(abi.encode(user, proposalId, salt));

Also, add logic that allows users to cancel old orders or proposals to prevent malicious actors from replaying them in the future.