hats-finance / Fenix--0x9d7765a7ebd5b6322a30797a44a5428531970d3d

0 stars 1 forks source link

in `RouterV2` a usage of `permit` directly in `removeLiquidityWithPermit` and `removeLiquidityETHWithPermit` is susceptible to greifing and constant reverts #28

Open hats-bug-reporter[bot] opened 2 months ago

hats-bug-reporter[bot] commented 2 months ago

Github username: -- Twitter username: -- Submission hash (on-chain): 0xe6131252ba2c174278001eb87acd792c14daf5e11afbb9200a22f80b08ce46c8 Severity: medium

Description: Description\ The RouterV2 contract contains two functions, removeLiquidityWithPermit and removeLiquidityETHWithPermit, which use the permit function to approve token spending. These functions are vulnerable to a front-running attack that can cause them to revert, denying service to legitimate users.

The vulnerability stems from the fact that these functions unconditionally call the permit function of the pair contract. An attacker can extract the signature parameters from a pending transaction and use them to front-run the original transaction, causing the subsequent legitimate call to fail.

Attack Scenario\ A user calls removeLiquidityWithPermit or removeLiquidityETHWithPermit with valid signature parameters.

An attacker observes this transaction in the mempool.

The attacker extracts the signature parameters (v, r, s) and other relevant data from the pending transaction.

The attacker front-runs the user's transaction by calling the permit function directly on the pair contract with the extracted parameters.

When the original user's transaction is processed, the permit call within the function fails because the permit has already been used, causing the entire transaction to revert.

The user is unable to remove liquidity, effectively being denied service.

This attack can be repeated, consistently preventing users from using these functions.

Attachments

File: RouterV2.sol
341:     function removeLiquidityWithPermit(
342:         address tokenA,
343:         address tokenB,
344:         bool stable,
345:         uint liquidity,
346:         uint amountAMin,
347:         uint amountBMin,
348:         address to,
349:         uint deadline,
350:         bool approveMax,
351:         uint8 v,
352:         bytes32 r,
353:         bytes32 s
354:     ) external returns (uint amountA, uint amountB) {
355:         address pair = pairFor(tokenA, tokenB, stable);
356:         {
357:             uint value = approveMax ? type(uint).max : liquidity;
358:             IBaseV1Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
359:         }
360: 
361:         (amountA, amountB) = removeLiquidity(tokenA, tokenB, stable, liquidity, amountAMin, amountBMin, to, deadline);
362:     }
363: 
364:     function removeLiquidityETHWithPermit(
365:         address token,
366:         bool stable,
367:         uint liquidity,
368:         uint amountTokenMin,
369:         uint amountETHMin,
370:         address to,
371:         uint deadline,
372:         bool approveMax,
373:         uint8 v,
374:         bytes32 r,
375:         bytes32 s
376:     ) external returns (uint amountToken, uint amountETH) {
377:         address pair = pairFor(token, address(wETH), stable);
378:         uint value = approveMax ? type(uint).max : liquidity;
379:         IBaseV1Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
380:         (amountToken, amountETH) = removeLiquidityETH(token, stable, liquidity, amountTokenMin, amountETHMin, to, deadline);
381:     }
  1. Proof of Concept (PoC) File

  2. Revised Code File (Optional)

0xmahdirostami commented 2 months ago

OOS, Invalid