Type Confusion: El Exploit de los Navegadores
Las vulnerabilidades de type confusion permiten a un atacante tratar un objeto en memoria como si fuera de otro tipo, corrompiendo datos y logrando ejecución de código. Son la clase de bug dominante en exploits de navegadores modernos, especialmente en motores JavaScript como V8, SpiderMonkey y JavaScriptCore.
Cuando un objeto no es lo que el procesador cree
En septiembre de 2023, una imagen WebP maliciosa permitía ejecutar código en cualquier navegador basado en Chromium, Firefox, Safari, Signal, 1Password y cientos de aplicaciones Electron. En marzo de 2025, una confusión de tipos en TurboFan (el compilador JIT de V8) logró ejecución remota de código como zero-day. En abril de 2021, una type confusion en V8 fue añadida al catálogo KEV de CISA como vulnerabilidad explotada activamente.
Estas no son coincidencias aisladas. Las vulnerabilidades de type confusion son la clase de bug dominante en la explotación de navegadores modernos. Son el resultado directo de la tensión entre rendimiento y seguridad en los motores JavaScript más sofisticados del mundo.
¿Qué es type confusion?
Type confusion (CWE-843) ocurre cuando un programa asigna o inicializa un recurso (puntero, objeto, variable) usando un tipo, pero posteriormente accede a ese recurso interpretándolo como un tipo diferente e incompatible.
En términos de memoria, el problema es la reinterpretación: los mismos bytes en memoria tienen significados completamente distintos según el tipo con el que se lean. Un valor de punto flotante de 64 bits y un puntero a un objeto JavaScript ocupan los mismos 8 bytes, pero representan cosas radicalmente diferentes. Si el motor cree que está leyendo un double pero en realidad hay un puntero, o viceversa, el atacante puede fabricar punteros falsos o leer direcciones de memoria como si fueran números.
Ejemplo conceptual en C
struct Animal {
int legs;
char *sound;
};
struct Vehicle {
int wheels;
void (*start_engine)(void); // puntero a función
};
// El programador asume que 'ptr' es un Animal
void make_sound(void *ptr) {
struct Animal *a = (struct Animal *)ptr;
printf("Sound: %s\n", a->sound); // lee el 2.º campo como char*
}
// Pero si ptr apunta a un Vehicle:
struct Vehicle car = {4, &malicious_function};
make_sound(&car);
// a->sound == car.start_engine == dirección de malicious_function
// printf intenta leer esa dirección como cadena → crash o leak
En este ejemplo trivial, los campos sound y start_engine ocupan la misma posición en memoria (offset 8 desde el inicio de la estructura). Al tratar un Vehicle como Animal, se reinterpreta un puntero a función como un puntero a cadena. En un escenario más sofisticado, el atacante puede controlar el contenido de la estructura para fabricar punteros arbitrarios.
Motores JavaScript: la fábrica de type confusion
Los navegadores modernos ejecutan JavaScript a velocidades cercanas al código nativo gracias a compiladores JIT (Just-In-Time). Chrome usa V8 (con los compiladores Sparkplug, Maglev y TurboFan), Firefox usa SpiderMonkey (con Warp/IonMonkey) y Safari usa JavaScriptCore (con DFG y FTL). Estos compiladores son la fuente más prolífica de vulnerabilidades de type confusion en la industria.
Cómo funciona la optimización JIT
JavaScript es un lenguaje dinámico: una variable puede contener un número, una cadena, un objeto o undefined en diferentes momentos de la ejecución. Interpretar este código directamente es lento. Los compiladores JIT observan el comportamiento del programa y generan código máquina especializado basado en asunciones de tipo:
function sum(a, b) {
return a + b;
}
// Las primeras 1000 llamadas usan enteros:
for (let i = 0; i < 1000; i++) sum(i, i + 1);
// TurboFan observa: "a y b siempre han sido SMI (Small Integer)"
// Genera código máquina que asume enteros:
// mov eax, [a] ; cargar a como entero
// add eax, [b] ; sumar b como entero
// jo deoptimize ; si hay overflow, deoptimizar
// ret
Si una llamada posterior pasa una cadena (sum("hello", "world")), V8 detecta que la asunción de tipo fue violada, descarta el código optimizado y vuelve al intérprete. Este proceso se llama deoptimización.
Dónde falla la asunción: el origen del bug
Los bugs de type confusion en JIT ocurren cuando:
- El compilador hace una asunción de tipo incorrecta: el análisis de tipos infiere un tipo que no corresponde con la realidad en todos los casos posibles
- Una operación con efectos secundarios cambia el tipo sin que el compilador lo sepa: una callback, un Proxy, un getter/setter o una interrupt modifica la estructura de un objeto, pero el JIT no inserta una comprobación de tipo después
- El compilador elimina comprobaciones de tipo redundantes: una optimización legítima (eliminar un CheckMaps que "ya se verificó") resulta incorrecta porque un efecto secundario entre medias cambió el mapa del objeto
En V8, los objetos JavaScript tienen un "mapa" (hidden class) que describe su layout: qué propiedades tiene, en qué offsets, de qué tipos son. El código optimizado compila accesos a propiedades como accesos directos a offsets de memoria. Si el mapa cambia y el código optimizado no lo detecta, accede al offset equivocado: type confusion.
Anatomía de un exploit de navegador por type confusion
La explotación de type confusion en motores JavaScript sigue un patrón bien establecido con varias fases.
Fase 1: Provocar la confusión
El atacante construye código JavaScript que engaña al compilador JIT para que genere código con una asunción de tipo incorrecta. El objetivo típico es confundir dos representaciones internas de arrays:
- Array de doubles (PACKED_DOUBLE_ELEMENTS): almacena valores de punto flotante directamente
- Array de objetos (PACKED_ELEMENTS): almacena punteros a objetos JavaScript
Ambos usan el mismo backing store (un bloque contiguo de 8 bytes por elemento), pero la interpretación es radicalmente diferente. Si el JIT cree que un array es de doubles cuando en realidad contiene punteros a objetos, el atacante puede:
- Leer punteros como doubles: obtener la dirección de memoria de un objeto JavaScript (primitiva
addrof) - Escribir doubles que se interpretan como punteros: fabricar una referencia a un objeto falso (primitiva
fakeobj)
Fase 2: Construir primitivas addrof y fakeobj
// Pseudocódigo conceptual (simplificado)
// Asume que 'confused_array' es un array que el JIT trata como
// doubles pero que en realidad contiene objetos
function addrof(obj) {
// Colocar el objeto en el array confundido
confused_array[0] = obj;
// El JIT lee el elemento como double (bits del puntero)
return confused_double_view[0];
}
function fakeobj(addr) {
// Escribir una dirección como double
confused_double_view[0] = addr;
// El JIT devuelve el elemento como objeto
// (interpreta los bits del double como puntero)
return confused_array[0];
}
Con addrof, el atacante conoce la dirección de cualquier objeto JavaScript. Con fakeobj, puede crear una referencia a un "objeto" en una dirección de memoria que controla.
Fase 3: Lectura/escritura arbitraria
Con las primitivas anteriores, el atacante fabrica un ArrayBuffer o TypedArray falso cuyo backing store apunta a una dirección de memoria controlada:
- Crear un array legítimo y obtener su dirección con
addrof - Fabricar un objeto falso con
fakeobjque tenga la estructura de unTypedArraypero con el campobacking_storeapuntando a la dirección objetivo - Leer y escribir a través del
TypedArrayfalso da lectura/escritura arbitraria en el espacio de memoria del proceso
Fase 4: Ejecución de código
Con lectura/escritura arbitraria, el atacante busca una región de memoria que sea ejecutable y escribible (RWX). En navegadores modernos, la opción más común es:
- Crear una función WebAssembly (se compila a código nativo)
- Localizar el bloque de código compilado en memoria (usando la primitiva de lectura)
- Sobrescribir el código máquina de la función WASM con shellcode
- Ejecutar la función WASM (que ahora ejecuta el shellcode del atacante)
Esto logra ejecución de código arbitrario dentro del proceso del renderer del navegador.
CVEs reales: la historia en vulnerabilidades
CVE-2021-21224: Type confusion en V8
Tipo: Type confusion (entero a otro tipo numérico) Motor: V8 (Chrome < 90.0.4430.85) Impacto: Ejecución remota de código dentro del sandbox Estado: Añadida al catálogo KEV de CISA (explotada activamente)
Esta vulnerabilidad residía en la forma en que V8 manejaba conversiones de tipos numéricos en código optimizado. Un integer overflow en una operación de conversión producía un valor que violaba las asunciones del compilador, permitiendo una confusión de tipos que daba lectura/escritura arbitraria dentro del sandbox de V8.
El exploit fue detectado en uso activo antes de que Google publicara el parche, lo que la convierte en un zero-day explotado in-the-wild. CISA la añadió a su catálogo de Known Exploited Vulnerabilities (KEV), obligando a las agencias federales de EE.UU. a parchear en un plazo determinado.
CVE-2022-1096: Type confusion en V8
Tipo: Type confusion (CWE-843) Motor: V8 (Chrome < 99.0.4844.84) Impacto: Heap corruption via crafted HTML page Reportado por: Anonymous
Otra type confusion en V8 que permitía corrupción del heap a través de una página HTML maliciosa. Google confirmó la existencia de un exploit in-the-wild y publicó un parche de emergencia. Los detalles técnicos se mantuvieron bajo embargo durante semanas para dar tiempo a que los usuarios actualizaran.
CVE-2022-1134: Super Inline Cache type confusion
Tipo: Type confusion en SuperIC (Super Inline Cache) Motor: V8 (Chrome < 100.0.4896.60) Reportado por: Man Yue Mo (GitHub Security Lab) Impacto: RCE en el renderer sandbox
El investigador Man Yue Mo documentó esta vulnerabilidad en detalle en el blog de GitHub Security Lab. El bug residía en la implementación de Super Inline Cache, un mecanismo de optimización para accesos a propiedades de clases JavaScript con super. La historia de SuperIC es reveladora: el mismo patrón de bug se encontró primero en la implementación runtime (CVE-2019-5790), luego en la implementación JIT (CVE-2019-5843) y finalmente en la implementación Torque (CVE-2019-5877). Cada corrección puntual dejaba otra implementación vulnerable.
CVE-2020-6418: Side-effect modelling incorrecto en TurboFan
Tipo: Type confusion por modelado incorrecto de efectos secundarios Motor: V8 TurboFan (Chrome) Reportado por: Clement Lecigne (Google Threat Analysis Group) Impacto: Explotado in-the-wild
Google Project Zero documentó esta vulnerabilidad en profundidad. El bug estaba en la función InferReceiverMapsUnsafe de TurboFan. La operación JSCreate estaba correctamente marcada como teniendo efectos secundarios, pero una ruta de código específica que procesaba JSCreate olvidaba marcar el resultado como no fiable cuando JSCreate no era el nodo que estaba analizando. Esto permitía a un atacante usar Reflect.construct con un Proxy como tercer argumento para cambiar el mapa de un objeto después de que TurboFan hubiera eliminado la comprobación de tipo.
El atacante usó esta confusión para intercambiar los tipos de arrays de punto flotante y de punteros, implementando la primitiva fakeobj y, a partir de ahí, sobrescribiendo una función WebAssembly compilada con shellcode.
CVE-2025-2135: TurboFan TransitionElementsKindOrCheckMap
Tipo: Type confusion en el nodo TransitionElementsKindOrCheckMap Motor: V8 TurboFan (Chrome < 134.0.6998.88) Reportado por: Equipo Zellic Impacto: RCE, usado como zero-day en V8CTF
El equipo de Zellic descubrió mediante fuzzing que la función InferMapsUnsafe() de TurboFan no manejaba correctamente el aliasing al procesar el nodo TransitionElementsKindOrCheckMap, introducido relativamente reciente. Esto permitía confusión de tipos entre arrays de objetos y arrays de doubles, la primitiva clásica que da lectura/escritura arbitraria dentro del sandbox de V8. Zellic lo usó para ganar el V8CTF de Google como zero-day.
CVE-2023-4863: Heap buffer overflow en libwebp
Tipo: Heap buffer overflow (no type confusion pura, pero derivada de confusión en el manejo de dimensiones) Librería: libwebp (afectó Chrome, Firefox, Safari, Signal, 1Password, Electron) Impacto: RCE vía imagen WebP maliciosa Severidad: CVSS 8.8 (Critical)
Aunque técnicamente clasificada como heap buffer overflow, esta vulnerabilidad ilustra cómo errores en la interpretación de tipos de datos (un integer overflow de 32 bits en el cálculo de dimensiones de imagen) producen corrupción de memoria a gran escala. Una imagen WebP con dimensiones manipuladas desbordaba el cálculo de tamaño del buffer, permitiendo escritura fuera de límites. Al estar libwebp integrada en prácticamente todo software que renderiza imágenes WebP, el impacto fue transversal: navegadores, aplicaciones de mensajería, editores de imagen y cualquier app Electron.
Type confusion fuera de los navegadores
Deserialización insegura en Java y .NET
La deserialización de objetos en Java y .NET es un escenario clásico de type confusion a nivel de aplicación. Cuando una aplicación deserializa datos de una fuente no confiable, un atacante puede manipular el stream serializado para que un campo que debería contener un tipo benigno (por ejemplo, String) contenga un tipo peligroso (por ejemplo, un objeto con un readObject que ejecuta comandos del sistema).
Frameworks como Apache Commons Collections, Spring y Jackson han sufrido cadenas de deserialización que permiten ejecución remota de código. La herramienta ysoserial genera payloads para docenas de gadget chains conocidas en el ecosistema Java.
En .NET, las vulnerabilidades en BinaryFormatter, ObjectStateFormatter y JavaScriptSerializer siguen el mismo patrón: el deserializador confía en los metadatos de tipo del stream serializado y reconstruye objetos del tipo que el atacante indica.
Type confusion en parsers de formatos binarios
Los parsers de formatos de archivo complejos (PDF, Office, fuentes TrueType/OpenType, imágenes TIFF) frecuentemente contienen type confusion cuando los campos de tipo de un registro no se validan antes de usarlos para interpretar el contenido del registro. Un campo que dice "esto es un texto" pero contiene datos binarios interpretados como punteros es un vector de type confusion.
Spectre: type confusion a nivel de hardware
Los ataques Spectre (CVE-2017-5753, CVE-2017-5715) representan type confusion a nivel del procesador. La predicción de ramas del CPU ejecuta especulativamente código que no debería ejecutarse (la rama incorrecta de un if), operando sobre datos cuyo "tipo" (accesible o no) es incorrecto durante la ventana de ejecución especulativa. Aunque los resultados especulativos se descartan, los efectos en la cache permanecen y permiten filtrar datos a través de canales laterales.
En cierto sentido, Spectre demuestra que la type confusion no es solo un problema de software: es una consecuencia fundamental de optimizaciones que asumen un tipo o estado que resulta incorrecto.
Por qué los compiladores JIT crean type confusion
La raíz del problema es la tensión entre rendimiento y seguridad en la compilación JIT.
Especulación de tipos
JavaScript no tiene tipos estáticos. El JIT debe especular basándose en ejecuciones previas. Cada especulación es una asunción que puede violarse. Cuanto más agresiva la especulación, mejor el rendimiento y mayor el riesgo de type confusion.
Eliminación de comprobaciones redundantes
Después de verificar el tipo de un objeto (CheckMaps en V8), el compilador elimina comprobaciones posteriores del mismo objeto si cree que nada entre medias puede cambiar su tipo. Pero JavaScript permite efectos secundarios en lugares inesperados: getters, setters, Proxies, Symbol.toPrimitive, valueOf, interrupts. Si alguno de estos cambia el mapa del objeto entre el CheckMaps y el acceso, la comprobación eliminada habría sido necesaria.
Complejidad del grafo de optimización
TurboFan opera sobre un grafo de nodos que representa el programa. Las optimizaciones son transformaciones de este grafo: eliminación de nodos redundantes, propagación de tipos, inlining de funciones. Con cientos de operadores y miles de interacciones posibles, verificar que cada transformación preserve la semántica de tipos es un problema de verificación formal que ningún motor JavaScript ha resuelto completamente.
Tamaño de la superficie de ataque
V8 tiene millones de líneas de código, con TurboFan como uno de los componentes más complejos. Cada nuevo operador, cada nueva optimización y cada nueva funcionalidad de JavaScript (cada propuesta TC39 que avanza a Stage 3) amplía la superficie de ataque. Los equipos de seguridad de Chrome, Firefox y Safari invierten recursos enormes en fuzzing y auditoría, pero la tasa de nuevas vulnerabilidades de type confusion se mantiene constante: cada año se publican decenas de CVEs en esta categoría.
Mitigaciones
Control Flow Integrity (CFI)
CFI restringe los destinos válidos de saltos indirectos (calls a través de punteros a función, virtual dispatches). Dificulta que un type confusion se convierta en ejecución de código, porque incluso si el atacante corrompe un puntero a función, el destino debe estar en el conjunto de destinos válidos.
V8 Sandbox
Desde Chrome 123, V8 implementa un sandbox de memoria que limita las direcciones que el código JavaScript compilado puede acceder. Incluso con lectura/escritura arbitraria dentro del sandbox, el atacante no puede acceder directamente a la memoria del proceso del navegador fuera de la región sandbox.
Type checks redundantes
Los motores insertan comprobaciones de tipo en puntos estratégicos del código optimizado. Cuando una optimización elimina una comprobación, otras comprobaciones actúan como red de seguridad. V8 ha añadido progresivamente más "type barriers" en las interfaces entre optimización y ejecución.
Site Isolation
Chrome ejecuta cada sitio web en un proceso separado. Si un atacante logra ejecución de código en el renderer de evil.com, no puede acceder a la memoria del renderer de bank.com. Para comprometer otro sitio necesita un segundo exploit que escape del sandbox del proceso.
Fuzzing continuo
Google opera ClusterFuzz (con miles de cores) y Fuzzilli (fuzzer de JavaScript grammar-aware). Estos sistemas encuentran cientos de bugs al año antes de que los atacantes los descubran. El fuzzer genera programas JavaScript que estresan las rutas de optimización del JIT buscando crashes que indiquen corrupción de memoria.
MiraclePtr y garbage collection seguro
MiraclePtr (Chrome) y técnicas similares protegen contra use-after-free (que a menudo se combina con type confusion). Un garbage collector que verifica la integridad de las referencias reduce la probabilidad de que una confusión de tipos se convierta en un puntero colgante.
Detección y análisis para equipos de seguridad
Indicadores de explotación de type confusion en navegadores
Para equipos SOC y analistas de CTI, estos son los indicadores de un ataque que explota type confusion en navegadores:
- Crashes del proceso renderer con señales de corrupción de heap (SIGSEGV, SIGBUS en direcciones que parecen punteros fabricados)
- JavaScript ofuscado que crea y manipula arrays de diferentes tipos, alterna entre operaciones con enteros y doubles, y fuerza la compilación JIT con bucles de warmup
- Creación de funciones WebAssembly seguida de acceso a su código compilado (indicador de que se busca una región RWX)
- Cadenas de exploit que combinan múltiples CVEs: primero un type confusion para RCE en el renderer, luego un sandbox escape
Herramientas de análisis
- Chrome DevTools: el panel Memory permite inspeccionar el heap de V8 y detectar objetos con mapas inconsistentes
- V8 flags de debug:
--trace-opt,--trace-deopt,--trace-turborevelan las decisiones de optimización y deoptimización - AddressSanitizer (ASan): detecta accesos fuera de límites y use-after-free que resultan de type confusion
- Fuzzilli: fuzzer de JavaScript especializado en encontrar bugs de JIT
Relevancia en campañas APT
Los exploits de navegador por type confusion son componentes frecuentes de las cadenas de explotación usadas por grupos APT y por vendors de spyware comercial:
- NSO Group (Pegasus) ha utilizado exploits de navegador como vector de acceso inicial en campañas zero-click
- Intellexa (Predator) combinó exploits de Chrome y Android en cadenas de ataque documentadas por Google TAG y Citizen Lab
- Grupos APT chinos (como APT41) y norcoreanos (Lazarus) han explotado vulnerabilidades de V8 como acceso inicial en campañas de espionaje y robo financiero
Para un analista CTI, las vulnerabilidades de type confusion en navegadores son indicadores de amenazas sofisticadas con capacidades de desarrollo de exploits propios o acceso a mercados de zero-days.
Relevancia en el mapa ATT&CK
Las vulnerabilidades de type confusion en navegadores se clasifican bajo T1203 (Exploitation for Client Execution). El atacante envía a la víctima un enlace o la redirige a una página que contiene el exploit JavaScript. La ejecución es silenciosa: no requiere interacción más allá de visitar la página (o, en ataques zero-click, ni siquiera eso si el exploit se entrega vía iMessage, WhatsApp u otro mensajero que renderice contenido web automáticamente).
En la cadena de ataque completa:
- T1189 (Drive-by Compromise): la víctima visita un sitio comprometido o un watering hole
- T1203 (Exploitation for Client Execution): el exploit de type confusion logra ejecución de código en el renderer
- T1055 (Process Injection): escape del sandbox para inyectar en procesos con más privilegios
- T1082 (System Information Discovery): una vez en el sistema, el malware recopila información del entorno
- T1105 (Ingress Tool Transfer): descarga del implant completo
Conclusión
Las vulnerabilidades de type confusion son el reflejo directo de la complejidad de los motores JavaScript modernos. La necesidad de ejecutar un lenguaje dinámico con rendimiento cercano al código nativo requiere compiladores JIT que hagan asunciones agresivas sobre los tipos de datos. Cada asunción incorrecta es una oportunidad de explotación.
A diferencia de las vulnerabilidades de format string o los buffer overflows clásicos, donde el bug es un error de programación individual, las type confusion en JIT son a menudo consecuencia de interacciones sutiles entre múltiples componentes del compilador. Corregir un caso específico no elimina la clase de bug: cada nueva optimización y cada nueva funcionalidad del lenguaje abre nuevas rutas para que el atacante fuerce una confusión de tipos.
Para la comunidad de seguridad, esto significa que los exploits de navegador basados en type confusion seguirán siendo relevantes durante años. Los equipos de defensa deben priorizar la actualización de navegadores como control de seguridad crítico, monitorizar las publicaciones de CVEs en V8/SpiderMonkey/JavaScriptCore, y considerar que cualquier estación de trabajo con un navegador desactualizado es un vector de acceso inicial viable para actores con capacidades de exploit development.
Técnicas MITRE ATT&CK referenciadas
Preguntas frecuentes
Artículos relacionados
Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.