R3n3r0/CVE-2026-20700
GitHub: R3n3r0/CVE-2026-20700
针对arm64e iOS上dyld的PAC签名预言机漏洞(CVE-2026-20700)的概念验证项目,演示如何利用Mach-O构造触发dyld写入PAC有效指针。
Stars: 7 | Forks: 2
# dyld-signing-oracle-poc
对 dyld 的页内链接(page-in linking)和链式修复(chained fixup)机制作为 PAC 签名预言机(PAC signing oracle)的受控探索,围绕 CVE-2026-20700 展开。
在 arm64e 上,每个函数指针都经过硬件认证。本项目的目标是展示:通过精心构造的 Mach-O 文件,可以引导 dyld 自身——仅利用其正常的修复机制——在攻击者选择的槽位中生成 PAC 有效的指针。
测试平台:iPhone 14(iOS 18.5, arm64e)。
## 演示内容
1. **可控的链式修复绑定(controlled chained-fixup bind)** —— dyld 接受一个精心构造的 Mach-O dylib,并在其自身的 `__DATA` 段中向选定槽位写入 PAC 有效的函数指针。
2. **`fixupPage64` 中的确定性崩溃** —— 格式错误的 `page_start` / `next` 值将 dyld 驱动出页面边界,证明分支可达性。
3. **派发事件循环执行(dispatch event loop execution)** —— dyld 写入的 PAC 有效指针被注册为 `dispatch_source_t` 定时器处理函数,并通过事件循环自然调用,PoC 代码不直接调用该指针。
## 仓库结构
```
dyld-signing-oracle-poc/
├── Makefile ← orchestrates the full pipeline
├── src/
│ └── launcher.c ← iOS launcher (2 threads + dispatch chain-close)
├── generators/
│ ├── gen_exports.py ← generates exports.c (N dummy symbols)
│ ├── gen_client.py ← generates client.c (N imports, dyld gate stress)
│ └── gen_malformed_dylib.py ← generates libmalformed.dylib (hand-crafted Mach-O)
├── tools/
│ ├── scan_pointers.py ← classifies Mach-O pointer sections as W/R
│ └── inspect_fixups.py ← parses LC_DYLD_CHAINED_FIXUPS header
└── blog/
├── it/
│ └── dyld-signing-oracle.md ← write-up completo in italiano
└── en/
└── dyld-signing-oracle.md ← full write-up in English
```
### 构建输出(不提交)
| 文件 | 生成方式 |
|---|---|
| `exports.c` | `generators/gen_exports.py` + Makefile 哨兵符号(sentinel symbols) |
| `client.c` | `generators/gen_client.py` |
| `libmalformed.dylib` | `generators/gen_malformed_dylib.py` |
| `libexports.dylib` | 由 `exports.c` 经 clang 编译 |
| `libclient.dylib` | 由 `client.c` 经 clang 编译 |
| `PoCApp` | 由 `src/launcher.c` 经 clang 编译 |
| `PoCApp.ipa` | Makefile `package` 步骤生成 |
## 环境要求
- 安装了 Xcode 命令行工具的 macOS
- iOS SDK(`xcrun --sdk iphoneos --show-sdk-path`)
- Python 3
- 设备测试:Sideloadly 或开发者证书 + 配置文件
## 构建
```
# 默认完整构建 (arm64, 99k 符号)
make
# 迭代快速构建
make SYMBOLS=10000
```
## 预设
```
# fixupPage64 中的确定性崩溃 (分支可达性证明)
make stress
# 稳定的镜像内 write-what-where
make exploit
# dyld 写入 PAC 有效指针 → dispatch 自然调用它
make chain_close
```
## 分析工具
```
# 验证生成的 chained-fixup blob 布局
make verify
# 解析 libmalformed.dylib 的 LC_DYLD_CHAINED_FIXUPS 头部
make inspect
# 扫描编译二进制文件中的指针段 (GOT/non-lazy)
make scan
```
## 可调参数
| 变量 | 默认值 | 描述 |
|---|---|---|
| `SYMBOLS` | 99000 | libclient 中的绑定目标数量(小于 100k 以绕过 pre‑26.3 门限,小于 64k 以绕过 26.3+) |
| `STACK_KB` | 128 | 工作线程的栈大小(KB) |
| `BURN_KB` | 0 | 在 dlopen 之前消耗的栈 KB(0 = 自动) |
| `MARGIN_KB` | 24 | 自动消耗的余量(KB) |
| `ARM64E` | 0 | 使用 DYLD_CHAINED_PTR_ARM64E_USERLAND24 格式 |
| `MALFORM_PAGEIN` | 0 | 启用格式错误的页内链 |
| `MALFORM_TARGET_OFFSET` | — | `__DATA` 段内的目标偏移量(例如 `0x10`) |
| `CHAIN_CLOSE` | 0 | 第二个槽位 → `_attacker_hook`,启用派发演示 |
## 在设备上安装
```
# Ad-hoc 签名 (Sideloadly)
make chain_close
# 将 PoCApp.ipa 拖入 Sideloadly
# 真实证书
make resign IDENTITY="iPhone Developer: ..." PROFILE=embedded.mobileprovision
# 监控日志
idevicesyslog | grep "POC"
```
## 原理说明
`PoCApp` 内部的运行时加载顺序:
1. `libexports.dylib` —— 首先加载(`RTLD_GLOBAL`),为后续的 `dlopen` 提供 `write_target_value` 和 `attacker_hook`。
2. `libclient.dylib` —— 由线程 B(128KB 栈)加载;约 99k 个绑定目标用于触发 dyld 的页内链接门(page-in linking gate)。
3. `libmalformed.dylib` —— 由线程 A 加载;精心构造的链式修复链使 dyld 解析并将 `_write_target_value`(以及可选的 `_attacker_hook`)写入 `__DATA+0x10` / `+0x20`。
4. 线程 A 读取写入的槽位,验证金丝雀值(canaries),然后调用 dyld 写入的函数指针。
5. 在 `chain_close` 模式下,主线程将 `__DATA+0x20` 注册为 `dispatch_source_t` 定时器处理函数——事件循环在 1 秒后自动调用该函数,PoC 代码不直接调用。
## 博客文章
完整的技术文章,提供意大利语和英语版本。涵盖:PAC 硬件机制、dyld 作为指针生成器、链式修复编码从零开始、页内链接门机制、Mach-O 工程陷阱(`sizeofcmds`、节区计数、步长)、金丝雀验证的数据布局、99k 符号门限、可达性崩溃证明、稳定的段内原语、arm64e 签名预言机概念、派发定时器链闭合。
- [🇮🇹 意大利语 — `blog/it/dyld-signing-oracle.md`](blog/it/dyld-signing-oracle.md)
- [🇬🇧 英语 — `blog/en/dyld-signing-oracle.md`](blog/en/dyld-signing-oracle.md)
标签:0day挖掘, ARM64e, CVE-2026-20700, dispatch_source_t, dyld漏洞, iOS 18.5, iOS安全, iPhone 14, Mach-O格式, PAC签名认证, PoC, 事件循环, 代码执行, 内存破坏, 内核安全, 函数指针认证, 控制流完整性, 操作系统安全, 暴力破解, 绕过, 逆向工具, 链式修复