Autor: CertiK

 

Anteriormente, el equipo de CertiK descubrió una serie de vulnerabilidades de denegación de servicio en la cadena de bloques Sui. Entre estas vulnerabilidades destaca una vulnerabilidad nueva y de alto impacto. Esta vulnerabilidad puede hacer que los nodos de la red Sui no puedan procesar nuevas transacciones, lo que tiene el efecto de cerrar completamente toda la red.

El lunes pasado, CertiK recibió una recompensa por errores SUI de 500.000 dólares por descubrir esta importante vulnerabilidad de seguridad. CoinDesk, el medio autorizado en la industria estadounidense, informó sobre el incidente, y luego los principales medios siguieron su informe y publicaron noticias relevantes.

Esta vulnerabilidad de seguridad se llama vívidamente "rueda de hámster": su método de ataque único es diferente de los ataques conocidos actualmente. El atacante solo necesita enviar una carga útil de aproximadamente 100 bytes para activar un bucle infinito en el nodo de verificación de Sui, lo que lo hace incapaz. para responder a nuevas transacciones.

Además, el daño causado por el ataque puede persistir después de que se reinicia la red y puede propagarse automáticamente en la red Sui, dejando a todos los nodos como un hámster corriendo sin parar sobre la rueda, incapaces de procesar nuevas transacciones. Es por eso que llamamos a este tipo de ataque único ataque de "rueda de hámster".

Después de descubrir la vulnerabilidad, CertiK se la informó a Sui a través del programa de recompensas por errores de Sui. Sui también respondió eficazmente lo antes posible, confirmó la gravedad de la vulnerabilidad y tomó activamente las medidas correspondientes para reparar el problema antes de que se lanzara la red principal. Además de solucionar esta vulnerabilidad específica, Sui ha implementado medidas preventivas de mitigación para reducir el daño potencial que esta vulnerabilidad podría causar.

Para agradecer al equipo de CertiK por la divulgación responsable, Sui otorgó al equipo de CertiK un bono de 500.000 dólares estadounidenses.

Se divulgarán los siguientes detalles técnicos de esta vulnerabilidad crítica para aclarar la causa raíz y el impacto potencial de la vulnerabilidad.

Explicación detallada de las vulnerabilidades.

El papel clave de los validadores en Sui

Para las cadenas de bloques basadas en el lenguaje Move, como Sui y Aptos, su mecanismo de protección contra ataques de carga maliciosa es principalmente tecnología de verificación estática. A través de la tecnología de verificación estática, Sui puede verificar la validez de la carga útil enviada por los usuarios antes de que se publique o actualice el contrato. El validador proporciona una serie de verificadores para garantizar la exactitud de la estructura y la semántica. Solo después de pasar las comprobaciones y verificaciones, el contrato ingresará a la máquina virtual Move para su ejecución.

Amenazas de carga útil maliciosas en la cadena Move

La cadena Sui proporciona un nuevo modelo de almacenamiento e interfaz además de la máquina virtual Move original, por lo que Sui tiene una versión personalizada de la máquina virtual Move. Para respaldar las nuevas primitivas de almacenamiento, Sui introduce además una serie de controles personalizados adicionales para la verificación de seguridad de cargas útiles que no son de confianza, como la seguridad de objetos y el acceso al almacenamiento global. Estos controles personalizados se ajustan a las características únicas de Sui, por lo que los llamamos validadores de Sui.

Orden de Sui de comprobar la carga.

Como se muestra en la figura anterior, la mayoría de las comprobaciones en el validador realizan una verificación de seguridad a nivel estructural contra CompiledModule (que representa la ejecución de la carga útil del contrato proporcionada por el usuario). Por ejemplo, use el "Verificador de duplicados" para asegurarse de que no haya entradas duplicadas en la carga útil del tiempo de ejecución; use el "Verificador de límites" para asegurarse de que la longitud de cada campo en la carga útil del tiempo de ejecución esté dentro del límite de entrada permitido.

Además de las comprobaciones a nivel estructural, la verificación estática del verificador aún requiere métodos de análisis más complejos para garantizar la solidez de la carga útil que no es de confianza a nivel semántico.

Obtenga más información sobre el intérprete abstracto de Move:

Análisis lineal e iterativo.

El intérprete abstracto proporcionado por Move es un marco diseñado específicamente para realizar análisis de seguridad complejos en código de bytes mediante interpretación abstracta. Este mecanismo hace que el proceso de verificación sea más refinado y preciso, y cada verificador puede definir su estado abstracto único para el análisis.

Al comienzo de una ejecución, el intérprete abstracto crea un gráfico de flujo de control (CFG) a partir de los módulos compilados. Cada bloque básico en estos CFG mantiene un conjunto de estados, a saber, "estado de pre-orden" y "estado de post-orden". El "estado de preorden" proporciona una instantánea del estado del programa antes de que se ejecute el bloque básico, mientras que el "estado de posorden" proporciona una descripción del estado del programa después de ejecutar el bloque básico.

Cuando el intérprete abstracto no encuentra saltos (o bucles) en el gráfico de flujo de control, sigue un principio de ejecución lineal simple: cada bloque básico se analiza por turno y la instrucción anterior se calcula en función de la semántica de cada instrucción del bloque. estado secuencial y estado post-secuencial. El resultado es una instantánea precisa de cada estado de nivel de bloque básico de un programa durante la ejecución, lo que ayuda a verificar las propiedades de seguridad del programa.

Mover el flujo de trabajo del intérprete abstracto

Sin embargo, este proceso se vuelve más complicado cuando existen bucles en el flujo de control. La aparición de un bucle significa que el gráfico de flujo de control contiene un borde de rebote. El origen del borde de rebote corresponde al estado posterior del bloque básico actual, y el bloque básico objetivo (cabeza del bucle) del borde de rebote es un estado previamente analizado. El estado de preorden del bloque básico, por lo que el intérprete abstracto debe fusionar cuidadosamente los estados de los dos bloques básicos relacionados con el salto.

Si se descubre que el estado fusionado es diferente del estado de pedido previo existente del bloque básico del cabezal del bucle, el intérprete abstracto actualiza el estado del bloque básico del cabezal del bucle y reinicia el análisis a partir de este bloque básico. Este proceso de análisis iterativo continúa hasta que el estado previo del bucle es estable. En otras palabras, este proceso se repite hasta que el estado de preorden del bloque básico al principio del ciclo ya no cambia entre iteraciones. Llegar a un punto fijo indica que el análisis del bucle está completo.

Validador Sui IDLeak:

Análisis personalizado de interpretación de resúmenes.

A diferencia del diseño Move original, la plataforma blockchain de Sui introduce un modelo de almacenamiento global único centrado en "objetivos". Una característica notable de este modelo es que cualquier estructura de datos con un atributo clave (almacenado como un índice en la cadena) debe tener el tipo de ID como primer campo de la estructura. El campo ID es inmutable y no se puede transferir a otros objetivos porque cada objeto debe tener un ID global único. Para garantizar estas propiedades, Sui creó un conjunto de lógica de análisis personalizada sobre el intérprete abstracto.

El verificador IDLeak, también conocido como id_leak_verifier, trabaja junto con el intérprete abstracto para realizar análisis. Tiene su propio AbstractDomain único, llamado AbstractState. Cada AbstractState consta de AbstractValue correspondiente a múltiples variables locales. Supervise el estado de cada variable local a través de AbstractValue para rastrear si una variable de ID es nueva.

Durante el proceso de empaquetado de la estructura, el validador IDLeak solo permite empaquetar una nueva ID en una estructura. A través del análisis de interpretación abstracta, el validador IDLeak puede rastrear exhaustivamente el estado del flujo de datos local para garantizar que no se transfieran ID existentes a otros objetos de la estructura.

Problema de inconsistencia en el mantenimiento del estado del validador Sui IDLeak

El validador IDLeak se integra con el intérprete abstracto Move implementando la función AbstractState::join. Esta función desempeña un papel integral en la gestión estatal, especialmente en la fusión y actualización de los valores estatales.

Examine estas funciones en detalle para comprender su funcionamiento:

En AbstractState::join, la función toma otro AbstractState como entrada e intenta fusionar su estado local con el estado local del objeto actual. Para cada variable local en el estado de entrada, compara el valor de la variable con su valor actual en el estado local (si no se encuentra, el valor predeterminado es AbstractValue::Other). Si los dos valores no son iguales, establecerá un indicador de "cambiado" como base para determinar si el resultado de la fusión del estado final ha cambiado y actualizará el valor de la variable local en el estado local llamando a AbstractValue::join.

En AbstractValue::join, la función compara su valor con otro AbstractValue. Si son iguales, devolverá el valor pasado. Si no es igual, se devuelve AbstractValue::Other.

Sin embargo, esta lógica de mantenimiento del estado contiene un problema de inconsistencia oculto. Aunque AbstractState::join devolverá un resultado que indica que el estado combinado ha cambiado (JoinResult::Changed) en función de la diferencia entre los valores antiguos y nuevos, es posible que el valor del estado actualizado combinado aún no haya cambiado.

Este problema de inconsistencia se debe al orden de las operaciones: la determinación del estado cambiado en AbstractState::join ocurre antes de la actualización del estado (AbstractValue::join), y esta determinación no refleja el resultado de la actualización del estado real.

Además, en AbstractValue::join, AbstractValue::Other juega un papel decisivo en el resultado de la fusión. Por ejemplo, si el valor anterior es AbstractValue::Other y el nuevo valor es AbstractValue::Fresh, el valor del estado actualizado sigue siendo AbstractValue::Other, incluso si los valores antiguos y nuevos son diferentes, el estado en sí no lo hace. cambiar después de la actualización.

Ejemplo: incoherencia en las conexiones estatales

Esto introduce una inconsistencia: el resultado de fusionar los estados del bloque básico se considera "cambiado", pero el valor del estado fusionado en sí no ha cambiado. En el proceso de interpretación y análisis abstractos, la aparición de tales inconsistencias puede tener graves consecuencias. Revisamos el comportamiento del intérprete abstracto cuando ocurren bucles en un gráfico de flujo de control (CFG):

Cuando se encuentra un bucle, el intérprete abstracto utiliza un método de análisis iterativo para fusionar el estado del bloque básico objetivo de salto con el bloque básico actual. Si el estado fusionado cambia, el intérprete abstracto volverá a analizar comenzando desde el objetivo de salto.

Sin embargo, si la operación de fusión del análisis de interpretación abstracta marca erróneamente el resultado de la fusión de estado como "cambiado" cuando en realidad el valor de la variable interna del estado no ha cambiado, conducirá a un reanálisis sin fin y creará un bucle infinito. .

explotando aún más la inconsistencia

Activar bucle infinito en el validador Sui IDLeak

Aprovechando esta inconsistencia, un atacante puede construir un gráfico de flujo de control malicioso para engañar al validador IDLeak en un bucle infinito. Este gráfico de flujo de control cuidadosamente construido consta de tres bloques básicos: BB1 y BB2, BB3. Vale la pena señalar que introdujimos intencionalmente un borde de salto de BB3 a BB2 para construir un bucle.

El estado CFG+ malicioso puede provocar un bucle infinito dentro del validador IDLeak.

El proceso comienza con BB2, donde el valor abstracto de una variable local específica se establece en ::Otro. Después de ejecutar BB2, el proceso se transfiere a BB3, donde la misma variable se establece en ::Fresh. Al final de BB3, hay un borde de salto que salta a BB2.

Las inconsistencias mencionadas anteriormente juegan un papel clave en la interpretación abstracta de este ejemplo. Cuando se procesa el borde de rebote, el intérprete abstracto intenta conectar el estado de pedido posterior de BB3 (la variable es "::Fresh") con el estado de pedido previo de BB2 (la variable es "::Otro"). La función AbstractState::join notó la diferencia entre los valores antiguos y nuevos y estableció el indicador "cambiar" para indicar que es necesario volver a analizar BB2.

Sin embargo, el comportamiento dominante de "::Otro" en AbstractValue::join significa que después de fusionar AbstractValue, el valor real de la variable de estado BB2 sigue siendo "::Otro" y el resultado de la fusión de estados no ha cambiado.

Entonces, una vez que comienza este proceso cíclico, es decir, mientras el validador continúa reanalizando BB2 y todos sus nodos de bloque básicos sucesores (BB3 en este caso), continúa indefinidamente. El bucle infinito consume todos los ciclos de CPU disponibles, lo que le impide procesar respuestas a nuevas transacciones, y esta situación persiste después de que se reinicia el validador.

Al explotar esta vulnerabilidad, los nodos validadores se ejecutan en un bucle infinito como un hámster corriendo sin cesar sobre una rueda, incapaz de procesar nuevas transacciones. Es por eso que llamamos a este tipo de ataque único ataque de "rueda de hámster".

Un ataque de "rueda de hámster" puede paralizar efectivamente el validador Sui, paralizando así toda la red Sui.

Después de comprender la causa y el proceso desencadenante de la vulnerabilidad, creamos un ejemplo específico utilizando la siguiente simulación de código de bytes Move y activamos con éxito la vulnerabilidad en la simulación en el entorno real:

Este ejemplo muestra cómo activar la vulnerabilidad en un entorno real mediante un código de bytes cuidadosamente construido. Específicamente, un atacante puede desencadenar un bucle infinito en el validador IDLeak, utilizando una carga útil de aproximadamente 100 bytes para consumir todos los ciclos de CPU de un nodo Sui, evitando efectivamente que se procesen nuevas transacciones y provocando una denegación de servicio en la red Sui. .

El daño persistente de los ataques de "rueda de hámster" en la red Sui

El programa de recompensas por errores de Sui tiene regulaciones estrictas sobre la evaluación de los niveles de vulnerabilidad, basadas principalmente en el grado de daño a toda la red. Una vulnerabilidad que cumpla con la calificación "crítica" debe cerrar toda la red e impedir efectivamente la confirmación de nuevas transacciones, y requiere una bifurcación dura para solucionar el problema, si la vulnerabilidad solo puede hacer que algunos nodos de la red rechacen el servicio, será así; calificado como “riesgo medio” como máximo (medio)” o vulnerabilidad “alta”.

La vulnerabilidad de la "rueda de hámster" descubierta por el equipo de CertiK Skyfall puede cerrar toda la red Sui y requiere el lanzamiento oficial de una nueva versión para actualizarla y solucionarla. Según la gravedad de la vulnerabilidad, Sui finalmente la calificó como "crítica". Para comprender mejor el grave impacto del ataque de la "rueda de hámster", debemos comprender la compleja arquitectura del sistema backend de Sui, especialmente todo el proceso de liberación o actualización de transacciones en cadena.

Descripción general de la interacción para enviar transacciones en Sui

Inicialmente, las transacciones de los usuarios se envían a través de RPC de front-end y se pasan al servicio de back-end después de una verificación básica. El servicio backend de Sui es responsable de validar aún más la carga útil de la transacción entrante. Después de verificar con éxito la firma del usuario, la transacción se convierte en un certificado de transacción (que contiene la información de la transacción y la firma de Sui).

Estos certificados de transacción son una parte fundamental del funcionamiento de la red Sui y pueden propagarse entre varios nodos de verificación de la red. Para las transacciones de creación/actualización de contratos, el nodo de verificación llamará al validador Sui para comprobar y verificar la validez de la estructura/semántica del contrato de estos certificados antes de que puedan colocarse en la cadena. Es durante esta fase crítica de verificación cuando se puede activar y explotar la vulnerabilidad del “bucle infinito”.

Cuando se activa la vulnerabilidad, provoca que el proceso de verificación se interrumpa indefinidamente, lo que obstaculiza efectivamente la capacidad del sistema para procesar nuevas transacciones y provoca un cierre completo de la red. Para empeorar las cosas, la situación persiste después de que se reinicia el nodo, lo que significa que las medidas de mitigación tradicionales están lejos de ser suficientes. Una vez que se activa esta vulnerabilidad, se producirán "daños continuos", lo que dejará un impacto duradero en toda la red Sui.

La solución de Sui.

Después de los comentarios de CertiK, Sui confirmó rápidamente la vulnerabilidad y lanzó una solución para abordar la falla crítica. La solución garantiza la coherencia entre los cambios de estado y las señales posteriores al cambio, eliminando el impacto crítico de los ataques de "rueda de hámster".

Para eliminar la inconsistencia anterior, la solución de Sui incluye un ajuste pequeño pero crítico a la función AbstractState::join. Este parche elimina la lógica de determinar el resultado de la fusión de estados antes de ejecutar AbstractValue::join. En su lugar, primero ejecuta la función AbstractValue::join para realizar la fusión de estados y establece si la fusión se produce comparando el resultado de la actualización final con el estado original. valor (valor_antiguo). Marca de cambio.

De esta manera, el resultado de la fusión de estados será consistente con el resultado de la actualización real y no se producirá ningún bucle infinito durante el proceso de análisis.

Además de solucionar esta vulnerabilidad específica, Sui ha implementado mitigaciones para reducir el impacto de futuras vulnerabilidades del validador. Según la respuesta de Sui en el informe de error, la mitigación implica una función llamada Denylist.

"Sin embargo, los validadores tienen un archivo de configuración de nodo que les permite rechazar temporalmente ciertas categorías de transacciones. Esta configuración se puede usar para deshabilitar temporalmente el procesamiento de lanzamientos y actualizaciones de paquetes. Debido a este error, es necesario ejecutar Sui antes de firmar un lanzamiento o paquete. actualice tx mientras que una lista de denegación detendrá la ejecución del validador y eliminará los tx maliciosos, denegar temporalmente la lista de estos tipos de tx es una mitigación 100% efectiva (aunque interrumpirá temporalmente el servicio para cualquiera que intente publicar o actualizar el código).

Por cierto, hemos tenido este archivo de configuración de lista de denegación de TX por un tiempo, pero también agregamos un mecanismo similar para los certificados como una mitigación de seguimiento para la vulnerabilidad del "bucle infinito del validador" que informó anteriormente. Con este mecanismo implementado, tendremos más flexibilidad con este ataque: usaremos la configuración de la lista de denegación de certificados para hacer que el validador se olvide de los certificados incorrectos (rompiendo el bucle infinito) y la configuración de la lista de denegación de TX para deshabilitar las versiones/actualizaciones. evitando así la creación de nuevas transacciones de ataques maliciosos. ¡Gracias por hacernos pensar en esto!

Un validador tiene un número limitado de "tics" (a diferencia del gas) para la verificación del código de bytes antes de firmar una transacción, si todo el código de bytes emitido en una transacción no se puede verificar en tantos ticks, el validador se negará a firmar la transacción, impidiendo que ejecutándose en la red. Anteriormente, la medición solo funcionaba para un conjunto selecto de pases de validación complejos. Para solucionar este problema, ampliamos la medición a cada validador para garantizar que exista una restricción en el trabajo realizado por el validador durante el proceso de verificación de cada tick. También solucionamos un posible error de bucle infinito en el validador de fugas de ID. "

--Instrucciones de los desarrolladores de Sui sobre corrección de errores

Con todo, Denylist permite a los validadores eludir temporalmente los exploits en los validadores y prevenir de manera efectiva daños potenciales causados ​​por algunas transacciones maliciosas al deshabilitar el proceso de lanzamiento o actualización. Cuando las medidas de mitigación de Denylist entran en vigor, los nodos garantizan que pueden continuar trabajando sacrificando sus propias funciones de contrato de publicación/actualización.

Resumir

En este artículo, compartimos los detalles técnicos del ataque de "rueda de hámster" descubierto por el equipo de CertiK Skyfall, explicando cómo este nuevo ataque explota vulnerabilidades clave para provocar el cierre completo de la red Sui. Además, también analizamos más de cerca la respuesta oportuna de Sui para solucionar este problema crítico y compartimos la solución de vulnerabilidad y los métodos de mitigación posteriores para vulnerabilidades similares.