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

● CVE-2024-4947 · CVSS 9.8 · 심각
보안 연구 · FlawOpen

심층 기술 분석: CVE-2024-4947: Chrome V8 JIT Compiler Type Confusion Teardown

vulnerabilidade 소스 코드 심층 기술 분석 및 시스템 보안 강화 가이드: 취약점 근본 원인과 패치 메커니즘 분석.

💡 알기 쉬운 설명 (ELI5)

직관적인 현실 비유 설명: 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.

핵심 개념 및 용어

Turbofan JIT
보안 개념 (Turbofan JIT): The optimizing compiler in Google's V8 engine that converts JavaScript bytecode into high-speed architecture-specific machine code.
Hidden Class / Map
보안 개념 (Hidden Class / Map): V8's internal metadata object tracking the layout, property names, and element types of JavaScript objects in memory.
Type Confusion
보안 개념 (Type Confusion): A memory corruption flaw occurring when code treats a memory region initialized as Type A as if it were Type B.
Map Deprecating Transition
보안 개념 (Map Deprecating Transition): When dynamic modification of an object property causes its internal layout to mutate, requiring previously compiled JIT code to deoptimize.

근본 원인 분석 (Root Cause)

근본 원인은 오픈 소스 시스템의 검증되지 않은 경계 매개변수로 인해 상태 비동기화 및 보안 제어 우회가 발생한 데 있습니다.

단계별 공격 실행 흐름

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.

소스 코드 비교: 취약한 구현 vs 보안 패치

✕ 취약한 구현
// 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();
}
✓ 보안 강화 패치
// 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();
}

엔지니어링 및 시스템 보안 강화 체크리스트