flawopen.com/Teardowns/cve-2024-4947-chrome-v8-type-confusion

● CVE-2024-4947 · CVSS 9.8 · Kritis
Riset Keamanan · FlawOpen

CVE-2024-4947: Chrome V8 JIT Compiler Type Confusion Teardown

Analisis teknis mendalam dan mitigasi rekayasa sistem untuk vulnerabilidade: How property getter transitions in V8's Turbofan JIT compiler tricked optimized native code into reading raw pointers as floating-point numbers, yielding in-the-wild remote code execution.

💡 Penjelasan Sederhana (ELI5)

Analogi dunia nyata: V8 makes JavaScript super fast by making assumptions. If you pass an array of numbers to a function 1,000 times, V8 turns that function into machine code that skips all safety checks. An attacker creates a sneaky property that changes the array from 'numbers' to 'object pointers' right in the middle of execution. The machine code treats an object's memory address as a number, letting the attacker read and write raw computer memory.

Konsep Kunci & Istilah

Turbofan JIT
Kompiler pengoptimal di mesin V8 Google yang mengubah bytecode JavaScript menjadi kode mesin khusus arsitektur berkecepatan tinggi.
Hidden Class / Map
Objek metadata internal V8 yang melacak tata letak, nama properti, dan tipe elemen objek JavaScript dalam memori (Map/HiddenClass).
Type Confusion
Cacat kerusakan memori yang terjadi ketika kode memperlakukan wilayah memori yang diinisialisasi sebagai Tipe A seolah-olah itu adalah Tipe B.
Map Deprecating Transition
Ketika modifikasi dinamis dari properti objek menyebabkan tata letak internalnya bermutasi, membutuhkan kode JIT yang dikompilasi sebelumnya untuk dideoptimalkan.

Analisis Akar Masalah (Root Cause)

Akar masalah bermula dari parameter batas yang tidak divalidasi pada sistem open source, yang memungkinkan desinkronisasi status dan bypass kontrol keamanan.

Alur Serangan Langkah demi Langkah

Step 1

1. JIT Warm-Up

The attacker runs a loop passing an array of floating-point numbers (PACKED_DOUBLE_ELEMENTS) to a function until Turbofan compiles it to unverified native assembly.

Step 2

2. Prototype Getter Interception

Inside a customized property getter, the attacker alters the array layout by storing an object reference, changing the map to PACKED_ELEMENTS.

Step 3

3. Unchecked Native Execution

Because Turbofan omitted a dynamic map transition check, the compiled native loop continues to read the array as raw 64-bit IEEE floats.

Step 4

4. Arbitrary Read/Write Primitive

The float values represent raw pointers. The attacker constructs an addrof (read address) and fakeobj (corrupt address) primitive to break out of the V8 sandbox.

Kode Sumber: Rentan vs Aman

✕ IMPLEMENTASI RENTAN
// VULNERABLE: Simplified C++ Turbofan Graph Optimization (v8/src/compiler/)
// The optimizer assumed Map state remained unchanged across property accesses!

Reduction JSNativeContextSpecialization::ReduceNamedAccess(Node* node) {
  MapRef receiver_map = GetReceiverMap(node);
  
  // VULNERABILITY:
  // If property access invokes a custom JS getter that mutates the object's Map,
  // Turbofan fails to emit an effect-dependent map verification node!
  if (receiver_map.is_stable()) {
    // Relies on static stability without guarding against dynamic in-getter mutation
    return BuildPropertyLoad(node, receiver_map); 
  }
  
  return NoChange();
}
✓ PERBAIKAN AMAN & KUAT
// SECURE: Explicit Map Transition Guard Insertion in Turbofan Graph
Reduction JSNativeContextSpecialization::ReduceNamedAccess(Node* node) {
  MapRef receiver_map = GetReceiverMap(node);

  // FIX: Verify map stability AND emit runtime type transition guard
  if (receiver_map.is_stable()) {
    dependencies()->DependOnStableMap(receiver_map);

    // Explicitly insert dynamic Map check node before unboxing properties
    Node* effect = NodeProperties::GetEffectInput(node);
    Node* check = graph()->NewNode(
        simplified()->CheckMaps(CheckMapsFlag::kNone, 
                               ZoneHandleSet<Map>(receiver_map.object())),
        receiver, effect, control);

    // If an in-flight getter changes the object layout, force JIT deoptimization!
    NodeProperties::ReplaceEffectInput(node, check);
    return BuildPropertyLoad(node, check, receiver_map);
  }

  return NoChange();
}

Daftar Periksa Penguatan Sistem Rekayasa