iOS26 "Liquid Glass" Exploitation Chain

PDF REPORT
STATUS
DECLASSIFIED
SEVERITY
10.0
DISCOVERED
2025-12-12
UPLOADED
2025-12-18
#IOS #IOS26 #APPLE #WEBKIT #MOBILE #ZEROCLICK #WEB #WEBGL #USEAFTERFREE #KERNEL #PRIVESC #RCE #TARGETEDSURVEILLANCE

1. The Patient

Target: iPhone 12+ (A14 Bionic and newer) Component: WebKit (ANGLE) & XNU Kernel Vector: Mobile Safari / WebGL (Remote)

The target environment is the “Liquid Glass” iteration of iOS (v26). This update introduced a visual overhaul requiring substantial rewrites in Core Animation and WebKit to support advanced GPU compositing. These changes significantly expanded the attack surface.

Defensively, the A14 Bionic is a fortress. It enforces:

  • Pointer Authentication (PAC): Cryptographically signs pointers, neutralizing standard ROP/JOP attacks.
  • Page Protection Layer (PPL): A hypervisor-like layer that sandboxes the Kernel itself, preventing attackers from remapping memory as executable even with Kernel Read/Write access.

The Context: This is a CVSS 10.0 chain. It requires No Authentication, Zero User Interaction (beyond viewing a texture), and results in Permanent Root Access. It falls into the “Targeted Surveillance” category, hoarded by Private Sector Offensive Actors (PSOAs).

2. The Diagnosis

Root Cause: A Triad of Failures—Logic Error (ANGLE), Use-After-Free (WebKit), and Integer Overflow (Kernel).

Part 1: The Breach (CVE-2025-14174)

Component: ANGLE (OpenGL to Metal Translator) The first flaw lies in how ANGLE handles texture uploads. To upload a texture, the engine calculates memory allocation based on the user’s Unpack Settings.

  • The Logic Trap: The developer assumed the user’s unpack setting matches the actual image size.
  • The Mismatch: The exploit sets GL_UNPACK_IMAGE_HEIGHT to 1. The allocator calculates a tiny buffer size (Row_Pitch * 1).
  • The Overflow: The copy logic ignores the user setting and copies the actual texture data (e.g., 1000 rows) into the tiny buffer, causing a massive Heap Overflow.

Part 2: The Takeover (CVE-2025-43529)

Component: WebKit LayerPool The second flaw is a Use-After-Free in the rendering lifecycle.

  • Stack vs. Heap: The developer placed the LayerPool (a recycling bin for graphical objects) on the temporary Stack instead of the persistent Heap.
  • The Fatal Disconnect: Function Render() returns, destroying the stack frame and freeing the LayerPool. However, a background thread still holds a reference to it. When the thread wakes up to use the pool, it accesses invalid memory.

Part 3: The Escalation (CVE-2025-46285)

Component: XNU Kernel The final flaw allows the attacker to escape the sandbox via an Integer Overflow.

  • The Trap: The Kernel tracked timestamps using 32-bit integers.
  • The Equation: Deadline = Current Time + User Duration.
  • The Overflow: By providing a massive duration (e.g., 0xFFFFFFF0), the addition wraps around the 32-bit limit, resulting in a tiny number. The Kernel uses this tiny value to allocate a buffer, but writes full-sized data into it, corrupting the Process Credentials (struct proc).

3. The Kill-Chain

Phase 1: The Lure & Setup

The victim visits a malicious website containing crafted WebGL content (potentially via a 1-click link). WebKit passes drawing commands to ANGLE. The exploit sets GL_UNPACK_IMAGE_HEIGHT to 1, tricking the allocator.

Phase 2: Memory Corruption

The texture upload writes past the end of the allocated buffer, corrupting internal WebKit structures. This provides the “Write Primitive” needed to manipulate the Heap layout.

Phase 3: Seizing Control (PAC Bypass)

The attacker triggers the LayerPool Use-After-Free and sprays the heap to fill the freed slot with fake data.

  • Data-Only Attack: To bypass PAC, the exploit does not overwrite code pointers. Instead, it corrupts non-protected data fields (like Array Lengths), granting the browser arbitrary Read/Write access to its own memory space.

Phase 4: The Kernel Pivot

The compromised WebContent process issues a syscall to the Kernel (via IOKit), passing a crafted “User Duration” integer that is near the 32-bit maximum.

Phase 5: Privilege Escalation

The integer overflows inside the Kernel. The resulting Heap Overflow overwrites the struct proc of the calling process, manually changing the User ID (UID) to 0 (Root). The device is now fully compromised.

4. The Fix

The remediation requires decoupling buffer sizing from user input, enforcing heap allocation for shared objects, and modernizing integer types.

Part 1: ANGLE (Logic Fix)

// Commit 95a32cb37: Decoupled buffer sizing from user input.
// OLD: Used pixelsDepthPitch (derived from user input)
// NEW: Calculates size based on ACTUAL texture dimensions

size_t requiredSize = actualWidth * actualHeight * bytesPerPixel;
if (allocatedSize < requiredSize) {
    // SECURITY: Block the upload or reallocate to match reality.
    ReallocateBuffer(requiredSize);
}

Part 2: WebKit (Lifetime Fix)

// Bug 302502: Enforced Heap Allocation.
// Mandates LayerPool creation on the heap via smart pointers.

// Vulnerable:
// LayerPool pool; // Stack allocated, dies when function returns.

// Fixed:
RefPtr<LayerPool> pool = LayerPool::create(); // Heap allocated.
// The memory remains valid as long as 'pool' is referenced by any thread.

Part 3: Kernel (Integer Fix)

// XNU Update: 64-bit Adoption.
// Transition from 32-bit to 64-bit for time values to prevent wrapping.

// Vulnerable:
// uint32_t deadline = current_time + user_duration; // Overflows if > 2^32

// Fixed:
uint64_t deadline = current_time + user_duration; // Safe capacity.

Developer Takeaway

Handle the Edge-Cases.

  • Shared Code is a Shared Threat: Vulnerabilities in third-party libraries (like ANGLE) can compromise the entire OS.
  • Manage Your Lifetimes: Never rely on stack allocation for objects that might be referenced asynchronously. Use Smart Pointers (RefPtr, shared_ptr).
  • Modernize Your Integers: In 2025, using 32-bit integers for time or size calculations is a liability. Default to 64-bit to prevent silent overflows.
// END TRANSMISSION CREDIT: Google TAG & Apple SEAR