Operaciones entre cadenas, DeFi y contratos inteligentes · Lección 5 de 6
Análisis de exploits y hackeos
11 min de lectura
Cuando se hackea un protocolo o un exchange, los analistas reciben las mismas preguntas en cuestión de horas: qué ocurrió, cuánto se sustrajo, dónde está ahora y quién lo hizo. Las respuestas surgen de un pequeño número de transacciones examinadas con gran detalle, seguidas de una larga labor de rastreo. Esta lección reúne las habilidades de decodificación de este módulo y de los anteriores (tokens, proxies, swaps, préstamos flash y puentes) y las aplica a casos públicos.
El ciclo de vida de un exploit en los datos
La mayoría de los incidentes, sea cual sea su causa raíz, pasan por las mismas fases, y cada una deja evidencias diferentes:
| Fase | Qué hace el atacante | Evidencias que recopilar |
|---|---|---|
| Financiación | Obtiene fondos para pagar el gas de direcciones nuevas | Primera transferencia entrante a cada dirección del atacante y su origen |
| Preparación | Despliega contratos de ataque, realiza pruebas, a veces primero en otras cadenas | Creaciones de contratos, intentos fallidos y sus motivos de reversión, bytecode |
| Ejecución | Ejecuta una o más transacciones de ataque | Trazas, registros de eventos, cambios de saldo por dirección y token |
| Consolidación | Intercambia tokens congelables o ilíquidos por ETH u otros activos neutrales, reúne los fondos | Swaps en DEX con un gran impacto en el precio, transferencias entre direcciones del atacante |
| Dispersión | Divide los fondos, los transfiere mediante puentes, utiliza mezcladores, los intercambia por Bitcoin, los convierte en dinero fiduciario | Patrones de distribución a múltiples direcciones, depósitos en puentes, depósitos en mezcladores, direcciones de depósito de exchanges |
Las fases se superponen y, cuando se comprometen claves, la preparación ocurre fuera de la cadena. Aun así, organizar las evidencias de esta manera evita que una investigación salte directamente a la transacción más visible y pase por alto la financiación que podría identificar al atacante.
Lectura de la transacción de ataque
Comience por la traza, no por los registros de eventos. Los registros de eventos recogen lo que los contratos decidieron anunciar; la traza registra cada llamada, su valor y si tuvo éxito. Un orden de trabajo práctico:
- Enumere los actores: la cuenta de propiedad externa que envió la transacción, el contrato de ataque al que llamó, los contratos víctimas y cualquier dirección que termine obteniendo beneficios.
- Calcule los cambios de saldo por dirección y por token para toda la transacción (la consulta de cálculo de saldos netos de la lección Swaps en DEX, exchanges instantáneos y flujos de liquidez sirve aquí). La ganancia neta del atacante y la pérdida neta de la víctima enmarcan todo lo demás.
- Recorra el árbol de llamadas desde arriba e identifique los préstamos flash (préstamos sin garantía que deben devolverse, junto con una comisión, antes de que termine la transacción; de lo contrario, se revierte toda la transacción) para no contabilizar el capital prestado como pérdida.
- Encuentre el paso en el que el estado del protocolo se volvió incoherente. Esa es la causa raíz y suele ser una sola llamada a una función.
Un resumen de cambios de saldo de una transacción de ataque ficticia muestra lo que produce el paso 2:
{
"tx_hash": "0x7c0d…e91a",
"block_number": 21000417,
"balance_changes": [
{"address": "0xa77a…c0de", "role": "contrato de ataque", "token": "DAI", "delta": "+2400000.00"},
{"address": "0x5af3…71b2", "role": "pool víctima", "token": "DAI", "delta": "-2401000.00"},
{"address": "0x87f1…4e2a", "role": "prestamista del préstamo flash", "token": "DAI", "delta": "+1000.00"},
{"address": "0x3e9d…02f7", "role": "EOA remitente", "token": "ETH", "delta": "-0.041"}
]
}
El préstamo flash de 2.000.000 DAI del prestamista no aparece en absoluto, porque salió y regresó en la misma transacción; solo queda su comisión de 1.000 DAI (0,05%). La víctima perdió 2.401.000 DAI, el contrato de ataque se quedó con 2.400.000 y el remitente pagó 0,041 ETH en gas.
El exploit de Euler Finance del 13 de marzo de 2023 ilustra el método. Los análisis publicados por investigadores de seguridad sobre una de las transacciones de ataque lo reducen a estos pasos:
Contrato de ataque, una de varias transacciones de ataque (pool de DAI)
1. Préstamo flash de 30.000.000 DAI de Aave
2. Depositar 20.000.000 DAI en Euler -> tokens de garantía (eDAI)
3. mint(): autoapalancamiento -> deuda de 200.000.000 dDAI, 195.600.000 eDAI
4. Devolver 10.000.000 DAI -> 10.000.000 dDAI quemados
5. mint() de nuevo -> otros 200.000.000 dDAI y 195.600.000 eDAI
6. donateToReserves(100,000,000 eDAI) -> sin comprobación de solvencia: la cuenta ahora es insolvente
7. Un segundo contrato de ataque liquida el primero con un descuento del 20%
8. Retirar 38.900.000 DAI, devolver el préstamo flash más la comisión y conservar el resto
El paso 6 es la causa raíz: una función que reducía la garantía sin comprobar la solvencia de la cuenta. Los pasos 1 y 8 compensan el capital prestado. Repetido en varios pools, el ataque sustrajo unos 197 millones de dólares en DAI, WETH, WBTC, stETH y USDC. El atacante intercambió la mayor parte por ETH y DAI, envió 100 ETH a un mezclador y luego negoció con el protocolo mediante mensajes en la cadena; para el 3 de abril de 2023 había devuelto todos los fondos recuperables. Conviene decodificar los mensajes en la cadena: son texto en los datos de entrada de transferencias simples y forman parte del registro.
Financiación, preparación e imitadores
La financiación de una dirección del atacante suele ser la mejor pista para la atribución. Las fuentes habituales son las retiradas de mezcladores (los pools de Tornado Cash utilizaban denominaciones fijas como 0,1, 1, 10 y 100 ETH), los puentes desde otra cadena, los servicios de exchange instantáneo y, ocasionalmente, una retirada de un exchange, cuyo seguimiento puede realizarse mediante procedimientos legales (véase la lección Rastreo a través de exchanges y servicios de custodia). Compruebe también:
- El desplegador de cada contrato de ataque y otros contratos que haya desplegado, incluidas las versiones de prueba en otras cadenas.
- La similitud del bytecode con contratos de ataque anteriores, que puede vincular incidentes.
- Los intentos fallidos anteriores al exitoso: sus motivos de reversión muestran qué estaba probando el atacante y cuándo comenzó.
No todas las direcciones que obtienen beneficios pertenecen al atacante original. Los bots de MEV copian transacciones pendientes rentables, y algunos grupos de hackers éticos se adelantan a los ataques para rescatar fondos. En el caso de Euler, una dirección que afirmó que su bot había copiado accidentalmente el primer ataque terminó enviando los DAI al atacante de todos modos, porque el contrato copiado tenía la dirección del atacante codificada de forma fija. En el incidente del puente Nomad de agosto de 2022, cientos de direcciones simplemente reprodujeron la transacción del primer atacante sustituyendo su dirección por la propia. Etiquete a estos actores por separado, con un nivel de confianza explícito, y nunca publique la identidad de una persona particular basándose únicamente en esos vínculos (véase la lección De la dirección a la entidad y a la persona: atribución y etiquetado).
Cuando el fallo no está en el código
Algunos de los mayores robos no implicaron ningún fallo en los contratos inteligentes. En el robo del puente Ronin de marzo de 2022, los atacantes controlaban cinco de las nueve claves de validadores que requería el puente, suficientes para firmar retiradas de unos 173.600 ETH y 25,5 millones de USDC; el robo pasó inadvertido durante seis días. Las autoridades estadounidenses atribuyeron el robo a Lazarus Group, de Corea del Norte, en abril de 2022. En la cadena, las retiradas estaban firmadas válidamente; solo el contexto (tamaño, destinatario y momento inusuales) las delataba.
El robo de Bybit del 21 de febrero de 2025, de unos 1.500 millones de dólares, fue el mayor robo de criptomonedas registrado hasta ese momento y ofrece una lección sobre cómo interpretar lo que los firmantes aprobaron realmente. La billetera fría del exchange era un proxy multifirma de Safe. Los investigadores descubrieron que la interfaz de la billetera había sido comprometida a través del equipo de un desarrollador del proveedor de la billetera, por lo que los firmantes veían una transferencia rutinaria mientras sus billeteras de hardware firmaban otra cosa. Una vez decodificada, la transacción firmada tiene este aspecto:
SafeProxy.execTransaction(...) -- selector 0x6a761202, tres firmas válidas
to = contrato del atacante
data = transfer(...) -- nombre de función aparentemente inofensivo
operation = 1 -- DELEGATECALL, no CALL
DELEGATECALL contrato del atacante.transfer(...) -- se ejecuta con el almacenamiento del proxy
SSTORE slot 0 := implementación maliciosa -- puntero al singleton de Safe reemplazado
Después: se llama a sweepETH(...) y sweepERC20(...) en el proxy, sin necesidad de firmas
Como un proxy de Safe guarda su puntero de implementación en la ranura de almacenamiento 0 (véase la lección Decodificación de interacciones con contratos inteligentes), una delegatecall que escribe en la ranura 0 entrega el control de toda la billetera. Las transacciones de vaciado movieron después unos 401.346 ETH, 90.375 stETH, 15.000 cmETH y 8.000 mETH. El 26 de febrero de 2025, el FBI atribuyó el robo a actores norcoreanos a los que denomina TraderTraitor, publicó una lista de direcciones e informó de que los fondos se estaban convirtiendo en Bitcoin y distribuyendo entre miles de direcciones en múltiples cadenas. Las conclusiones para el analista: decodificar cada campo operation en las transacciones multifirma, generar alertas ante cualquier delegatecall a un contrato desconocido y supervisar las ranuras de implementación de los proxies de alto valor.
Rastreo posterior al incidente
Las primeras horas determinan cuánto se puede congelar o marcar. Una secuencia habitual:
- Construya el conjunto inicial: todas las direcciones controladas por el atacante identificadas a partir de las transacciones de ataque, la financiación y los vínculos con el desplegador.
- Vigile los activos congelables. Algunos emisores de stablecoins pueden congelar saldos, por lo que los atacantes los intercambian primero; comunique las direcciones rápidamente.
- Comparta las direcciones y los hashes de las transacciones con exchanges, puentes y otros servicios que puedan recibir los fondos, a través de sus canales de notificación establecidos.
- Rastree la consolidación y la dispersión hacia adelante, salto a salto, entre cadenas (véanse las lecciones Rastreo con rigor probatorio, Saltos entre cadenas y rastreo entre cadenas y Mezcladores con custodia).
-- Primeros dos saltos desde las direcciones del conjunto inicial de un incidente, con los mayores flujos primero
WITH seeds AS (
SELECT address FROM incident_addresses WHERE incident_id = 'INC-0142'
), hop1 AS (
SELECT t.to_address, SUM(t.amount_usd) AS usd, MIN(t.block_timestamp) AS first_seen
FROM value_transfers t JOIN seeds s ON t.from_address = s.address
WHERE t.to_address NOT IN (SELECT address FROM seeds)
GROUP BY t.to_address
)
SELECT h.to_address AS hop1, t.to_address AS hop2, SUM(t.amount_usd) AS usd
FROM hop1 h
JOIN value_transfers t
ON t.from_address = h.to_address AND t.block_timestamp >= h.first_seen
GROUP BY h.to_address, t.to_address
ORDER BY usd DESC;
La consulta presupone una tabla value_transfers que ya combina las transferencias nativas de las trazas con las transferencias de tokens, cada una valorada en el momento de la transferencia. La primera CTE encuentra las direcciones que recibieron fondos del conjunto inicial (excluyendo los movimientos entre direcciones de ese conjunto); el paso final sigue cada una de ellas un salto más, contabilizando solo las transferencias posteriores a la primera recepción. Los grandes flujos del segundo salto hacia servicios conocidos señalan dónde pueden existir registros fuera de la cadena.
Redacción del informe de un incidente
Clasifique la causa raíz, porque determina qué evidencias importan:
| Clase de causa raíz | Ejemplo público | Patrón típico en los datos |
|---|---|---|
| Fallo de lógica | Euler, 2023 | Préstamo flash más una secuencia de llamadas inusual que deja un estado imposible |
| Inicialización o control de acceso | Nomad, 2022 | Muchos invocadores tienen éxito con los mismos datos de llamada |
| Verificación de firmas | Wormhole, 2022 | Tokens acuñados sin un depósito correspondiente |
| Compromiso de claves | Ronin, 2022 | Retiradas firmadas válidamente, sin fallo en el código |
| Interfaz o cadena de suministro | Bybit, 2025 | Transacción firmada válidamente con una delegatecall inesperada |
| Gobernanza | Beanstalk, 2022 | Poder de voto prestado, propuesta ejecutada en la misma transacción |
Valore las pérdidas a los precios del bloque de cada transacción de ataque, enumere todas las transacciones de ataque con su altura de bloque y mantenga los importes recuperados separados de la pérdida. Las lecciones Redacción del informe forense: confianza y lenguaje y Ética, privacidad, protección de datos y seguridad del investigador explican cómo presentar y compartir estos hallazgos.
Enfoque del examen: las cinco fases de un exploit y las evidencias que deja cada una; lectura de la transacción de ataque a partir de la traza, cálculo de cambios de saldo y exclusión del capital de los préstamos flash al calcular los saldos netos; los pasos del ataque a Euler y su causa raíz (donateToReserves sin una comprobación de solvencia); las fuentes de financiación, los vínculos del desplegador y del bytecode, los intentos fallidos y los imitadores como pistas de atribución; los compromisos de claves e interfaces (Ronin, Bybit) y la delegatecall de Safe que reescribió la ranura 0; las prioridades de las primeras horas (conjunto inicial, activos congelables, notificación a los servicios); las consultas de saltos sobre transferencias nativas y de tokens combinadas; las clases de causa raíz y la valoración de las pérdidas a los precios del bloque.
Preguntas de práctica
Comprueba lo que has aprendido. Estas preguntas no cuentan para el examen.
Inicia sesión para guardar tu progreso y continuar donde lo dejaste. Es gratis. Iniciar sesión