Back to Blog

El Análisis Adicional del Ataque a la Red Poly

Code Auditing
August 12, 2021
7 min read

El ataque consta de dos pasos principales. El primer paso es cambiar el keeper y el segundo paso es retirar los tokens (ejecutando la función unlock). El segundo paso ha sido completamente analizado. Para el primer paso, Kevin ha señalado que la colisión de hash es un truco inteligente utilizado por el hacker para invocar la función putCurEpochConPubKeyBytes. Sin embargo, por qué el atacante puede tener una transacción válida para realizar esta llamada en primer lugar sigue siendo desconocido.

En este blog, utilizamos la transacción maliciosa de Ontology (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c) para ilustrar todo el proceso.

En resumen, encontramos que:

  • El relayer de Ontology no cuenta con suficientes mecanismos de validación para la transacción proveniente de la cadena Ontology.
  • El atacante puede invocar directamente la función putCurEpochConPubKeyBytes en EthCrossChainData sin pasar por el relayer de Ethereum, siempre que exista un bloque válido en la cadena Poly.
  • La colisión de hash señalada por Kevin

Descargo de responsabilidad: Este blog contiene los resultados del análisis de nuestro equipo, que se basan en el código fuente disponible públicamente y en las transacciones on-chain. Sin información adicional de Poly Network, no podemos verificar nuestros resultados.

0x.1 Transacciones y Contratos

Flujo del Ataque

Transacción Ontology -> Relayer Ontology -> Cadena Poly -> Relayer Ethereum -> Ethereum

Ethereum

0x838bf9e95cb12dd76a54c9f9d2e3082eaf928270: EthCrossChainManager
0xcf2afe102057ba5c16f899271045a0a37fcb10f2: EthCrossChainData
0x250e76987d838a75310c34bf422ea9f1ac4cc906: LockProxy
 
Transacción: 0xb1f70464bd95b774c6ce60fc706eb5f9e35cb5f06e6cfe7c17dcda46ffd59581

Ontology

Transacción: 0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c

Poly

Transacción: 0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80

0x2. Flujo del Ataque

Tomemos como ejemplo el ataque ocurrido en Ethereum. Este es un ataque cross-chain que involucra tres cadenas (y sus correspondientes relayers), es decir, la Cadena Ontology, la Cadena Poly y Ethereum.

El flujo completo del ataque consta de tres pasos:

  1. el atacante primero inició una transacción maliciosa (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c) en la Cadena Ontology;
  2. el atacante luego modificó la clave pública del keeper almacenada en el contrato EthCrossChainData en Ethereum;
  3. el atacante finalmente elaboró una transacción maliciosa para obtener activos criptográficos.

0x2.1 El Primer Paso

El atacante primero inició una transacción cross-chain (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c) desde Ontology, que incluye un payload malicioso:

Puede notar que este payload contiene un nombre de función manipulado (comenzando con 6631, es decir, f1121318093 después de la conversión). Este nombre es definitivamente meticuloso, porque el atacante lo usaría para invocar la función putCurEpochConPubKeyBytes (ver el contrato EthCrossChainData en Ethereum) explotando la colisión de hash de las firmas de funciones. Aquí no ilustraremos los detalles de la colisión de hash, ya que ha sido ampliamente discutida.

Después de eso, esta transacción fue aceptada exitosamente por el Relayer de la Cadena Ontology. Tenga en cuenta que NO existe ninguna verificación estricta. Como resultado, se convirtió en una nueva transacción válida (0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80) en la Cadena Poly.

La nueva transacción fue percibida y RECHAZADA por el Relayer de Ethereum. Porque el Relayer de Ethereum verificó la dirección del contrato de destino (es decir, EthCrossChainData en este caso), sin embargo, solo se permitiría LockProxy.

De esta manera, el procesamiento fue terminado. Sin embargo, la transacción con el payload malicioso ha sido almacenada en la Cadena Poly, lo que puede ser explotado para lanzar el ataque.

0x2.2 El Segundo Paso

El atacante envió manualmente una transacción a Ethereum invocando la función verifyHeaderAndExecuteTx del contrato EthCrossChainManager. Los datos de la transacción maliciosa almacenados en la Cadena Poly fueron utilizados como entrada. Como una transacción válida de la Cadena Poly, fue capaz de eludir la verificación (incluyendo las firmas y la prueba merkle) en la función verifyHeaderAndExecuteTx. Después de eso, se invocó la función putCurEpochConPubKeyBytes del contrato EthCrossChainData para modificar los cuatro keepers originales por uno nuevo (es decir, 0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B) controlado por el atacante.

0x2.3 El Tercer Paso

Después de la modificación del keeper, el atacante pudo llamar directamente a la función verifyHeaderAndExecuteTx sin usar la Cadena Poly. Finalmente, se invocó la función unlock del contrato LockProxy para robar una enorme cantidad de activos digitales de Ethereum. El análisis detallado se puede encontrar en nuestro informe anterior.

0x3. Relayer

Tanto los relayers de Ontology como de Ethereum están implementados en Go. Sin embargo, carecen de suficiente validación, por lo que

  • El atacante puede construir una transacción maliciosa, que será empaquetada en la cadena Poly
  • El atacante puede invocar directamente las funciones en el contrato inteligente EthCrossChainData en Ethereum

0x3.1 El Relayer de Ontology Confía Ciegamente en las Transacciones Cross-chain de Ontology

El ont_relayer es responsable de escuchar las transacciones cross-chain de la cadena Ontology y enviarlas a la cadena Poly.

  • Side significa la cadena Ontology; Alliance significa la cadena Poly
  • CrossChainContractAddress es el contrato inteligente nativo (número 09) en la cadena Ontology

La figura anterior muestra que el relayer de Ontology inicia dos rutinas para escuchar las transacciones cross-chain desde y hacia la cadena Ontology, y la rutina para verificar el estado de la transacción cross-chain (línea 71).

En la figura anterior, el relayer de Ontology invoca la interfaz RPC expuesta por la cadena Ontology (línea 215 GetSmartContractEventByBlock) para obtener eventos en la cadena. Desde las líneas 228 y 232, podemos ver que esta rutina solo escucha el evento makeFromOntProof activado por CrossChainContractAddress.

En la figura anterior, al procesar la transacción cross-chain, hay cinco verificaciones. Las dos primeras verifican las solicitudes RPC (verificación 1 y 4) a la cadena Ontology y tres verificaciones para comprobar si los parámetros son nulos (verificación 2, 3 y 5). Sin embargo, no existe ninguna verificación de la semántica en la transacción cross-chain, es decir, si el contrato y el nombre del método son razonables. Finalmente, envía la transacción a la cadena Poly (línea 183)

El relayer de Ontology construye y envía la transacción a la cadena Poly usando la interfaz RPC (línea 164 - SendTransaction).

La función ProcessToAliianceCheckAndRetry solo verifica si la transacción ha fallado. En caso afirmativo, reenviará la transacción.

En resumen, ont-relayer escucha todos los eventos makeFromOntProof activados por CrossChainContractAddress desde la cadena Ontology. Luego la transacción será enviada a la cadena Poly. Tenga en cuenta que la transacción cross-chain de cualquier persona en la cadena Ontology activará el evento makeFromOntProof, lo que resulta en ser enviada a la cadena Poly.

0x3.2 Eludir el Relayer de Ethereum

El Relayer de Ethereum es responsable de escuchar las transacciones de la cadena Poly y luego enviar la transacción a Ethereum.

El Relayer de Ethereum inicia una Goroutine para monitorear la Cadena Poly;

Monitorea la transacción cross-chain cuyo destino es Ethereum (líneas 275 - 278). Luego verifica si el contrato de destino (ToContractAddress) es uno de los contratos configurados en config.TargetContracts. Si no es así, la transacción cross-chain no será enviada a la cadena de destino (Ethereum).

Sin embargo, el atacante puede interactuar directamente con la cadena de destino e invocar la función en EthCrossChainManager. En otras palabras, la verificación en el relayer de Ethereum puede ser eludida. Siempre que la transacción maliciosa haya sido empaquetada en la cadena Poly (lo cual se logró en el paso anterior a través del relayer de Ontology), el atacante puede interactuar directamente con EthCrossChainManager. Durante este proceso, la verificación de firmas (ECCUtils.verifySig) y la prueba merkle (ECCUtils.merkleProve) pueden pasar, ya que existe una transacción válida en la Cadena Poly.

Usando los dos métodos anteriores, el atacante puede invocar exitosamente ToContractAddress.method en Ethereum. Combinando con la colisión de hash, la función putCurEpochConPubKeyBytes es eventualmente invocada para cambiar el keeper.

Créditos

Yufeng Hu, Siwei Wu, Lei Wu, Yajin Zhou @ BlockSec

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