Envío de registros, alertas y datos de telemetría a través de un diodo de datos

Descubre cómo
Utilizamos inteligencia artificial para traducir el sitio web y, aunque nos esforzamos por garantizar la precisión, es posible que las traducciones no sean siempre 100 % exactas. Agradecemos tu comprensión.

Solución de la vulnerabilidad CVE-2024-0517 en Google Chrome

Con tecnología de MetaDefender Endpoint
Por OPSWAT
Comparte esta publicación
Foto de los participantes en el programa OPSWAT , Hoai Nam Do y Minh Quan Le
Participantes en el Programa OPSWAT

Acerca de CVE-2024-0517

CVE-2024-0517 es una vulnerabilidad de escritura fuera de límites en el motor JavaScript V8 de Google Chrome anterior a la versión 120.0.6099.224, que permite a atacantes remotos aprovechar una corrupción del montón mediante una página HTML manipulada. La vulnerabilidad fue comunicada por primera vez por Toan (Suto) Pham, de Qrious Secure. 

Captura de pantalla en la que se muestra una puntuación base de gravedad CVSS 3.x de 8,8 (Alta), junto con una descripción detallada de los vectores de vulnerabilidad proporcionada por el NVD
CVE-2024-0517 en la Base de Datos Nacional de Vulnerabilidades (NVD)

Esta vulnerabilidad se debe a una confusión de tipos, que se produce cuando una aplicación asigna o inicializa un recurso —como un puntero, un objeto o una variable— utilizando un tipo determinado, pero posteriormente accede a dicho recurso utilizando un tipo incompatible con el original (CWE-843). En este CVE, la confusión de tipos se desencadena durante un proceso de asignación de memoria denominado «asignación plegada», que utiliza Maglev —un compilador optimizador para el motor JavaScript V8— con el fin de optimizar la memoria. 

Al aprovechar la confusión de tipos y escribir códigos de shell arbitrarios mediante WebAssembly, un atacante puede ejecutar comandos en el equipo de la víctima. 

Fases de ataque

Los atacantes pueden alojar un sitio web que contenga una página HTML manipulada y engañar a los usuarios para que accedan a ella a través de correos electrónicos de phishing o redes sociales. Cuando los usuarios visitan el sitio utilizando una versión vulnerable de Google Chrome, el código malicioso incrustado ejecutará comandos arbitrarios. 

Diagrama que muestra un proceso de cuatro pasos para aprovechar una vulnerabilidad mediante un correo electrónico de phishing que contiene un archivo HTML malicioso, lo que permite la ejecución remota de código
Campaña ofensiva paso a paso 

Motor JavaScript V8 

El motor JavaScript V8 fue desarrollado en C++ por Google y se lanzó el 2 de septiembre de 2008. V8 compila y ejecuta código fuente JavaScript, gestiona la asignación de memoria para los objetos y se encarga de la recolección de basura de los objetos que ya no necesita. V8 es un componente fundamental de Google Chrome y puede integrarse en cualquier aplicación de C++, como Node.js, para ejecutar código JavaScript o WebAssembly.

Maglev y asignación plegada

Maglev, un compilador optimizador de V8, mejora la ejecución del código y la asignación de memoria. Maglev solo se ejecuta cuando el código se ejecuta con frecuencia y se marca como «activo», lo que indica la necesidad de una ejecución más rápida mediante la compilación, en lugar de una interpretación línea por línea, que resulta más lenta. 

Por lo general, las asignaciones se producen en regiones de memoria no contiguas, lo que da lugar a un uso disperso e ineficiente de la memoria. Para solucionar este problema, V8 emplea una técnica denominada «asignación agrupada», que asigna varias variables de forma continua y simultánea. Maglev también optimiza las asignaciones utilizando la asignación agrupada en su funcionamiento. 

Diagrama que muestra representaciones codificadas por colores de la distribución de carpetas, con y sin carpetas asignadas
Malev y la asignación de carpetas

Recolección de basura generacional 

Para liberar las regiones de memoria no utilizadas, V8 emplea una técnica de recolección de basura generacional (GC), que divide la memoria en dos espacios: la generación joven y la generación vieja. Además, hay dos recolectores de basura: el recolector de basura menor, que se encarga de liberar el espacio joven, y el recolector de basura mayor, que se ocupa de liberar el espacio viejo. La generación joven es el área de memoria donde se asignan inicialmente los objetos recién creados, y la generación vieja es una región de memoria donde se almacenan los objetos de larga duración. Los objetos que han sobrevivido a múltiples ciclos de GC menor en la generación joven acaban siendo promocionados a la generación vieja. 

Diagrama que muestra el proceso de asignación de objetos en las generaciones de memoria joven, intermedia y vieja durante la recolección de basura (GC)
Espacios de la memoria: la generación joven y la generación mayor

Análisis de vulnerabilidades

Resumen

La vulnerabilidad surge cuando se crea un objeto a partir de una clase que hereda de una clase base sin un constructor definido explícitamente (constructor predeterminado de la clase base) y, posteriormente, se crea otro objeto. Debido a la asignación agrupada, la asignación del primer objeto puede ir seguida de la asignación del segundo. Si entre estas dos asignaciones se produce un evento como la recolección de basura, puede surgir una vulnerabilidad por confusión de tipos.

Análisis de las causas fundamentales 

Los becarios OPSWAT llevaron a cabo un análisis detallado del flujo de trabajo de V8 durante el proceso de asignación y determinaron que, durante dicho proceso, se activan las siguientes funciones: 

Diagrama que ilustra el flujo de trabajo de V8 durante el proceso de asignación de objetos, desde la búsqueda del constructor hasta la extensión de la asignación en memoria
Flujo de trabajo de V8 durante el proceso de asignación 

En el marco de este proceso, se detectó un problema en la función `TryBuildFindNonDefaultConstructorOrConstruct`: la función `BuildAllocateFastObject` amplía `current_raw_allocation_` (un puntero a la región de memoria asignada para varias variables simultáneamente) para construir la instancia de la clase derivada, pero no la borra asignándole el valor `null`. 

Por lo tanto, el siguiente objeto creado siempre se asigna inmediatamente después de la memoria a la que apunta `current_raw_allocation_`, independientemente de los eventos que se produzcan antes de la segunda asignación. 

Diagrama que muestra la creación de un nuevo objeto en memoria, pasando de «asignación bruta actual» a «siguiente objeto»
«current_raw_allocation» y «Next object» en la región de memoria

Si se activa el recolector de basura (GC), la región de memoria contigua a la asignada a `current_raw_allocation_` puede asignarse a otros objetos. Esto puede dar lugar a una situación en la que, tras activarse el recolector de basura y crearse otro objeto, dos punteros hagan referencia a la misma región de memoria pero tengan tipos de datos diferentes, lo que da lugar a una vulnerabilidad por confusión de tipos.

Diagrama que muestra el proceso de una vulnerabilidad por confusión de tipos, en el que se ilustran el desencadenante de la recolección de basura y la asignación de objetos que dan lugar a posibles problemas
Vulnerabilidad por confusión de tipos 

Explotación

Para aprovechar esta vulnerabilidad, los becarios OPSWAT crearon instancias de WebAssembly que contenían código shell e intentaron provocar una confusión de tipos mediante el GC para controlar la memoria y ejecutar el código shell: 

Un diagrama de flujo paso a paso que muestra cómo provocar la ejecución remota de código mediante una confusión de tipos en el motor V8, desde el inicio de la confusión de tipos hasta la ejecución del código shell
Pasos para provocar la ejecución remota de código en el motor V8 

Confusión sobre el tipo de disparador

Durante la inicialización, primero definimos una matriz (_arrayObject) que contiene objetos vacíos. A continuación, creamos una instancia de la clase derivada y activamos el recolector de basura. Por último, definimos otra matriz con un número de punto flotante, denominada _arrayDouble. 

Un fragmento de código que muestra una función que activa la recolección de basura en JavaScript, creando un búfer de matriz

Estas construcciones deben repetirse para que el código se ejecute varias veces, lo que hace que V8 lo marque como «activo» y active el compilador Maglev. Para ello, invocamos el constructor de la clase hija dentro de un bucle de la siguiente manera: 

Un breve fragmento de código JavaScript que muestra un bucle que crea varias instancias de una clase derivada

Se producirá una confusión de tipos tras inicializar repetidamente estos objetos en un bucle.

Crear primitivas de lectura y escritura

Tras provocar con éxito la confusión de tipos, la ejecución del código shell requiere leer la memoria y sobrescribir su contenido en una dirección controlada. Para ello, hemos creado primitivas de lectura y escritura. Las primitivas de explotación aprovecharán los metadatos de los objetos para obtener regiones de memoria de lectura y escritura arbitrarias y utilizarlas para ejecutar código arbitrario. 

Una representación gráfica de las operaciones básicas de lectura y escritura, en la que se muestran las regiones de memoria y los valores que se sobrescriben
Primitiva de lectura y escritura 

Las primitivas de lectura y escritura de este paso nos permitirán controlar el puntero de la tabla de saltos de la instancia de WebAssembly en el siguiente paso. 

Crear instancias de WebAssembly

A continuación, creamos dos instancias de WebAssembly: una para almacenar el código shell y otra para ejecutarlo. Para evitar escribir directamente el código shell en la memoria de la instancia de WebAssembly mediante primitivas de lectura y escritura, definimos algunos valores constantes de punto flotante dentro de la instancia de WebAssembly. 

Un fragmento de código escrito en WebAssembly que ilustra las funciones de acceso a la memoria y almacenamiento

Controlar el puntero de la tabla de saltos de una instancia de WebAssembly

Mediante el uso de primitivas de lectura y escritura, ajustamos el puntero de la tabla de saltos de la segunda instancia de WebAssembly para omitir algunos bytes del código compilado de las constantes de la primera instancia de WebAssembly, de modo que las constantes de punto flotante se interpreten como el código shell que pretendemos:

Fragmento de código en ensamblador que muestra instrucciones para transferir datos a los registros

Ejecuta una instancia de WebAssembly para ejecutar el código shell 

Por último, tras provocar una confusión de tipos y utilizar primitivas de lectura/escritura para controlar los punteros de la tabla de saltos de las instancias de WebAssembly, invocamos la función exportada de la segunda instancia de WebAssembly, lo que provocó la ejecución del código shell de la primera instancia de WebAssembly. 

El código shell que estamos utilizando está diseñado para cerrar todos los procesos de un equipo Linux, tal y como lo hace el siguiente comando: 

Un sencillo fragmento de código de terminal con el comando «kill» para cerrar procesos

El código en ensamblador para ejecutar este comando, obtenido a partir de los números de coma flotante, será el siguiente: 

Un fragmento de código ensamblador para una llamada al sistema que finaliza un proceso mediante el comando «kill»

Simular la vulnerabilidad de seguridad 

Para simular este ataque en un escenario real, los becarios OPSWAT crearon una página HTML diseñada con fines maliciosos. 

Un fragmento de código WebAssembly diseñado para ejecutar código shell mediante el acceso a la memoria y la manipulación de datos

Se envía a la víctima un correo electrónico de phishing que contiene un enlace al dominio que aloja esta página HTML manipulada. 

Captura de pantalla en la que se muestra un correo electrónico de phishing junto a una herramienta de supervisión del sistema, lo que ilustra la ejecución del ataque

Si la víctima accede al enlace utilizando una versión vulnerable de Google Chrome, se ejecuta el código shell, lo que provoca la finalización de todos los procesos. Como consecuencia, el usuario queda desconectado, tal y como se muestra a continuación: 

Captura de pantalla de la pantalla de inicio de sesión de Kali Linux

Remediación

Se utilizó MetaDefender para mitigar de forma proactiva esta CVE aprovechando su función «Aplicaciones vulnerables». La solución identifica y muestra de forma eficaz todas las CVE asociadas a las aplicaciones de Google Chrome en el entorno de los terminales. Para neutralizar la amenaza, los usuarios pueden desinstalar Chrome de inmediato o aplicar el último parche de seguridad. Al implementar cualquiera de estas medidas, la CVE queda totalmente controlada, lo que reduce significativamente el riesgo de que se produzca un ciberataque con éxito en el terminal.

Endpoint de MetaDefender Endpoint que muestra las vulnerabilidades de Google Chrome, incluyendo detalles sobre los CVE

Endpoint de última generación 

Descubra por qué organizaciones, instituciones y entidades de todo el mundo confían en MetaDefender Endpoint proteger sus puntos finales críticos. Hable hoy mismo con un experto para obtener más información y compruébelo usted mismo con una demostración gratuita.  


¡Mantente al día con OPSWAT!

Regístrate hoy mismo para recibir las últimas novedades de la empresa, historias, información sobre eventos y mucho más.