Firefox IPC Sandbox Escape

PDF REPORT
STATUS
DECLASSIFIED
SEVERITY
10.0
DISCOVERED
2025-03-27
UPLOADED
2025-12-18
#FIREFOX #WINDOWS #SANDBOXESCAPE #IPC #PSEUDOHANDLE #RCE #BROWSER #JIT #PRIVESC #BINEXP

1. The Patient

Target: Mozilla Firefox Component: ipc_channel_win.cc (IPC Broker) Vector: Windows Handle Duplication (Remote)

Firefox relies on the Electrolysis multi-process architecture to separate untrusted web content from system resources.

  • The Parent (Broker): Runs with User Privileges (Medium Integrity). It manages files, network, and hardware.
  • The Content (Renderer): Runs in a Sandbox (Low Integrity). It parses HTML/JS and renders the page.
  • IPC: The bridge between them. Since the Renderer cannot touch resources directly, it asks the Parent to perform actions on its behalf.

The vulnerability resides in the IPC Handle Sharing mechanism on Windows. The Broker blindly trusted an integer provided by the compromised Renderer, leading to a catastrophic Sandbox Escape.

The Context: This vulnerability is rated CVSS 10.0. It implies No Authentication, No User Interaction (beyond the initial page load), and results in Full Shell Access on the host machine.

2. The Diagnosis

Root Cause: Semantic Confusion regarding Windows Pseudo-Handles.

Windows uses Handles to track resources. A handle is simply an integer index in a kernel table. Process A cannot use Process B’s handles directly; they must be Duplicated by the Kernel.

The flaw exists in the logic that allows the Renderer to ask the Broker to “relay” a handle:

  1. The Request: The Renderer sends an IPC message: “Please duplicate Handle X to me.”
  2. The Execution: The Broker executes DuplicateHandle(BrokerProcess, X, RendererProcess...).
  3. The Assumption: The Broker assumes X is a valid handle index that belongs to the Renderer.
  4. The Reality: The Broker failed to check if X was a Pseudo-Handle. In Windows, specific negative integers have magical, context-dependent meanings:
    • -1 = Current Process
    • -2 = Current Thread

The danger is that -2 means “My Thread.” When the Renderer sends -2, it means “Renderer Thread.” But when the Broker passes -2 to the Kernel, the Kernel interprets it as “Broker Thread.”

3. The Kill-Chain

Phase 1: JIT Optimization Trap (Initial RCE)

The exploit begins with a JavaScript file that triggers a bug in the JIT (Just-In-Time) Compiler.

  • Type Confusion: The JIT assumes a variable is always an Integer, removing safety checks. The script swaps it for an Object mid-execution.
  • Primitives: This mismatch allows the attacker to read memory (addrOf) and write fake objects (fakeObj).
  • Execution: A fake ArrayBuffer is created to write shellcode into executable WASM memory. Control flow is hijacked. The attacker now has code execution inside the Sandbox.

Phase 2: The IPC Pivot

To escape the sandbox, the attacker pivots to the IPC layer. They construct a malicious “Relay Message” destined for the Broker.

  • Payload: The handle value is set to the magic integer -2 (0xFFFFFFFE).

Phase 3: The Fatal Leak

The Broker receives the message and calls DuplicateHandle.

  • Input: Source=BrokerProcess, Handle=-2.
  • Kernel Logic: The Kernel sees -2 coming from the Broker. It resolves this to the Broker’s Main Thread.
  • Output: The Kernel creates a THREAD_ALL_ACCESS handle to the Broker and sends it back to the Renderer.

Phase 4: Weaponization & System Compromise

The compromised Renderer now holds a handle that grants full control over the Parent process.

  1. Freeze: Calls SuspendThread() to pause the Parent.
  2. Hijack: Calls SetThreadContext() to overwrite the Instruction Pointer (RIP) of the Parent process.
  3. Resume: Calls ResumeThread().

Impact: The Parent process wakes up and immediately executes the attacker’s shellcode. The malware now runs with Medium Integrity, bypassing all sandbox restrictions and granting full access to the operating system.

4. The Fix

The remediation requires validating the context of the handle before processing it. The Broker must explicitly reject OS “Magic Numbers.”

Vulnerable Logic (Conceptual):

// VULNERABLE: Blindly passes user input to the Kernel.
HANDLE handle_value = message.ReadInt(); // Attacker sends -2

DuplicateHandle(
    GetCurrentProcess(), // Source: Broker
    handle_value,        // Value: -2 (Interpreted as Broker's Thread)
    target_process,
    &new_handle,
    ...
);

Patched Logic:

// PATCHED LOGIC in ipc_channel_win.cc

// Helper to detect magic values (-1, -2, etc.)
// Windows reserves the range [-12, -1] for current context pseudo-handles.
inline bool IsPseudoHandle(HANDLE handle) {
    int32_t value = (int32_t)(uintptr_t)handle;
    return value >= -12 && value < 0;
}

// In the IPC processing loop:
if (IsPseudoHandle(remote_handle)) {
    // SECURITY: Renderer is trying to trick us.
    LOG(ERROR) << "Security: Received pseudo-handle.";
    return false; // Abort connection
}

// Safe to proceed only if it's a real index.
DuplicateHandle(..., remote_handle, ...);

Developer Takeaway

Context Awareness > Type Safety. Validating that an input is an “Integer” is insufficient when that integer controls system resources. Magic numbers (like -1 or -2 in Windows) are powerful context-switching mechanisms. Trust boundaries in IPC must enforce that handles are strictly local indices, never interpreted execution contexts. Know your input.

// END TRANSMISSION CREDIT: Mozilla Security Team