Back to Blog

El Análisis del Incidente de Seguridad del Puente Nervioso

Code Auditing
November 18, 2021
5 min read

0x.1 Prefacio

El 15 de noviembre de 2021, nuestro sistema de monitoreo interno detectó transacciones flashloan sospechosas en BSC. Tras la investigación, descubrimos que se trataba de un ataque dirigido a Nerve Bridge, incluyendo los MetaPools de fUSDT y UST.

Figura 1: un ejemplo de transacción de ataque
Figura 1: un ejemplo de transacción de ataque

Al momento de redactar este artículo, el atacante ha agotado la liquidez de fUSDT y UST de los pools de staking de Nerve, y obtuvo una ganancia de 900 BNB.

Sorprendentemente, descubrimos que el código vulnerable es un fork de Saddle.Finance, que ya había provocado una pérdida de $800M en Synapse Bridge el 6 de noviembre de 2021. Específicamente, la causa raíz de la vulnerabilidad proviene de la implementación inconsistente del cálculo del monto de intercambio de tokens en diferentes bibliotecas.

Sin embargo, NO existe ningún informe público disponible que analice este incidente de seguridad. Por ello, en este blog, nuestro objetivo es proporcionar un análisis exhaustivo, incluyendo el mecanismo del proyecto, la vulnerabilidad y el ataque.

0x2. Contexto

0x2.1 ¿Qué es un MetaPool?

Básicamente, Curve ofrece dos tipos de pools de intercambio de stablecoins, es decir, el Pool StableSwap Estándar y el MetaPool. El primero es un AMM completo para crear mercados cruzados entre diferentes stablecoins [1]. Es el tipo de pool más utilizado, por ejemplo, Curve.3pool, que consiste en DAI, USDC y USDT. Sin embargo, este pool no puede aislar el riesgo entre stablecoins, lo que puede provocar grandes pérdidas para los proveedores de liquidez (LP).

Por ello, se propuso el MetaPool para resolver este problema. Según lo establecido por Curve [2], "permite que una sola moneda se combine con todas las monedas de otro pool (base) sin diluir su liquidez". Es esencialmente un pool de intercambio entre una stablecoin y un token LP de un Pool StableSwap Estándar (que consiste en varias otras stablecoins). En nuestro contexto, llamamos a estos dos tipos de stablecoins stablecoin del pool y stablecoin subyacente, respectivamente.

Por ejemplo, una de las víctimas de este incidente es precisamente el MetaPool de fUSDT y el token LP de Nerve.3pool (incluyendo BUSD, USD y USDC), y la estructura de este pool es esencialmente [fUSDT, token LP de (BUSD, USD, USDC)]. Por lo tanto, fUSDT es la stablecoin del pool, mientras que BUSD, USD y USDC son las stablecoins subyacentes.

Figura 2: Nerve.3pool
Figura 2: Nerve.3pool

0x2.2 Origen del Código Vulnerable

El MetaPool de Curve está implementado en Vyper. Para apoyar el desarrollo en Solidity, el equipo de desarrollo de Saddle.Finance reescribió el código en Solidity. Desde el inicio de esta vulnerabilidad, fue forkeado y adoptado por Synapse y Nerve, respectivamente. El 6 de noviembre, Synapse fue atacado.

Figura 3: transacciones de ataque dirigidas a Synapse
Figura 3: transacciones de ataque dirigidas a Synapse

Aproximadamente $8.2M en fondos fueron drenados del MetaPool, aunque en realidad no se perdieron fondos debido a un error "tonto" cometido por el atacante [3].

Después de eso, Saddle.Finance tomó medidas de emergencia para garantizar la seguridad de sus fondos pausando todos los contratos MetaPool. Sin embargo, Nerve Bridge no tomó ninguna acción, lo que inevitablemente llevó a este incidente de seguridad.

Las direcciones de contratos relevantes se enumeran a continuación:

  • MetaSwap: 0xd0fBF0A224563D5fFc8A57e4fdA6Ae080EbCf3D3
  • SwapUtils: 0x02338Ee742ddCDe44488640F4edf1Aa947E670E7

0x3. Análisis de la Vulnerabilidad

En MetaPool, existen dos funciones importantes, es decir, swap y swapUnderlying. Específicamente, la primera se utiliza para intercambiar el token LP y la stablecoin del pool, mientras que la segunda se utiliza para intercambiar la stablecoin del pool y las stablecoins subyacentes.

swap: función _calculateSwap
swap: función _calculateSwap
swapUnderlying: función _calculateSwapUnderlying
swapUnderlying: función _calculateSwapUnderlying

Sin embargo, las dos funciones están implementadas de manera inconsistente. Como se muestra en las dos figuras anteriores. El fragmento de código en el rectángulo rojo se utiliza para ajustar el valor del token LP midiendo el "precio virtual" de un token LP (que aumenta desde un valor base de 1 a medida que se acumulan más comisiones). Mientras tanto, la función swap ignora el impacto del precio virtual, lo que significa que el valor del token LP será subestimado. En otras palabras, se podrían intercambiar más tokens LP.

Como resultado, es posible obtener más stablecoins del pool recuperando primero la liquidez de las stablecoins subyacentes con el token LP correspondiente, y luego intercambiando stablecoins del pool mediante la función swapUnderlying.

0x4. Análisis del Ataque

Tomaremos la transacción de ejemplo como ejemplo para ilustrar el ataque.

Figura 6: los cinco pasos del ataque
Figura 6: los cinco pasos del ataque

La Figura 6 muestra que el atacante siguió los siguientes cinco pasos para lanzar el ataque:

  • Paso 1: solicitar un préstamo de 50,000 BUSD mediante Flashloan de Fortube
  • Paso 2: intercambiar 50,000 BUSD por 50,351 fUSDT en Ellipsis.
  • Paso 3: invocar la función swap de MetaSwap para intercambiar 50,351 fUSDT por 36,959 Nerve 3-LP con un slippage relativamente alto.
  • Paso 4: invocar la función removeLiquidityOneCoin de Nerve.3pool con los tokens LP (recibidos en el paso anterior) para retirar la liquidez de BUSD, es decir, 37,071 BUSD.
  • Paso 5: invocar la función swapUnderlying de MetaSwap para intercambiar BUSD por fUSDT, y recibir 51,494 fUSDT.

El atacante ejecutó repetidamente los cinco pasos anteriores (alrededor de 200+ transacciones) para drenar la liquidez del MetaPool, y finalmente obtuvo 900 BNB.

Curiosamente, el atacante adoptó el mismo enfoque utilizado en el incidente de Synapse, que no es la forma optimizada de lograr el objetivo. Alternativamente, es posible lanzar ataques de manera más eficiente, por ejemplo, aplicando parámetros optimizados para drenar la liquidez en una sola transacción. El resultado sugiere que el atacante podría NO haber comprendido completamente la causa raíz de esta vulnerabilidad.

Referencias

[1] https://curve.fi/files/stableswap-paper.pdf

[2] https://resources.curve.fi/lp/depositing/depositing-into-a-metapool/

[3] https://synapseprotocol.medium.com/11-06-2021-post-mortem-of-synapse-metapool-exploit-3003b4df4ef4

Créditos: Hailin Wang, Lei Wu, Yajin Zhou @BlockSec

Twitter: https://twitter.com/BlockSecTeam

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit