El 15 de mayo de 2024, Sonne Finance fue atacada en la cadena Optimism, lo que provocó pérdidas de hasta 20 millones de dólares.
Después del ataque, el usuario @tonyke_bot en
(https://twitter.com/tonyke_bot/status/1790547461611860182)
Después de que el proyecto Sonne Finance descubrió el ataque, rápidamente suspendió todos los mercados en Optimism y declaró que los mercados en Base estaban seguros.
(https://twitter.com/SonneFinance/status/1790535383005966554)
Informe de ataque
Sonne Finance es un protocolo de préstamos descentralizado que bifurca Compound V2 on Optimism, brindando a individuos, instituciones y protocolos acceso a servicios financieros. El protocolo Sonne Finance agrega los activos simbólicos de los usuarios para formar un fondo de liquidez crediticia, proporcionando a los usuarios un negocio de préstamos similar al de un banco. Al igual que Compound, los participantes del protocolo pueden hipotecar sus tokens en el fondo de liquidez de préstamos de Sonne Finance y obtener el certificado soToken (igual que cToken). SoToken es un certificado de activo que devenga intereses, que generará una cierta cantidad de ingresos a medida que avance el bloque, y también recibirá incentivos de token SONE. Los participantes también pueden pedir prestados otros tokens del grupo de activos de préstamo de Sonne con el soToken en sus manos. Por ejemplo, los participantes pueden hipotecar una cierta cantidad de USDC para obtener certificados de soUSDC y luego prestar WETH para su posterior circulación. Los préstamos hipotecarios en el protocolo de Sonne Finance pueden ser una relación de activos de muchos a muchos. Durante el proceso de préstamo hipotecario, el protocolo calculará automáticamente el factor de salud (Factor de salud) de la dirección del participante. la hipoteca de la dirección Los productos respaldarán la liquidación, y los liquidadores también pueden recibir ciertas recompensas de liquidación.
La relación entre la cantidad de tokens subyacentes depositados por los usuarios y los soTokens acuñados está relacionada principalmente con una variable llamada tasa de cambio. Esta variable se puede utilizar de manera aproximada para indicar cuánto vale cada token subyacente. La fórmula de cálculo del tipo de cambio es la siguiente:
En la fórmula anterior, totalCash se refiere a la cantidad de tokens subyacentes que posee soToken, totalBorrows se refiere a la cantidad de tokens subyacentes prestados en un determinado mercado, totalReserves se refiere al monto total de la reserva (incluido el interés pagado por el prestatario), totalSupply Se refiere a la cantidad de soToken acuñados.
Al canjear, el usuario puede especificar la cantidad de tokens subyacentes que se canjearán, canjearAmount, para calcular la cantidad de soTokens que deben destruirse, canjearTokens. El método de cálculo es aproximadamente "redeemTokens = canjearAmount / exchangeRat". pérdida de precisión aquí.
La esencia de este ataque es que cuando se creó el mercado (soToken), el atacante realizó la primera operación de emisión de hipoteca y acuñó muy pocos soTokens con una pequeña cantidad de tokens subyacentes, lo que resultó en que el valor de "suministro total" de soToken fuera demasiado pequeño. Luego, el atacante aprovechó la vulnerabilidad de la pérdida de precisión del contrato de Solidity y luego envió el token subyacente directamente al contrato soToken (soToken no se acuñará, lo que significa que "totalSupply" permanece sin cambios y "totalCash" se hace más grande) en lugar del método de apuesta + lanzamiento. para depositar el token subyacente. Tal operación hace que la variable "totalCash" en el contrato sea mayor, pero "totalSupply" permanece sin cambios, lo que hace que el tipo de cambio aumente. Al final, cuando el atacante canjea el token subyacente, el soToken que debe destruirse es menor que el soToken acuñado durante la hipoteca. El atacante utiliza el soToken obtenido para prestar el token subyacente WETH y USDC a otros soTokens (como soWETH). , entonces USDC), y finalmente obtiene ganancias de hasta 20 millones de dólares estadounidenses.
Direcciones clave involucradas en el ataque
Transacciones de preparación de ataques:
https://optimistic.etherscan.io/tx/0x45c0ccfd3ca1b4a937feebcb0f5a166c409c9e403070808835d41da40732db96
Atacar transacciones rentables:
https://optimistic.etherscan.io/tx/0x9312ae377d7ebdf3c7c3a86f80514878deb5df51aad38b6191d55db53e42b7f0
Direcciones relacionadas con ataques EOA:
0x5d0d99e9886581ff8fcb01f35804317f5ed80bbb
0xae4a7cde7c99fb98b0d5fa414aa40f0300531f43
Dirección relacionada con el atacante (contrato):
0xa78aefd483ce3919c0ad55c8a2e5c97cbac1caf8
0x02fa2625825917e9b1f8346a465de1bbc150c5b9
token subyacente (VELO Token V2):
0x9560e827af36c94d2ac33a39bce1fe78631088db
Contrato de vulnerabilidad (soVELO, similar al cToken de Compound):
0xe3b81318b1b6776f0877c3770afddff97b9f5fe5
@tonyke_bot Transacción de rescate del usuario en X:
https://optimistic.etherscan.io/tx/0x816f9e289d8b9dee9a94086c200c0470c6456603c967f82ab559a5931fd181c2
Análisis del proceso de ataque.
Resumen
El equipo del proyecto Sonne Finance aprobó recientemente una propuesta para agregar el mercado VELO a Sonne Finance (https://twitter.com/SonneFinance/status/1786871066075206044) y organizó cinco transacciones a través de la billetera multifirma que se ejecutarán dos días después ( https://optimistic.etherscan.io/tx/0x18ebeb958b50579ce76528ed812025949dfcff8c2673eb0c8bc78b12ba6377b7), estas cinco transacciones se utilizan para crear el mercado VELO (contrato soVELO) y establecer algunas configuraciones clave del mercado, como establecer el modelo de tasa de interés, establecer el oráculo de precios y establecer los factores de la hipoteca, etc. Una vez creado el mercado VELO, los usuarios pueden depositar tokens VELO para acuñar tokens soVELO, que a su vez pueden usarse para pedir prestados otros soTokens.
preparación de ataque
La fase de preparación del ataque consiste principalmente en que el atacante cree un mercado VELO (contrato soVELO) basado en la información de la propuesta de proyecto de Sonne Finance después de que haya expirado el período de bloqueo de dos días de la propuesta, establezca configuraciones clave y acuñe. tokens VELO en el contrato soVELO hipotecando los tokens soVELO, y también envía los tokens VELO que posee directamente al contrato soVELO para aumentar la tasa de cambio y prepararse para obtener ganancias de ataques posteriores.
Los pasos específicos son los siguientes:
Después del período de bloqueo de dos días, el atacante primero empaquetó las operaciones de las primeras cuatro transacciones dispuestas en la propuesta en una sola transacción (transacción 0x45c0cc), la utilizó para crear el mercado VELO (contrato soVELO) y estableció configuraciones clave. . Cuando se inicializa el mercado VELO, el tipo de cambio se establece en "200.000.000.000.000.000.000.000.000".
El atacante llama a la función "mint" del contrato soVELO para depositar tokens VELO y acuñar tokens soVELO. El atacante especifica "mintAmount" como "400,000,001" (el número de tokens VELO). Como se puede ver en la función "exchangeRateStoredInternal", dado que "_totalSuppl" del token soVELO es 0 en este momento, exchangeRate es el valor establecido en el paso 1. Según la fórmula " mintTokens = actualMintAmount / exchangeRate ", el número calculado de tokens soVELO que deben acuñarse en este momento es 2. En resumen, en este paso, el atacante deposita tokens VELO con un valor de "400.000.001" en el contrato soVELO y obtiene tokens soVELO con un valor de 2.
soVELO.menta:
El atacante envió tokens VELO con un valor de "2,552,964,259,704,265,837,526" al contrato soVELO enviando tokens VELO directamente al contrato soVELO. En este momento, la cantidad de tokens VELO en poder del contrato soVELO aumentó, pero como no había nuevos tokens soVELO. Casting, por lo que totalSupply permanece sin cambios, lo que significa que el tipo de cambio calculado de acuerdo con la fórmula de cálculo del tipo de cambio aumentará en este momento.
El atacante transfirió sus tenencias de tokens soVELO varias veces y finalmente a otro atacante, EOA 0xae4a.
Ataque con fines de lucro
La fase de ganancias del ataque implica principalmente que el atacante ejecute la quinta transacción de la propuesta y preste tokens VELO directamente al contrato soVELO a través de préstamos rápidos para aumentar aún más el tipo de cambio. Luego, el atacante usó el token soVELO con un valor de 2 en su mano para tomar prestados tokens subyacentes como WETH y USDC de otros contratos de soToken (como soWETH, soUSDC, etc.), y estas partes se convirtieron en ganancias del atacante. Luego, el atacante fue a canjear su token subyacente en el contrato soVELO. Debido al aumento en el tipo de cambio y la pérdida de precisión en el cálculo de los tokens soVELO que deben destruirse para el canje, el atacante finalmente solo usó el token soVELO con un valor de. 1. Casi todos los tokens VELO depositados previamente se canjearon, lo que puede entenderse como que el atacante utilizó los tokens soVELO adicionales con un valor de 1 para obtener tokens subyacentes como WETH y USDC tomando prestados de otros soTokens. El atacante utilizó la misma técnica para repetir el ataque muchas veces y finalmente obtuvo enormes ganancias.
Los pasos específicos son los siguientes:
El atacante ejecuta la quinta transacción de la propuesta y establece el factor de préstamo especificado en la propuesta.
El atacante presta rápidamente tokens VELO con un valor de "35,469,150,965,253,049,864,450,449" del grupo VolatileV2 AMM - USDC/VELO, lo que activa la función de enlace del atacante. En la función de gancho, el atacante continúa realizando la operación de ataque.
El atacante envía sus propios tokens VELO al contrato soVELO para aumentar aún más el tipo de cambio. Actualmente, hay un total de tokens VELO con un valor de "35,471,703,929,512,754,530,287,976" en el contrato soVELO (la suma de tokens VELO transferidos tres veces por el atacante).
El atacante crea un nuevo contrato 0xa16388a6210545b27f669d5189648c1722300b8b en el constructor y transfiere los 2 tokens soVELO que posee al contrato recién creado 0xa163 (en adelante, el atacante 0xa163).
El atacante 0xa163 utilizó los tokens soVELO que tenía para pedir prestado WETH con un valor de "265,842,857,910,985,546,929" de soWETH.
El atacante 0xa163 llama a la función "redeemUnderlying" de soVELO y especifica el valor de los tokens VELO canjeados como "35,471,603,929,512,754,530,287,976" (casi la cantidad de tokens VELO que el atacante ha transferido o hipotecado previamente en el contrato soVELO. En este momento, la fórmula "redeemTokens =). redimeAmountIn / exchangeRate" para calcular la cantidad de tokens soVELO que deben destruirse para el canje.
Como se puede ver en la función "exchangeRateStoredInternal", dado que _totalSupply es 2 en lugar de 0, el valor de exchangeRate debe calcularse de acuerdo con la fórmula "exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply", el tipo de cambio actual es. "17,735,851,964,756,377,265,143,988,000, 000,000,000,000,000", este valor es mucho mayor que el tipo de cambio inicial establecido en "200,000,000,000,000,000,000,000,00".
El valor de "redemeTokens" calculado en base al nuevo tipo de cambio es "1,99". Debido a las características de redondeo a la baja de Solidity, el valor de "redemeTokens" termina siendo 1. Esto significa que el atacante 0xa163 utilizó tokens soVELO con un valor de 1 para canjear casi todos los tokens VELO depositados previamente. Al mismo tiempo, el atacante 0xa163 también obtuvo WETH con un valor de "265.842.857.910.985.546.929" prestado de soWETH.
soVELO.redeemSubyacente:
soVELO.exchangeRateStoredInternal:
El atacante 0xa163 transfirió todos los WETH prestados y canjeó los tokens VELO al atacante de nivel superior y luego se autodestruyó.
El atacante llama a la función "liquidateBorrow" de soWETH para liquidar parte de los activos tomados prestados del contrato recién creado 0xa163, con el objetivo de recuperar los tokens soVELO bloqueados con un valor de 1. Actualmente, el atacante solo posee tokens soVELO con un valor de 1.
El atacante llama a la función "mint" de soVELO para hipotecar y acuñar tokens soVELO nuevamente, con el objetivo de recolectar tokens soVELO con un valor de 2, y luego realiza nuevamente los pasos 3 a 8 anteriores para beneficiarse de otros tokens no permanentes.
El atacante realiza el paso 9 varias veces, paga el préstamo flash y se marcha con una ganancia.
Cómo 100 dólares aprovechan 6,5 millones de dólares
Después del ataque, el usuario @tonyke_bot en X acuñó 0.00000011 soVELO al apostar 1144 tokens VELO en el contrato soVELO en la transacción 0x0a284cd. La razón por la cual esta operación puede evitar que el atacante realice más ataques es porque esta transacción cambia el tamaño de totalSupply en soVELO y la cantidad de tokens VELO en totalCash retenidos, y el impacto del crecimiento de totalSupply en el cálculo del tipo de cambio es mayor que el impacto. del crecimiento de totalCash Por lo tanto, el tipo de cambio se vuelve más pequeño, lo que hace que el atacante ya no pueda usar la pérdida de precisión para ganar soVELO al realizar un ataque, lo que hace que el ataque ya no sea posible.
Seguimiento de dinero
El atacante transfirió los fondos poco después de apoderarse de las ganancias ilegales. La mayoría de los fondos fueron transferidos a las siguientes cuatro direcciones. Algunas tenían como objetivo cambiar de dirección para continuar el ataque y otras para lavar dinero.
0x4ab93fc50b82d4dc457db85888dfdae28d29b98d
El atacante transfirió 198 WETH a esta dirección, y luego la dirección utilizó el mismo método de ataque para obtener ganancias ilegales en las siguientes transacciones:
Después del ataque, la dirección transfirió las ganancias ilegales antes mencionadas a 0x5d0d99e9886581ff8fcb01f35804317f5ed80bbb.
0x5d0d99e9886581ff8fcb01f35804317f5ed80bbb
El atacante transfirió 724277 USDC y 2353 VELO a esta dirección e intercambió USDC por Ether. Parte de los fondos se transfirieron inmediatamente al puente entre cadenas de Stargate y la mayoría de los fondos ilegales permanecieron en esta dirección:
0xbd18100a168321701955e348f03d0df4f517c13b
El atacante transfirió 33 WETH a esta dirección y utilizó Peel Chain para intentar lavar dinero. El vínculo de lavado de dinero es el siguiente:
0xbd18100a168321701955e348f03d0df4f517c13b -> 0x7e97b74252b6df53caf386fb4c54d4fb59cb6928 -> 0xc521bde5e53f537ff208970152b75a0 03093c2b4 -> 0x9f09ec563222fe52712dc413d0b7b66cb5c7c795。
0x4fac0651bcc837bf889f6a7d79c1908419fe1770
El atacante transfirió 563 WETH a esta dirección y luego a 0x1915F77A116dcE7E9b8F4C4E43CDF81e2aCf9C68. Actualmente no hay más acciones.
El método de lavado de dinero del atacante esta vez es relativamente profesional y los métodos muestran una tendencia a la diversidad. Por lo tanto, para nosotros, los participantes de Web3, debemos continuar mejorando nuestras capacidades contra el lavado de dinero en términos de seguridad y mejorar la seguridad de los proyectos Defi a través de KYT, AML y otros productos de seguridad de transacciones blockchain relacionados.
Consejos de seguridad
La pérdida de precisión debe tomarse en serio. Los problemas de seguridad causados por la pérdida de precisión surgen sin cesar, especialmente en los proyectos Defi, donde la pérdida de precisión a menudo conduce a graves pérdidas financieras. Se recomienda que las partes del proyecto y los auditores de seguridad revisen cuidadosamente el código con pérdida de precisión en el proyecto y realicen pruebas para evitar esta vulnerabilidad tanto como sea posible.
Se recomienda que la creación de un mercado similar a cToken en Compound y la primera operación de conversión de hipoteca sean realizadas por usuarios privilegiados para evitar ser operados por atacantes y así manipular el tipo de cambio.
Cuando hay variables clave en el contrato que dependen del valor de "this.balance" o "token.balanceOf()", debe considerar cuidadosamente las condiciones para el cambio de la variable clave, como si está permitido transfiera directamente moneda nativa o tokens al contrato. Cambie el valor de la variable, o el valor de la variable solo se puede cambiar llamando a una función específica.
Este artículo fue coescrito por Cara del equipo ZAN (cuenta X @Cara6289) y XiG (cuenta X @SHXiGi).