How to exploit the same vulnerability of MetaPool in two different ways (Nerve Bridge / Saddle Finance) — What you see is not what you get
May 6 2022

On April 30th 2022, an attacker exploited the same vulnerability in the Nerve Bridge Incident to attack the Saddle Finance. In total, 4,900 Ether were under attack. Fortunately, 1,360 Ether of them were successfully saved by us. The detailed description of this incident can be found from the official post mortem.

Although the same vulnerability was exploited, the attack method is different from the previous one. As the new attack method is not as straightforward as one may expect, we believe it deserves more efforts to perform a deep investigation. In this report, we first briefly illustrate the vulnerability, and then review the original attack method of the Nerve Bridge Incident. After that, we focus on the Saddle Finance Incident by dissecting the attack process to demystify the new attack method.

0x1. About the Deployed Contracts

The relevant contract addresses are listed in the following:

  • The victim MetaSwap contract: 0x824dcd7b044d60df2e89b1bb888e66d8bcf41491
  • The vulnerable MetaSwapUtils contract: 0x88Cc4aA0dd6Cf126b00C012dDa9f6F4fd9388b17

It is worth noting that the shown code of the MetaSwapUtils contract associated with the verified MetaSwap contract is NOT equivalent to the deployed MetaSwapUtils contract, whose address is specified in the Settings, as follows:

So do not be confused with these two MetaSwapUtils contracts:)

0x2. Vulnerability Analysis

The vulnerable contract belongs to MetaPool, which has been discussed in detail in the previous blog. In short, MetaPool was originally designed by Curve to allow a single coin to be pooled with all the coins in another (base) pool without diluting its liquidity. It's essentially a pool consisting of a stable-coin and a LP token of the base pool, which consists of several other stable-coins. There is a concern for the MetaPool design, i.e., the MetaPool is basically a stable-coin pool maintaining prices for stable-coins, while the LP token of a base stable-coin pool is NOT a stable-coin.

In fact, the price of a LP token of a base stable-coin pool can be obtained by invoking the getVirtualPrice function of the base pool, and its price steadily increases with the accumulation of fees charged by the base pool. To handle that, MetaPool scales up the LP token's reserve before calculating the price, as shown in the below.

Accordingly, if a user swaps a LP token for a stable-coin, the amount of the LP token will be scaled up before calculating the price. Alternatively, if a user swaps a stable-coin for a LP token, the calculated amount of the LP token will be scaled down before transferring and bookkeeping.

The above code snippet of the swapUnderlying function is used to swap between the stable-coin in the MetaPool and those stable-coins in the base pool. As shown in the two red rectangles, the function scales up the amount of incoming LP token and scales down the amount of LP token being exchanged.

However, the implementation of the swap function is inconsistent with that of the swapUnderlying function. Specifically, the root cause of the vulnerability is due to the flawed calculation implemented in the swap function (i.e., the _calculateSwap function) which does not properly scale down and up the amount of the LP token. As shown in the below, the left side gives the vulnerable code of MetaPool, while the right side gives the fixed version.

The attacker of the Nerve Bridge Incident exploited the inconsistency between the swap function and swapUnderlying function. (Note that Nerve Bridge is a fork project of Saddle Finance.) After that, Saddle Finance fixed the vulnerability and re-deployed the new version (i.e., V2) of the MetaSwapUtils library immediately.

Unfortunately, due to some unknown reason, the sUSD V2 MetaPool on Ethereum was still deployed with the old and vulnerable MetaSwapUtils library. As a result, this vulnerability was successfully exploited by an attacker once again on April 30th. Interestingly, unlike the attack method used in the Nerve Bridge Incident, a different way was adopted to attack the vulnerable MetaPool.

0x3. The Original Attack Method of the Nerve Bridge Incident

We re-use the below figure (see the previous blog) to review the original attack method.

Since the vulnerable swap function does not scale down the amount of the LP token (Nerve 3-LP) being exchanged, the exchanged amount (36,959) in the Step 3 is larger than normal. Then the attacker invokes the swapUnderlying function (without vulnerability) to sell the 36,959 Nerve 3-LP (in the Step 4 and 5) for 51,494 fUSDT, which profits 1,143 fUSDT.

Reasonably, the profit can be explained as: the attacker harvests more Nerve 3-LP in the Step 3, and then the attacker sells them in a "normal" price by leveraging the inconsistency between the swap function and the swapUnderlying function.

0x4. The New Attack Method of the Saddle Finance Incident

The attacker of the recent Saddle Finance Incident used a different way to attack the same vulnerable swap function without involving the swapUnderlying function. Here we take one attack transaction as a concrete example to illustrate the process.

Intuitively, it seems that there should not exist any profit, as any implication of Step 3 and Step 4 would be counteracted. Specifically, in Step 3, the attacker could swap out more saddleUSD due to the lack of scaling down the LP token (i.e., saddleUSD) being exchanged. However, in Step 4, the attacker would inevitably swap out LESS sUSD, because the vulnerable swap function does not scale up the amount of incoming saddleUSD before calculating the price.

However, as shown in the above figure, the attacker profited 2,059,771 sUSD through the pair of swaps in Step 3 and Step 4. To figure out the reason of the profit, we have to dive into the pricing mechanism and perform a deep investigation to understand the attack process.

0x4.1 The Pricing Mechanism

The MetaPool of Saddle Finance inherits Curve's pricing formula:

The graph of the function (when n equals to 2) is shown as the blue curve in the below figure. (The design of the formula can be found in Curve StableSwap Whitepaper.)

Here comes the question: how does the MetaPool calculate the price for each swap by using this formula?

Let's say n is 2, and a user uses dx0 token0 to swap dx1 token1. We can simulate the calculation process for dx1. In each swap, A can be treated as a constant, and D is the only variable that can affect the price curve. In fact, D is increased with the accumulation of the fees charged by the pool. Specifically, the calculation process can be summarized as the following three steps:

  • Step I: Put the current pool's reserves (x0 and x1) into the formula to calculate the current D, which determines the current price curve.
  • Step II: Let the x0 increase dx0, and put the current D and x0 into the formula to calculate the new x1.
  • Step III: Then, dx1 is the difference between the new x1 and the old x1.

If token0 is the LP token of a base pool, then the Step II becomes:

Here baseVirtualPrice/1e18 is around 1.0033 during the attack. Alternatively, if the token is the LP token of a base pool, then the Step III becomes:

To understand how D affects the price curve, we also use an example to describe it. Say a user first swaps dx0 token0 for dx1 token1, and then swaps dx1 token1 for dx0' token0.

As shown in the above figure, since Step ② charges fees for the first swap, D is increased to shift the price curve upwards (from the black curve to the blue one). Furthermore, the figure clearly describes the reason why dx0' is smaller than dx0'.

0x4.2 The Attack Analysis

To analyze the reason of the profit, we deployed the vulnerable and fixed MetaSwapUtils libraries locally and used the state of the victim pool at that moment to simulate the attack. Furthermore, during this simulation, we also recorded a few values that can help to understand the attack process, i.e., A is 10,000, x_sUSD is 8,130,463, x_saddleUSD is 9,688,608, and D is 17,818,392 at that moment.

The above figure describes the process of the profitable pair of swaps:

  • Swap-I: swap 14,800,272 sUSD for 9,657,586 saddleUSD
  • Swap-II: swap 9,657,586 saddleUSD for 16,860,043 sUSD

Specifically, Swap-I can be divided into the following two steps:

  • ①: Swap 14,800,272 sUSD for 9,625,654 saddleUSD. Now, D is increased as 17,931,435 (due to the charged fees).
  • ②: Since the vulnerable MetaPool does not scale down the amount of exchanged saddleUSD, the pool losses 31,932 saddleUSD. The losses decrease D as 15,736,195, which further shifts the price curve down (from the black curve to the gray one).

Similarly, Swap-II can also be divided into two steps:

  • ③: Since the price curve is shifted down, the same 9,625,654 saddleUSD can swap out 16,891,906 sUSD that is far more than the cost: 14,800,272 sUSD.
  • ④: Since the vulnerable MetaPool does not scale up the amount of incoming saddleUSD before calculating the price, there is 31,863 sUSD left in the MetaPool, which shifts the price curve up (from the gray curve to the blue one). Nevertheless, the pair of swaps still profits 2,059,771 sUSD.

Obviously, the above analysis clearly elaborates why the attacker could harvest the profit by using the new attack method. Besides, it seems that the original attack method seems to be more efficient than the new one due to the sUSD left in the MetaPool in Swap-II. Of course, the attacker could launch multiple attacks to drain the pool, which have been observed in the wild.

0x5. Some Take Away

The investigation suggests that the root cause for the profits in the two incidents is the same. Specifically, the first swap (which swaps for the LP token) decreases D of the vulnerable MetaPool, which further shifts its price curve down. That shifting greatly affects the subsequent pricing and is the main reason for the subsequent profit.

About BlockSec

BlockSec is a pioneering blockchain security company established in 2021 by a group of globally distinguished security experts. The company is committed to enhancing security and usability for the emerging Web3 world in order to facilitate its mass adoption. To this end, BlockSec provides smart contract and EVM chain security auditing services, the Phalcon platform for security development and blocking threats proactively, the MetaSleuth platform for fund tracking and investigation, and MetaDock extension for web3 builders surfing efficiently in the crypto world.

To date, the company has served over 300 esteemed clients such as MetaMask, Uniswap Foundation, Compound, Forta, and PancakeSwap, and received tens of millions of US dollars in two rounds of financing from preeminent investors, including Matrix Partners, Vitalbridge Capital, and Fenbushi Capital.

Official website: https://blocksec.com/

Official Twitter account: https://twitter.com/BlockSecTeam

Sign up for the latest updates
#10: ThirdWeb Incident: Incompatibility Between Trusted Modules Exposes Vulnerability
Security Insights

#10: ThirdWeb Incident: Incompatibility Between Trusted Modules Exposes Vulnerability

This blog shows the vulnerability and attack caused by Incompatibility of commonly used modules.

#9: MEV Bot 0xd61492: From Predator to Prey in an Ingenious Exploit
Security Insights

#9: MEV Bot 0xd61492: From Predator to Prey in an Ingenious Exploit

On August 3, 2023, an MEV Bot on Arbitrum was attacked, resulting in $800K in loss. The root cause of this attack was **Insufficient User Input Verification**.

#8: SushiSwap Incident: A Clumsy Rescue Attempt Leads to a Series of Copycat Attacks
Case Studies

#8: SushiSwap Incident: A Clumsy Rescue Attempt Leads to a Series of Copycat Attacks

On April 9, 2023, SushiSwap became the target of an exploit due to an Unverified External Parameter. The total loss is about $3.3 million.

BlockSec uses cookies and other identifiers to analyze our traffic in accordance. We also share information about your use of our site with our analytics partners. By remaining on this website, you consent to our use of cookies and the Privacy Policy.