Back to Blog

Enfoque Sistemático para Mantener la Compatibilidad y Seguridad de EVM

Code Auditing
March 27, 2023
8 min read

Las cadenas de bloques compatibles con EVM (Máquina Virtual de Ethereum) están diseñadas para ser compatibles con la funcionalidad de contratos inteligentes de la cadena de bloques Ethereum, su lenguaje de programación (Solidity) y el ecosistema de herramientas. Durante este proceso, la implementación de una máquina virtual compatible con EVM es uno de los pasos clave. Sin embargo, durante nuestra investigación, descubrimos que mantener la compatibilidad con EVM en diferentes implementaciones no es sencillo.

Para resolver el problema, BlockSec desarrolló un sistema interno que puede localizar sistemáticamente los errores y vulnerabilidades de seguridad dentro de la implementación de EVM. Este sistema resultó ser efectivo. Reportó cuatro errores en Aurora Engine y se localizaron cuatro errores en Moonbeam. Todos ellos fueron reportados y corregidos. Cabe destacar que esta metodología de prueba también se utilizó para localizar dos vulnerabilidades críticas (CVE-2021–46102, CVE-2022–23066) en la implementación de Solana rbpf el año pasado.

1. Antecedentes

Hoy en día, se proponen muchas cadenas de bloques diferentes con optimizaciones en tarifas de gas bajas, alto rendimiento y gran desempeño. En este contexto, se proponen nuevas máquinas virtuales o lenguajes de desarrollo, lo que aumenta la barrera de transformación para los desarrolladores originales de Solidity. En este caso, se proponen muchas soluciones compatibles con EVM, que permiten a los usuarios desplegar sus DApps desarrolladas en Solidity en estas nuevas cadenas. Aurora y Moonbeam son los representantes de estas soluciones compatibles con EVM. Sin embargo, la robustez, fiabilidad y precisión de estas implementaciones de EVM son desconocidas y merecen nuestra atención. Con este fin, utilizamos la técnica de fuzzing diferencial y verificamos si existen fallas en las implementaciones.

2. Fuzzing Diferencial

La idea fundamental es proporcionar entradas idénticas a estas implementaciones de EVM (p. ej., Aurora, Moonbeam) y al cliente Ethereum más avanzado (es decir, geth) para verificar si producen la misma salida. Específicamente, recopilamos las transacciones históricas en Ethereum y mutamos los códigos de contrato y los estados de transacción con diferentes estrategias para generar casos de prueba. Nuestros hallazgos muestran que Aurora Engine y Moonbeam no cumplen con la especificación en algunos casos. Afortunadamente, todos los problemas reportados han sido resueltos y ahora compartiremos los detalles.

3. Errores Encontrados

La mayoría de estos errores se encuentran en los contratos precompilados y las causas raíz e impactos son variados. Por ejemplo, algunos de los errores pueden influir en el cálculo del valor del nonce, mientras que otros pueden influir en el cálculo del gas y pueden resultar en un ataque de DoS. Todos los errores encontrados van en contra de la lógica de ejecución designada de la especificación EVM y pueden resultar en un comportamiento inesperado en casos específicos. A continuación se encuentra la descripción detallada de los errores encontrados.

3.1 Validación incorrecta

La lógica criptográfica es compleja. En este caso, implementar la lógica correspondiente en bytecode de EVM puede resultar en un uso de gas bastante elevado. En cambio, los contratos precompilados, desarrollados en código nativo, pueden aumentar el rendimiento. Sin embargo, encontramos varios errores en los contratos precompilados debido a una validación incorrecta.

Aurora Engine: ecPairing

Este error se encuentra en el contrato precompilado ecPairing.

La entrada de ecPairing consiste en múltiples puntos en dos curvas elípticas. Según la especificación, el punto (0, 0) se encuentra en ambas curvas y debería ser una entrada válida:

Sin embargo, Aurora Engine (versión 2.7.0) revertirá si el punto (0,0) está incluido en la entrada.

El PR relacionado está aquí.

Moonbeam: ecMul

Este error se encuentra en el contrato precompilado ecMul. A diferencia de Aurora Engine, Moonbeam revierte la transacción cuando la entrada es válida. Según la especificación, el contrato precompilado ecMul debería rellenar la entrada con ceros cuando la longitud de la entrada es menor que 64. Sin embargo, Moonbeam revertirá en lugar de realizar la operación de relleno.

También encontramos que los contratos precompilados ecAdd y modexp tienen el mismo problema.

Moonbeam: ecRecover

Este error se encuentra en el contrato precompilado ecRecover, que se utiliza para recuperar la dirección de Ethereum.

Según la especificación, la entrada[32..63] v representa un identificador U256, y se espera que sea 27 o 28; de lo contrario, ecRecover no debería devolver nada (pero la transacción completa no debería revertirse).

Sin embargo, Moonbeam comete dos errores aquí:

  • Solo verifica la entrada[63] en lugar de convertir la entrada[32..63] a un tipo U256 y luego verificar el valor.
  • La entrada se considera válida cuando el identificador es 0 o 1 (solo debería ser 27 o 28).

Moonbeam: ecPairing

Este error se encuentra en el contrato precompilado ecPairing. Moonbeam no revierte la transacción cuando la entrada es inválida. Según la especificación, la entrada del contrato precompilado ecPairing debe ser un múltiplo de 192. De lo contrario, la transacción debería revertirse.

Sin embargo, Moonbeam no revierte la transacción cuando los requisitos mencionados anteriormente no se cumplen.

3.2 Cálculo de gas incorrecto

Cada contrato precompilado tiene un algoritmo para determinar el uso de gas. El cálculo incorrecto del gas puede resultar en un ataque de DoS.

Sin embargo, hemos encontrado dos errores tanto en Aurora Engine como en Moonbeam donde el cálculo del gas es incorrecto.

Aurora Engine: modexp

El error se encuentra en el contrato precompilado modexp. El algoritmo para calcular el uso de gas está definido por EIP-2565. El uso de gas está relacionado con el número de iteraciones.

El algoritmo para calcular el número de iteraciones es el siguiente.

def calculate_iteration_count(exponent_length, exponent):
   iteration_count = 0
   if exponent_length <= 32 and exponent == 0: iteration_count = 0
   elif exponent_length <= 32: iteration_count = exponent.bit_length() - 1
   elif exponent_length > 32: iteration_count = (8 * (exponent_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1)
   return max(iteration_count, 1)

Según el algoritmo anterior, el conteo de iteraciones es al menos uno. Sin embargo, Aurora Engine devuelve iteration_count directamente en lugar de max(iteration_count, 1). En este caso, el valor devuelto (es decir, iteration_count) puede ser 0, lo que significa que Aurora cobrará una tarifa de gas considerablemente menor a la esperada en casos específicos.

El enlace al problema relacionado está aquí.

Moonbeam: modexp

El error también se encuentra en la función calculate_iteration_count del contrato precompilado modexp. Pero se encuentra en Moonbeam.

Cuando exponent_length es mayor que 32, el iteration_count se calcula con el siguiente algoritmo.

(8 * (exponent_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1)

Nótese que usa exponent & (2**256 - 1), que toma los 32 bytes más bajos de exponent, y la implementación de Moonbeam sigue este algoritmo.

Sin embargo, según la especificación, la fórmula de cálculo de gas debería usar los 32 bytes más altos de exponent:

3.3 Error de incremento de nonce

El nonce de una cuenta de propiedad externa (EOA) indica el número de transacciones exitosas firmadas por esta dirección. Sin embargo, notamos que el nonce puede incrementarse enviando transacciones inválidas en Aurora Engine.

Según EIP-1559, antes de ejecutar una transacción, la EVM debe asegurarse de que el firmante tenga saldo suficiente para cubrir el token nativo transferido (p. ej., ETH) y el gas requerido. De lo contrario, la transacción debe descartarse y el nonce del firmante no debe incrementarse.

Aunque Aurora Engine descarta la transacción en esta situación, aún incrementa el nonce del firmante.

El PR relacionado está aquí.

3.4 Implementación incorrecta de opcode

Este error se refiere a la implementación de un opcode específico (es decir, PUSH). Cuando los bytes que siguen al opcode PUSH están incompletos, deben estar alineados a la derecha. Por ejemplo, el bytecode 0x64ffff puede decodificarse como:

PUSH5 0xffff

Como el operando debe estar alineado a la derecha, el valor 0xffff000000 debería colocarse en la pila. Sin embargo, las implementaciones de EVM tanto en Aurora Engine como en Moonbeam colocan 0xffff en su lugar, lo cual es incorrecto.

El PR relacionado está aquí.

4. Nuestro Servicio

En BlockSec, entendemos la importancia de mantener la compatibilidad con EVM y la seguridad en diferentes implementaciones de cadenas de bloques. Por eso hemos desarrollado un enfoque sistemático para la detección de errores que puede localizar vulnerabilidades en implementaciones de EVM con facilidad.

Nuestro sistema interno ha demostrado ser altamente efectivo para localizar errores y vulnerabilidades de seguridad en implementaciones de EVM. Ha reportado y corregido exitosamente cuatro errores en Aurora Engine y cuatro errores en Moonbeam. Además, nuestra metodología de prueba se utilizó para localizar dos vulnerabilidades críticas (CVE-2021–46102, CVE-2022–23066) en la implementación de Solana rbpf el año pasado, destacando la efectividad de nuestro enfoque.

Al implementar nuestro enfoque sistemático de detección de errores, nuestros clientes pueden tener la confianza de que sus implementaciones de EVM son seguras y confiables. Estamos comprometidos a proporcionar soluciones de primera categoría para la compatibilidad y seguridad de EVM, ayudando a nuestros clientes a generar confianza con sus usuarios y partes interesadas.

Acerca de BlockSec

El equipo de BlockSec se enfoca en la seguridad del ecosistema blockchain y colabora con los principales proyectos DeFi para asegurar sus productos. El equipo fue fundado por investigadores de seguridad de primer nivel y expertos experimentados tanto del mundo académico como de la industria. Han publicado múltiples artículos de seguridad blockchain en conferencias de prestigio, reportado varios ataques de día cero en aplicaciones DeFi y publicado informes de análisis detallados de incidentes de seguridad de alto impacto.

Sitio Web Oficial | Twitter | Medium

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit