How Was Biswap Exploited?

5 min read

Learn how an attacker exploited Biswap to steal assets worth approximately $865,000.

TL;DR#

On June 30, 2023, the new liquidity migrator contract of Biswap, meant for LPs to migrate their liquidity from v2 to v3, was exploited, which resulted in a loss of funds worth approximately $865,000.

Introduction to Biswap#

Biswap aims to enhance the DeFi ecosystem by providing liquidity providers with increased capital efficiency, control, and flexibility. 

Vulnerability Assessment#

The root cause of the exploit is a lack of proper access control, allowing the attacker to steal tokens from the users who had approved LP tokens for the V3 Migrator contract.

Steps#

Step 1:

We attempt to analyze one of the attack transactions executed by the exploiter.

Step 2:

The migrate function on the V3 contract was vulnerable as it didn't validate the `params.recipient` entries, due to which tokens approved by users for migrations can be transferred by anyone.

function migrate(MigrateParams calldata params) external override returns (uint256 refund0, uint256 refund1) {
  // burn v2 liquidity to this address
  IBiswapPair(params.pair).transferFrom(params.recipient, params.pair, params.liquidityToMigrate);
  (uint256 amount0V2, uint256 amount1V2) = IBiswapPair(params.pair).burn(address(this));

  // calculate the amounts to migrate to v3
  uint128 amount0V2ToMigrate = uint128(amount0V2);
  uint128 amount1V2ToMigrate = uint128(amount1V2);

  // approve the position manager up to the maximum token amounts
  safeApprove(params.token0, liquidityManager, amount0V2ToMigrate);
  safeApprove(params.token1, liquidityManager, amount1V2ToMigrate);

  // mint v3 position
  (,, uint256 amount0V3, uint256 amount1V3) = ILiquidityManager(liquidityManager).mint(
    ILiquidityManager.MintParam({
      miner: params.recipient,
      tokenX: params.token0,
      tokenY: params.token1,
      fee: params.fee,
      pl: params.tickLower,
      pr: params.tickUpper,
      xLim: amount0V2ToMigrate,
      yLim: amount1V2ToMigrate,
      amountXMin: params.amount0Min,
      amountYMin: params.amount1Min,
      deadline: params.deadline
    })
  );

  // if necessary, clear allowance and refund dust
  if (amount0V3 < amount0V2) {
    if (amount0V3 < amount0V2ToMigrate) {
      safeApprove(params.token0, liquidityManager, 0);
    }

    refund0 = amount0V2 - amount0V3;
    if (params.refundAsETH && params.token0 == WETH9) {
      IWETH9(WETH9).withdraw(refund0);
      safeTransferETH(params.recipient, refund0);
    } else {
      safeTransfer(params.token0, params.recipient, refund0);
    }
  }
  if (amount1V3 < amount1V2) {
    if (amount1V3 < amount1V2ToMigrate) {
      safeApprove(params.token1, liquidityManager, 0);
    }

    refund1 = amount1V2 - amount1V3;
    if (params.refundAsETH && params.token1 == WETH9) {
      IWETH9(WETH9).withdraw(refund1);
      safeTransferETH(params.recipient, refund1);
    } else {
      safeTransfer(params.token1, params.recipient, refund1);
    }
  }

  emit Migrate(params, amount0V2, amount1V2, amount0V3, amount1V3);
}

Step 3:

The attacker also controlled the `params.token0` and `params.token1` entities, allowing them to add arbitrary tokens for the V3 liquidity as they also lacked checks validating whether those tokens were actually the V2 LP tokens referencing token0 and token1.

Step 4:

Essentially, the attacker used a real token pair but fake entities of `token0` and `token1` to migrate the victim's token into the migrator's contract, and then used a fake token pair but real `token0` and `token1` to drain the contract.

Step 5:

The attacker called the migrate function using fake tokens on all of the affected users who had provided approvals to the BSW-LP to V3Migrator.

Step 6:

This allowed them to burn LP and transfer the underlying tokens to V3Migrator.

Step 7:

The LiquidityManager transferred fake tokens as underlying tokens and then minted the V3 position of the fake underlying tokens for the victim.

Step 8:

The attacker called the migrate function yet again, with their exploit contract as a `params.pair` and set `token0` and `token1` as the real underlying tokens.

Step 9:

The LiquidityManager used the underlying tokens from the earlier executed burn function to mint a new LP, and the left-over tokens from minting this new LP were ultimately transferred to the attacker's address as profit.

Aftermath#

Following the exploit, the team acknowledged the occurrence of the exploit and urged users to revoke the contract approvals for all of the affected contracts.

They added that their team had fixed the exploit on the migrator contract and that the assets on the V2 and V3 AMM protocols of Biswap were safe.

According to the postmortem report, the team has investigated the issue and restricted access to the migrator contract. A confluence of factors led to the exploit, and Biswap takes responsibility for this incident. All of the affected users are likely to get compensation in the days to come.

Solution#

The Biswap exploit serves as a stark reminder of the potential risks in DeFi and the crucial role of smart contract security. Preventing such attacks is a multi-pronged effort involving vigilance by both developers and users, but the impact of such attacks can be significantly mitigated with protective measures such as Neptune Mutual's coverage.

Firstly, this exploit highlights the importance of regular audits and thorough testing of smart contract code, especially for critical functionalities like a liquidity migration contract. Although Biswap had security measures in place, this incident shows that they were not comprehensive enough.

Secondly, users must be careful when granting approvals to contracts. The Biswap exploit allowed the attacker to leverage approvals given by users.

Most importantly, had Biswap set up a dedicated cover pool in the Neptune Mutual marketplace, the impact of this attack on its users would have been significantly reduced. Our platform provides coverage against losses from all such exploits as a result of smart contract vulnerabilities. If the affected users had taken Neptune Mutual's parametric coverage, they could have claimed their losses without needing to provide evidence of the loss, as our incident resolution system expedites claims as soon as an incident is resolved.

Our marketplace is available on multiple popular blockchain networks, including EthereumArbitrum, and the BNB chain. This accessibility enables us to serve a wide range of DeFi users and protect them from potential smart contract vulnerabilities.

Our platform is not just about providing coverage; we also evaluate the platform for DNS and web-based security, frontend and backend security, intrusion detection and prevention, and other crucial security aspects. This comprehensive approach ensures that our users are protected on multiple fronts, enhancing their confidence and trust in the DeFi ecosystem.

Reference Source Biswap

By

Tags