
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.

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.

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.

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.

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:

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.

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.

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:

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.

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:

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.

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.

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:

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:

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

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.

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.

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:

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 ú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.
Referencias
https://nvd.nist.gov/vuln/detail/CVE-2024-0517
https://cwe.mitre.org/data/definitions/843.html
https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/
https://jhalon.github.io/chrome-browser-exploitation-1/
https://whenderson.dev/blog/webgl-garbage-collection/
https://v8.dev/
https://github.com/Uniguri/CVE-nday/tree/master/Chrome/V8/CVE-2024-0517
