Problema de sincronización: cómo el protocolo Verus perdió $7.5M por las diferencias entre blockchains

Problema de sincronización: cómo el protocolo Verus perdió $7.5M por las diferencias entre blockchains

El ataque no requirió comprometer claves ni hackear validadores: el atacante aprovechó la forma en que dos blockchains diferentes interpretaban las confirmaciones de notarización. Explicamos por qué las firmas legítimas de los notarios se convirtieron en parte de uno de los ataques más inusuales a los puentes cross-chain.

3 ago 2026

A registros de notarización completamente legítimos se añadieron registros maliciosos duplicados con una raíz de estado (state root) sustituida. Estos registros fueron firmados por los notarios de Verus y luego transmitidos a Ethereum, donde reemplazaron la state root de confianza real. Al obtener el control de este valor, el atacante pudo enviar a través del puente una prueba de importación falsa que permitió retirar muchos más fondos de los que realmente se enviaron, a pesar de que la exportación original fue de tan solo 0.01 VRSC.

Qué es una notarización

Dicha confirmación contiene:

  • el identificador de la blockchain o de la moneda;
  • la altura de la notarización;
  • una o más raíces de prueba (proofRoots), que incluyen:
  • el identificador de la red;
  • la altura del bloque;
  • la raíz de estado (state/proof root);
  • el hash del bloque;
  • la potencia de cálculo acumulada;
  • información sobre la moneda y el estado del conversor;
  • una referencia a la notarización anterior;
  • el hash de la notarización cross-chain anterior;
  • información sobre el nodo y el iniciador.

Las raíces de prueba se forman a partir de los datos públicos de las blockchains de Verus y Ethereum. Cualquier usuario puede crear y transmitir un candidato a notarización, pero la red solo lo aceptará si se cumplen los requisitos de consenso y se utiliza el UTXO correcto de la cadena de notarizaciones anterior.

Las firmas de los notarios (CNotarySignature) forman parte de la estructura CNotaryEvidence y se publican de forma abierta. Gracias a ello, el atacante pudo obtener estas firmas y reutilizarlas.

Cronología del ataque (UTC)

Los atacantes se prepararon minuciosamente para el hackeo y actuaron durante dos días.

Cómo se desarrolló el ataque: cuatro etapas

Todo el algoritmo del hackeo del protocolo puede dividirse en cuatro etapas clave.

1. Sustitución de la notarización en la red Verus

La primera transacción utilizó la salida confirmada anterior de la cadena de notarizaciones (4f4f…:1) y creó una nueva (0c247…:0). Aunque en la interfaz del explorador de bloques solo se mostraban dos registros legítimos, dentro de los datos serializados se incrustaron de forma encubierta registros adicionales con state roots falsas.

La causa residía en las particularidades del procesamiento de datos. Verus primero leía la lista de raíces como un array y luego la trasladaba a una estructura Map. Gracias a ello, el atacante pudo crear dos transacciones consecutivas, cada una de las cuales contenía además varios registros maliciosos ocultos con state roots sustituidas.

2. Sustitución de la raíz de estado en Ethereum

Después de esto, el atacante esperó a que el software de los notarios verificara los primeros registros correctos. Luego, 11 nodos notariales firmaron la notarización completa, incluidos los registros duplicados ocultos con datos maliciosos, que el sistema Verus en realidad ignoraba.

Las firmas obtenidas se incluyeron en la estructura CNotaryEvidence. A continuación, a través de la interfaz RPC de Verus, el atacante obtuvo estas firmas y luego construyó una llamada a la función setLatestData() en Ethereum.

Del lado de Ethereum, el atacante actuó únicamente como retransmisor: copió los datos en bytes de la notarización junto con las firmas legítimas de los notarios y los transmitió al contrato inteligente.

Durante la ejecución de la función deserializeNotarization(), el contrato de Ethereum procesaba el array proofRoots de forma secuencial. Con ello, cada registro con el identificador del sistema Verus sobrescribía el valor de stateRoot:

  • el primer registro - la state root real;
  • el segundo - datos de Ethereum;
  • el tercero - una state root maliciosa;
  • el cuarto - de nuevo maliciosa;
  • el quinto - también maliciosa.

Como resultado, el último registro reemplazó por completo la state root de confianza real. Fue precisamente esta state root falsa la que se utilizó posteriormente para verificar la prueba de transferencia fraudulenta a través del puente.

3. Preparación de la exportación a través de Verus

Luego, el atacante creó una solicitud de transferencia cross-chain completamente ordinaria. En la transacción 5b5043febfd7f7c089e976d11d0f87a904881266bb96dd118b3d69b0e02aab52, una nueva dirección inició una exportación de tan solo 0.01 VRSC, pagando una comisión de alrededor de 12 unidades a través de Bridge.vETH.

Después de esto, la solicitud fue procesada por el conversor, y LuckPool formó una exportación por lotes en una transacción independiente. Fue precisamente esta solicitud completamente legítima la que más tarde se convirtió en la base para construir la prueba falsa.

En particular, se utilizaron los parámetros:

  • hashtransfers: 440787f9114dbb41b7d3d6f6c48980d51221f62ef0a33613d1d305b98ae85053
  • sourceheightstart: 4162638
  • sourceheightend: 4162847

4. Importación falsa y retiro de fondos a través de Ethereum

En la etapa final, el atacante llamó a la función submitImports(). En la estructura CCE, de 14 campos, solo se modificaron algunos parámetros clave. El campo hashtransfers fue completamente falsificado de modo que coincidiera con las transacciones de retiro de fondos.

Además:

  • el valor numInputs se cambió a 8;
  • firstInput - a 0;
  • los campos totalAmounts, totalFees y totalBurned estaban completamente ausentes.

Parte de la prueba permaneció original. En particular, se utilizaron valores reales:

  • el identificador de la transacción (TxID);
  • el primer nodo del árbol de pruebas (First node);
  • los parámetros generales del formato de las pruebas, las versiones y los identificadores de los sistemas.

Todos los demás elementos se generaron artificialmente. Gracias a que la state root maliciosa ya había sido registrada por Ethereum como de confianza, la prueba resultante superó la verificación con éxito, a pesar de la ausencia del volumen de fondos correspondiente en la transferencia original.

En qué consistía la vulnerabilidad: Verus y Ethereum leían los datos de forma diferente

Verus percibía los registros serializados como una estructura en la que los elementos duplicados se ignoraban en la práctica tras convertir el array en un Map.

Ethereum, por el contrario, procesaba todos los registros de forma secuencial, por lo que cada registro siguiente podía sobrescribir el valor de la state root.

Como resultado, los notarios de Verus firmaron datos que consideraban completamente correctos, pero Ethereum interpretó esos mismos bytes de otra manera y, al final, almacenó como state root de confianza un valor totalmente controlado por el atacante.

Una vez que Ethereum reconoció esta state root falsa como fiable, cualquier prueba de importación construida a partir de ella era considerada legítima por el sistema.

Un factor adicional fue un error lógico en el contrato del puente de Ethereum. El contrato no verificaba si el importe indicado en la solicitud de importación correspondía al volumen de activos que realmente se había exportado desde la red Verus.

Bastaba con construir un parámetro hashtransfers falso que coincidiera con las transacciones de retiro de fondos para superar con éxito la verificación de la estructura CCE.

Movimiento de los fondos robados: 2,778 ETH a través de Tornado Cash

Esquema del movimiento de los fondos robados al protocolo Verus. Visualización: Certik
Esquema del movimiento de los fondos robados al protocolo Verus. Visualización: Certik

Tras explotar con éxito la vulnerabilidad, el atacante cambió los activos robados por 2,778.8662 ETH a través de Relay, y luego transfirió los fondos obtenidos al servicio de anonimización Tornado Cash.

#Hackeo
Un error de $7.5M: lo que los desarrolladores del protocolo Verus pasaron por alto