Back to Blog

Cómo explotar la misma vulnerabilidad de MetaPool de dos formas distintas (Nerve Bridge / Saddle Finance): Lo que ves no es lo que obtienes

Code Auditing
May 6, 2022
9 min read

El 30 de abril de 2022, un atacante explotó la misma vulnerabilidad del Incidente de Nerve Bridge para atacar Saddle Finance. En total, 4.900 Ether estuvieron bajo ataque. Afortunadamente, 1.360 Ether de ellos fueron salvados con éxito por nosotros. La descripción detallada de este incidente se puede encontrar en el post mortem oficial.

Aunque se explotó la misma vulnerabilidad, el método de ataque es diferente al anterior. Como el nuevo método de ataque no es tan sencillo como podría esperarse, creemos que merece un mayor esfuerzo para llevar a cabo una investigación profunda. En este informe, primero ilustramos brevemente la vulnerabilidad, luego revisamos el método de ataque original del Incidente de Nerve Bridge. Después de eso, nos centramos en el Incidente de Saddle Finance diseccionando el proceso de ataque para desmitificar el nuevo método de ataque.

0x1. Acerca de los Contratos Desplegados

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

  • El contrato víctima MetaSwap: 0x824dcd7b044d60df2e89b1bb888e66d8bcf41491
  • El contrato vulnerable MetaSwapUtils: 0x88Cc4aA0dd6Cf126b00C012dDa9f6F4fd9388b17

Vale la pena señalar que el código mostrado del contrato MetaSwapUtils asociado con el contrato MetaSwap verificado NO es equivalente al contrato MetaSwapUtils desplegado, cuya dirección se especifica en Settings, como se muestra a continuación:

Por lo tanto, no confunda estos dos contratos MetaSwapUtils :)

0x2. Análisis de la Vulnerabilidad

El contrato vulnerable pertenece a MetaPool, que ha sido discutido en detalle en el blog anterior. En resumen, MetaPool fue diseñado originalmente por Curve para permitir que una sola moneda se agrupe con todas las monedas en otro pool (base) sin diluir su liquidez. Es esencialmente un pool que consiste en una stable-coin y un token LP del pool base, que consiste en varias otras stable-coins. Existe una preocupación con el diseño de MetaPool, es decir, MetaPool es básicamente un pool de stable-coins que mantiene precios para stable-coins, mientras que el token LP de un pool base de stable-coins NO es una stable-coin.

De hecho, el precio de un token LP de un pool base de stable-coins se puede obtener invocando la función getVirtualPrice del pool base, y su precio aumenta de manera constante con la acumulación de comisiones cobradas por el pool base. Para manejar eso, MetaPool escala hacia arriba la reserva del token LP antes de calcular el precio, como se muestra a continuación.

En consecuencia, si un usuario intercambia un token LP por una stable-coin, la cantidad del token LP se escalará hacia arriba antes de calcular el precio. Alternativamente, si un usuario intercambia una stable-coin por un token LP, la cantidad calculada del token LP se escalará hacia abajo antes de transferirla y contabilizarla.

El fragmento de código anterior de la función swapUnderlying se utiliza para intercambiar entre la stable-coin en el MetaPool y las stable-coins en el pool base. Como se muestra en los dos rectángulos rojos, la función escala hacia arriba la cantidad del token LP entrante y escala hacia abajo la cantidad del token LP que se intercambia.

Sin embargo, la implementación de la función swap es inconsistente con la de la función swapUnderlying. Específicamente, la causa raíz de la vulnerabilidad se debe al cálculo defectuoso implementado en la función swap (es decir, la función _calculateSwap) que no escala correctamente hacia abajo y hacia arriba la cantidad del token LP. Como se muestra a continuación, el lado izquierdo muestra el código vulnerable de MetaPool, mientras que el lado derecho muestra la versión corregida.

El atacante del Incidente de Nerve Bridge explotó la inconsistencia entre la función swap y la función swapUnderlying. (Tenga en cuenta que Nerve Bridge es un proyecto fork de Saddle Finance.) Después de eso, Saddle Finance corrigió la vulnerabilidad y re-desplegó inmediatamente la nueva versión (es decir, V2) de la biblioteca MetaSwapUtils.

Desafortunadamente, por alguna razón desconocida, el MetaPool sUSD V2 en Ethereum todavía fue desplegado con la antigua y vulnerable biblioteca MetaSwapUtils. Como resultado, esta vulnerabilidad fue explotada con éxito por un atacante una vez más el 30 de abril. Curiosamente, a diferencia del método de ataque utilizado en el Incidente de Nerve Bridge, se adoptó una forma diferente para atacar el MetaPool vulnerable.

0x3. El Método de Ataque Original del Incidente de Nerve Bridge

Reutilizamos la figura a continuación (ver el blog anterior) para revisar el método de ataque original.

Dado que la función swap vulnerable no escala hacia abajo la cantidad del token LP (Nerve 3-LP) que se intercambia, la cantidad intercambiada (36.959) en el Paso 3 es mayor de lo normal. Luego, el atacante invoca la función swapUnderlying (sin vulnerabilidad) para vender los 36.959 Nerve 3-LP (en los Pasos 4 y 5) por 51.494 fUSDT, obteniendo una ganancia de 1.143 fUSDT.

Razonablemente, la ganancia se puede explicar así: el atacante obtiene más Nerve 3-LP en el Paso 3, y luego los vende a un precio "normal" aprovechando la inconsistencia entre la función swap y la función swapUnderlying.

0x4. El Nuevo Método de Ataque del Incidente de Saddle Finance

El atacante del reciente Incidente de Saddle Finance utilizó una forma diferente para atacar la misma función swap vulnerable sin involucrar la función swapUnderlying. Aquí tomamos una transacción de ataque como ejemplo concreto para ilustrar el proceso.

Intuitivamente, parecería que no debería existir ninguna ganancia, ya que cualquier implicación de los Pasos 3 y 4 se contrarrestaría. Específicamente, en el Paso 3, el atacante podría intercambiar más saddleUSD debido a la falta de escalado hacia abajo del token LP (es decir, saddleUSD) que se intercambia. Sin embargo, en el Paso 4, el atacante inevitablemente intercambiaría MENOS sUSD, porque la función swap vulnerable no escala hacia arriba la cantidad de saddleUSD entrante antes de calcular el precio.

Sin embargo, como se muestra en la figura anterior, el atacante obtuvo una ganancia de 2.059.771 sUSD a través del par de intercambios en los Pasos 3 y 4. Para descubrir la razón de la ganancia, debemos profundizar en el mecanismo de precios y realizar una investigación exhaustiva para comprender el proceso de ataque.

0x4.1 El Mecanismo de Precios

El MetaPool de Saddle Finance hereda la fórmula de precios de Curve:

La gráfica de la función (cuando n es igual a 2) se muestra como la curva azul en la figura a continuación. (El diseño de la fórmula se puede encontrar en el Libro Blanco de Curve StableSwap.)

Aquí surge la pregunta: ¿cómo calcula el MetaPool el precio para cada intercambio utilizando esta fórmula?

Digamos que n es 2, y un usuario usa dx0 token0 para intercambiar dx1 token1. Podemos simular el proceso de cálculo para dx1. En cada intercambio, A puede tratarse como una constante, y D es la única variable que puede afectar la curva de precios. De hecho, D aumenta con la acumulación de comisiones cobradas por el pool. Específicamente, el proceso de cálculo se puede resumir en los siguientes tres pasos:

  • Paso I: Poner las reservas actuales del pool (x0 y x1) en la fórmula para calcular el D actual, que determina la curva de precios actual.
  • Paso II: Hacer que x0 aumente en dx0, y poner el D actual y x0 en la fórmula para calcular el nuevo x1.
  • Paso III: Entonces, dx1 es la diferencia entre el nuevo x1 y el antiguo x1.

Si token0 es el token LP de un pool base, entonces el Paso II se convierte en:

Aquí baseVirtualPrice/1e18 es aproximadamente 1.0033 durante el ataque. Alternativamente, si el token es el token LP de un pool base, entonces el Paso III se convierte en:

Para comprender cómo D afecta la curva de precios, también usamos un ejemplo para describirlo. Digamos que un usuario primero intercambia dx0 token0 por dx1 token1, y luego intercambia dx1 token1 por dx0' token0.

Como se muestra en la figura anterior, dado que el Paso ② cobra comisiones por el primer intercambio, D aumenta para desplazar la curva de precios hacia arriba (de la curva negra a la azul). Además, la figura describe claramente la razón por la que dx0' es menor que dx0'.

0x4.2 El Análisis del Ataque

Para analizar la razón de la ganancia, desplegamos localmente las bibliotecas MetaSwapUtils vulnerables y corregidas y utilizamos el estado del pool víctima en ese momento para simular el ataque. Además, durante esta simulación, también registramos algunos valores que pueden ayudar a comprender el proceso de ataque, es decir, A es 10.000, x_sUSD es 8.130.463, x_saddleUSD es 9.688.608, y D es 17.818.392 en ese momento.

La figura anterior describe el proceso del par de intercambios rentable:

  • Swap-I: intercambiar 14.800.272 sUSD por 9.657.586 saddleUSD
  • Swap-II: intercambiar 9.657.586 saddleUSD por 16.860.043 sUSD

Específicamente, el Swap-I se puede dividir en los siguientes dos pasos:

  • ①: Intercambiar 14.800.272 sUSD por 9.625.654 saddleUSD. Ahora, D aumenta a 17.931.435 (debido a las comisiones cobradas).
  • ②: Dado que el MetaPool vulnerable no escala hacia abajo la cantidad de saddleUSD intercambiado, el pool pierde 31.932 saddleUSD. Las pérdidas disminuyen D a 15.736.195, lo que desplaza adicionalmente la curva de precios hacia abajo (de la curva negra a la gris).

Del mismo modo, el Swap-II también se puede dividir en dos pasos:

  • ③: Dado que la curva de precios se desplaza hacia abajo, los mismos 9.625.654 saddleUSD pueden intercambiarse por 16.891.906 sUSD, que es mucho más que el costo: 14.800.272 sUSD.
  • ④: Dado que el MetaPool vulnerable no escala hacia arriba la cantidad de saddleUSD entrante antes de calcular el precio, quedan 31.863 sUSD en el MetaPool, lo que desplaza la curva de precios hacia arriba (de la curva gris a la azul). No obstante, el par de intercambios aún genera una ganancia de 2.059.771 sUSD.

Obviamente, el análisis anterior explica claramente por qué el atacante pudo obtener ganancias utilizando el nuevo método de ataque. Además, parece que el método de ataque original es más eficiente que el nuevo debido al sUSD restante en el MetaPool en el Swap-II. Por supuesto, el atacante podría lanzar múltiples ataques para vaciar el pool, lo cual ha sido observado en la práctica.

0x5. Algunas Conclusiones

La investigación sugiere que la causa raíz de las ganancias en los dos incidentes es la misma. Específicamente, el primer intercambio (que intercambia por el token LP) disminuye D del MetaPool vulnerable, lo que desplaza su curva de precios hacia abajo. Ese desplazamiento afecta enormemente la fijación de precios posterior y es la razón principal de la ganancia subsiguiente.

Acerca de BlockSec

BlockSec es una empresa pionera en seguridad blockchain establecida en 2021 por un grupo de expertos en seguridad de reconocimiento mundial. La empresa está comprometida a mejorar la seguridad y la usabilidad del emergente mundo Web3 con el fin de facilitar su adopción masiva. Con este fin, BlockSec ofrece servicios de auditoría de seguridad de contratos inteligentes y cadenas EVM, la plataforma Phalcon para el desarrollo de seguridad y el bloqueo proactivo de amenazas, la plataforma MetaSleuth para el seguimiento e investigación de fondos, y la extensión MetaDock para que los constructores de web3 naveguen de manera eficiente en el mundo cripto.

Hasta la fecha, la empresa ha prestado servicios a más de 300 clientes de prestigio, como MetaMask, Uniswap Foundation, Compound, Forta y PancakeSwap, y ha recibido decenas de millones de dólares en dos rondas de financiación de inversores destacados, incluyendo Matrix Partners, Vitalbridge Capital y Fenbushi Capital.

Sitio web oficial: https://blocksec.com/

Cuenta oficial de 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