Seis años de espera: cómo MakerDAO fue hackeado una vez más

Seis años de espera: cómo MakerDAO fue hackeado una vez más

El atacante solo necesitó 0.1 ETH, retirados de Tornado Cash, para lanzar el ataque, y tras el robo los 200 ETH comenzaron a regresar al mismo servicio.

9 oct 2026

Estos 200 ETH consistían en cuatro lotes de 50 ETH que el contrato había ganado en subastas de MakerDAO con pujas nulas durante las liquidaciones del «jueves negro» de marzo de 2020, pero que nunca había reclamado finalmente.

Una de las funciones desprotegidas del contrato antiguo no verificaba quién la invocaba. Esto permitió al atacante otorgar a un contrato bajo su control el control total sobre la cuenta de este contrato en el sistema de MakerDAO. En una sola transacción, el atacante liquidó las subastas antiguas y retiró la garantía que se mantenía allí.

Transacciones clave (horas en UTC)

HoraTXIDDescripción
2026-10-06 05:57:230xd4c0b18a058e7f0a12855f30174f4cb1e973c15c886063deab97e1a21f048ac6Retiro de 0.1 ETH desde Tornado Cash. Este fue el único financiamiento que recibió esta cuenta.
2026-10-06 06:12:110x4a587af4213cc345c4c109fbf5fec46f9643183f91a9edf60305380f31ad1167Despliegue del contrato de ataque utilizado para explotar la vulnerabilidad.
2026-10-06 06:13:110xbb6940f7c2a1e68cafbae7bb9b94d09af9af06ec3a114f6996f2cab993f3a88cLa transacción de ataque. El contrato de ataque obtuvo permisos delegados a través de la función del keeper 0x8804d1de, liquidó las subastas 1457-1460 y envió 200 ETH a la cuenta de propiedad externa (EOA) del atacante.
2026-10-06 06:19:350xb8ecff9c129d8d9331c85558eaeddff29a38c4c16b71a40986acbf8f6febefebEl primero de nueve depósitos de 10 ETH en el router de Tornado Cash.

Direcciones clave

DirecciónRol
0x01EB957E5C7DcDDD60F3C875956cCc6fb9BdA5FALa cuenta de propiedad externa (EOA) del atacante.
0xEc997d2aD033277913d6002277353368E8321dcFEl contrato de ataque.
0xf09a13072Ed939B79Bc25B66AA3a836ea6DCC170El módulo adaptador malicioso, que aún conserva permisos delegados sobre la cuenta de la víctima en Vat.
0x9c05a05893Ada984FC20D0DA0c046De5Cc0e8273El contrato vulnerable (keeper de subastas antiguo, AdminUpgradeabilityProxy).
0x68399ed8aa33C5b43F863EE6782de492006A5546La implementación del contrato vulnerable (código fuente no verificado).
0xaDC374E77b89Af0B8B39F7c47E8e0A37B6DaF073El propietario y operador del keeper en marzo de 2020.
0xd8a04F5412223F513DC55F839574430f5EC15531MakerDAO ETH-A Flipper, un mecanismo de subasta retirado de servicio para la venta de garantías.
0x35D1b3F3D7966A1DFe207aa4514C12a259A0492BMakerDAO Vat, el módulo contable principal.
0x2F0b23f53734252Bda2277357e97e1517d6B042AMakerDAO ETH-A GemJoin, el punto de salida del activo de garantía.
0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31bEl router de Tornado Cash, la dirección que recibió los fondos robados.
0x12D66f87A04A9E220743712cE6d9bB1B5616B8FcEl pool de 0.1 ETH de Tornado Cash, la fuente del financiamiento inicial del atacante.

Cómo se desarrolló el ataque

Despliegue del módulo

El exploit comenzó cuando el contrato de ataque creó un módulo adaptador en 0xf09a13072Ed939B79Bc25B66AA3a836ea6DCC170. Al crearse, el módulo recibió los siguientes parámetros: el Flipper, Vat, ETH-A GemJoin, el tipo de garantía (ilk), WETH, una dirección de pago y cuatro ID de subasta.

Entrega de permisos

El contrato de ataque llamó a la función del keeper 0x8804d1de y le pasó el adaptador recién creado en 0xf09. Luego, el keeper llamó a las funciones drip() y vat() del módulo, verificó mediante Vat.can() si ya se le habían otorgado permisos, y llamó a Vat.hope(). Esto le dio al módulo permisos ilimitados para administrar la cuenta del keeper en el sistema Vat.

El callback

Luego, el keeper llamó a la función join() del contrato de ataque. Esto cedió el control al código escrito por el atacante en un momento en que los nuevos permisos ya estaban vigentes.

Liquidación de las subastas

Dentro del callback, el módulo llamó a la función deal(id) del Flipper ETH-A descontinuado para las subastas 1457, 1458, 1459 y 1460. En marzo de 2020, el keeper originalmente había ganado cada uno de los cuatro lotes de 50 ETH con una oferta de cero, pero nunca había liquidado los acuerdos. Una vez liquidadas las subastas, se acreditaron 200 ETH como colateral ETH-A en la cuenta del keeper en Vat.

Retiro de los fondos

El módulo leyó el saldo de colateral del keeper y usó los permisos que había obtenido para mover todos los 200 ETH de la cuenta del keeper en Vat a su propia dirección con la función flux(). Luego retiró el colateral a través de ETH-A GemJoin como 200 WETH y envió el WETH al contrato de ataque.

¿Qué hay en el núcleo de la vulnerabilidad?

La causa raíz del ataque fue la falta de control de acceso en la función 0x8804d1de en la implementación del keeper en 0x68399ed8aa33C5b43F863EE6782de492006A5546.

Todas las demás funciones privilegiadas del contrato, incluidos los wrappers del keeper para las operaciones hope, flux y move, primero ejecutan una verificación ds-auth y rechazan las llamadas no autorizadas con el error ds-auth-unauthorized.

La función 0x8804d1de, en cambio, acepta cualquier dirección como adaptador, llama a Vat.hope() para esa dirección si el keeper aún no le ha otorgado permisos, y luego llama a join() en la misma dirección.

Debido a que el keeper luego llamó a join(), el módulo del atacante pudo ejecutar su propio código en un momento en que estos permisos ya estaban vigentes.

Los cuatro lotes sin usar de 2020 hicieron que esta vulnerabilidad fuera rentable para el atacante. Cualquiera puede llamar a la función deal para una subasta.

DeFiTuna aprendió a redondear: un error lógico costó $570 mil en USDC20 jul 2026Leer más

Movimiento de los fondos

El atacante recibió todos los 200 ETH directamente dentro de la transacción utilizada para explotar la vulnerabilidad. A las 06:19:35 UTC, apenas seis minutos después, el atacante comenzó a mover los fondos hacia Tornado Cash, enviándolos como 20 depósitos de 10 ETH.

#Hackeo#Ethereum#Mixers#DeFi
200 ETH esperaron seis años: la historia del ataque a un contrato antiguo de MakerDAO