bohmiiidd/libimobiledevice-0DayVulnSuite
GitHub: bohmiiidd/libimobiledevice-0DayVulnSuite
针对 libimobiledevice 的 13 个漏洞概念验证集合,提供可复现的触发器用于补丁验证和 CVE 查阅。
Stars: 0 | Forks: 0
# libimobiledevice — PoC 集合(13 个发现)
这是针对 `finds.md` 中记录的宿主机端 `libimobiledevice` 错误的概念验证触发器,
每一个都包含了说明、根本原因、触发方式和影响
评估。
**范围 / 威胁模型。** 对端扮演*设备*(AFC daemon / service
daemon)或 usbmux/TCP 通道上的 MitM。受害方是任何
链接了 `libimobiledevice` 并调用其公开 API(`idevice*`
工具、`ifuse`、GUI 应用)的宿主机进程。这**不是**互联网 RCE;它是一个“与你配对的恶意对端”模型。这里没有任何对第三方
的攻击 —— 它是用于修补/CVE 查阅的实验环境环回测试套件。
**验证基准**:基于 `1.4.0-9-gfa0f791` 检出版本(对于此处引用的每一行,它与当前上游的 `master` 版本完全一致 —— `src/afc.c` 已与 GitHub 上的版本进行过 diff 比对)。
## 布局
| 文件 | 目的 |
|------|---------|
| `victim.c` | 用于 AFC 错误的宿主机客户端。仅使用公开的 AFC API;环回 TCP 垫片 |
| `peer.py` | 恶意 AFC daemon 模拟器,每个 AFC 错误对应一种模式 |
| `services_victim.c` | 用于 PLS/Ostrace/DBG/WI/RP 的宿主机客户端(公开 API + RSS 监视器) |
| `services_peer.py` | 恶意服务 daemon 模拟器(pls, ostrace, dbg, wi, rp) |
| `build.sh` | 编译两个测试客户端(`LIBROOT` = libimobiledevice 安装前缀) |
| `run.sh` | 运行一个错误(索引 1..13):启动对端,运行受害端,打印特征 |
| `README.md` | 本文件 |
## 快速开始(Linux / WSL)
```
# 1. 构建 library,然后构建 victims
./poc/build.sh
# 2. heap overflow (finds.md Bug #2)
./poc/run.sh 2
# 3. 未配对的 key -> strdup(NULL) (Bug #5)
./poc/run.sh 5
# 4. 错误路径 double-free (AFC-4)
./poc/run.sh 6
# 5. reverse-proxy Connect hostlen 被忽略 (RP-1)
./poc/run.sh 10
# 6. 短 FILE_OPEN_RES handle 泄漏 (Bug #12)
./poc/run.sh 13
```
## 漏洞索引(与 `finds.md` 匹配)
| # | ID | 组件 | 根本原因(单行概述) | 影响 | 运行 |
|---|-----|-----------|----------------------|--------|-----|
| 1 | Bug #1 | `afc.c` | `make_strings_list` 无界 `strdup`/`strlen` 遍历 | OOB **读取** / 泄漏(放大器) | `run.sh 1`(链式) |
| 2 | Bug #2 / AFC-5 | `afc.c` | 分配 `entire_len`,接收 `this_len`;u64→u32 截断 | 堆**写入**溢出 | `run.sh 2` |
| 3 | Bug #3 | `afc.c` | `service_receive` 前未检查 `malloc` | DoS(大部分被拦截) | `run.sh 3`(对照组) |
| 4 | Bug #4 | `afc.c` | `make_strings_list` 中未检查 `malloc`/`strdup` | DoS / NULL 解引用 | `run.sh 4` |
| 5 | Bug #5 / AFC-6 | `afc.c` | 不成对的键 → `strdup(*(ptr+1))` 且为 NULL | SEGV / 崩溃 | `run.sh 5` |
| 6 | AFC-4 | `afc.c` | 出错时 `free(buf)` **但未 `return`** | Double-free / UAF | `run.sh 6` |
| 7 | AFC-5 | `afc.c` | u64→u32 对 `entire`/`this` 长度的截断 | 堆溢出(截断项) | `run.sh 7` |
| 8 | PLS-1 | `property_list_service.c` | 对端的 `pktlen` → `malloc(pktlen)` 无上限 | 内存 DoS | `run.sh 8` / `plsb` |
| 9 | Ostrace | `ostrace.c` | 对端的 `rlen` → `malloc(rlen)` 无上限 | 内存 DoS | `run.sh 9` / `ostraceb` |
| 10 | RP-1 | `reverse_proxy.c` | `hostlen` (buf[2]) 被忽略;`strdup(&buf[3])` | 错误的主机解析 / 设备驱动的连接 | `run.sh 10` |
| 11 | DBG-1 | `debugserver.c` | 响应循环不断 realloc 直到收到 `#`;但永不出现 | 内存增长 DoS / 泄漏 | `run.sh 11` |
| 12 | WI | `webinspector.c` | `realloc` 未检查 → 泄漏 + NULL `memcpy` | 泄漏 / NULL 解引用崩溃 | `run.sh 12` / `wif` |
| 13 | Bug #12 | `afc.c` | `memcpy(handle, data, 8)` 仅由 `bytes > 0` 保护 | 堆**信息泄漏**(旧 chunk) | `run.sh 13` |
额外演示:`plsb`(PLS-1 有界 RSS 飙升),`ostraceb`(Ostrace 大 rlen 分配探测 —— RSS 保持平稳,参见 Ostrace 的注意事项),`wif`(WI 无界 realloc 增长)。
## AFC 家族(`poc/peer.py` + `poc/victim.c`)
共享接收管道:公开 API(`afc_read_directory`,
`afc_get_device_info`, …) → `afc_receive_data()` → `make_strings_list()` /
`make_dictionary()` / `afc_get_device_info_key()`。
对端控制的标头(`src/afc.h`):`magic[8] "CFA6LPAA"`, `entire_length`,
`this_length`, `packet_num`, `operation` —— 均为 u64。
### Bug #2 / AFC-5 — 堆溢出:`this_len > entire_len`
**位置:** `src/afc.c:308-314`
```
entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); // allocation size
this_len = (uint32_t)header.this_length - sizeof(AFCPacket); // recv size
buf = (char*)malloc(entire_len);
if (this_len > 0) { err = ...service_receive(client->parent, buf, this_len, &recv_len); }
```
**根本原因。** 仅 `header.this_length < sizeof(AFCPacket)` 会被拒绝
(第 293 行)。没有 `this_len <= entire_len` 检查,没有
`entire_length >= sizeof(AFCPacket)` 检查,并且 u64 字段被静默
窄化转换为 `uint32_t`。`service_receive` (`src/service.c:177`) →
`idevice_connection_receive_timeout` (`src/idevice.c:749`) 执行单次
最多 `size` 字节的 `recv`,因此对端使得宿主机**将 `this_len`
字节写入 `entire_len` 字节的缓冲区**。
**触发(对端):** 对于任何列表操作(`READ_DIR`/`GET_DEVINFO`/`GET_FILE_INFO`)
回复 `operation = DATA`, `entire_length = 40 + 0x18`, `this_length = 40 +
0x200` → 宿主机执行 `malloc(24)` 然后 `service_receive(buf, 512)`,接着
`make_strings_list(data, 512)` 从 24 字节的 chunk 中
越界读取 512 字节(Bug #1 链式反应)。
**影响。** 在任何使用 AFC API 的进程中发生堆**写入溢出** → glibc abort
(`malloc(): corrupted top size`, exit 134) 或 SEGV (139);通过堆排布,这可以成为
代码执行原语。该溢出还将 `*bytes_recv` 输入到
`make_strings_list` 中,从而引发 Bug #1 的 OOB 读取。
**预期输出:** `victim exit=134` / `malloc(): corrupted top size`, 或
`exit=139`。
### Bug #1 — `make_strings_list` 无界 `strdup`(放大器)
**位置:** `src/afc.c:434-451`
```
nulls = count_nullspaces(tokens, length); // bounded by length (OK)
list = malloc(sizeof(char*) * (nulls + 1));
for (i = 0; i < nulls; i++) {
list[i] = strdup(tokens + j); // walks to '\0', ignores length
j += strlen(list[i]) + 1;
}
```
**根本原因。** `count_nullspaces` 是有界的,但 token 拷贝是无界的。
`strdup`/`strlen` 仅在遇到 NUL 字节时停止。
**诚实声明(已验证)。** 在传入真实的 `length` 下独立运行,它**不会**
发生 OOB 读取:每个 `strdup` 都会在缓冲区内已被 `count_nullspaces`
计数的 NUL 处终止。只有当
`length` 是一个谎言时 —— 比如接在 Bug #2 之后,或在其他堆破坏之后 —— 它才会变成真正的 OOB **读取**。这依然是一个设计缺陷(对比位于 `src/afc.c:453-495` 使用了 `strnlen` 的安全版本 `make_dictionary`),这也是为什么 Bug #2 会引发干净的崩溃,并可能将相邻堆内存的信息泄漏到返回的字符串中。
**影响。** OOB 读取 / 堆信息泄漏;Bug #2 的放大器。无独立运行
模式;`./poc/run.sh 1` 将运行 Bug #2 链式反应。
### Bug #3 — `afc_receive_data` 中未检查 `malloc`(对照组)
**位置:** `src/afc.c:311-314`
**发现(已更正)。** 缺失的 `if (!buf)` 检查确实存在,但
文档中记录的“接收路径中的 NULL 写入”影响对于此
代码库是**错误**的:`service_receive_with_timeout` 拒绝 NULL 目标
(`src/service.c:161` → `SERVICE_E_INVALID_ARG`) 并且 `recv_len` 保持为 0,因此
`recv_len <= 0` 分支 (`src/afc.c:319`) 会进行清理(`free(NULL)`)并返回
错误。强制巨大的 `entire_len`(下溢)会导致 `malloc` 失败并退化为
优雅的 API 错误。
**影响。** 无可见影响。作为对照组保留:
`./poc/run.sh 3` 应显示受害端*没有*崩溃(仅 API 错误)。
### Bug #4 — `make_strings_list` 中未检查 malloc/strdup (DoS)
**位置:** `src/afc.c:443-446`
```
list = (char**)malloc(sizeof(char*) * (nulls + 1)); // unchecked
for (i = 0; i < nulls; i++) {
list[i] = strdup(tokens + j); // unchecked
j += strlen(list[i]) + 1; // strlen(NULL) if strdup failed
}
```
**根本原因。** NUL 填充的正文使得 `nulls` 等于正文大小 → 列表
分配空间为 `8 * nulls`(64 位下)。`malloc`(→ 对 NULL 执行 `list[i]`)
或 `strdup`(→ `strlen(NULL)`)失败会使宿主机崩溃。两种失败模式都
依赖于 OOM 的发生。
**触发(对端):** 回复 `DATA`,带有全 NUL 的大正文(`--nulflood`,
默认 `0x10000000` → 64 位下 2 GB 的列表分配)。
**影响。** 内存压力下的拒绝服务。与
`practical-test/REPORT_TRIGGERS.md` 的记录一致,该记录在内存充足的主机上将其记录为“存活”。
### Bug #5 / AFC-6 — 不成对的键 → `strdup(NULL)`
**位置:** `src/afc.c:640-645`
```
for (ptr = kvps; *ptr; ptr++) {
if (!strcmp(*ptr, key)) {
*value = strdup(*(ptr+1)); // no check that a value follows
break;
}
}
```
**根本原因。** 设备信息是一个以 NUL 分隔的扁平键/值列表,被转换为
一个带有 NULL 哨兵的 `char**`。**奇数**列表(单独的键)会使得匹配键的 `ptr+1` 指向 NULL 哨兵 → `strdup(NULL)` → `strlen(NULL)`
→ SIGSEGV。
**触发(对端):** 回复 `GET_DEVINFO`,正文仅为 `ModelNumber\0`;
受害端调用 `afc_get_device_info_key(client, "ModelNumber", &value)`。
**影响。** 可靠的 NULL 解引用 / 崩溃 (DoS)。在发生之前的 Bug #2 堆
破坏的情况下,该哨兵可能会受到攻击者的影响 → 通过 `strdup` 实现任意读取。
**预期输出:** `victim exit=139` (SIGSEGV)。
### AFC-4 — 接收错误路径上的 double-free
**位置:** `src/afc.c:314-328`
```
err = ...service_receive(client->parent, buf, this_len, &recv_len);
if (err != AFC_E_SUCCESS) {
free(buf); // 1st free
debug_info(...);
}
if (recv_len <= 0) { // recv_len was NEVER updated on error
free(buf); // 2nd free -> double free
...
}
```
**根本原因。** 在 `service_receive` 失败时,代码释放了 `buf`,但**没有** `return`。
`service_receive_with_timeout` 出错时将 `recv_len` 留在 0
(它仅在成功时写入 `*received`),因此 `recv_len <= 0` 分支
被执行并再次释放。
**触发(对端):** 发送一个有效的 `OP_DATA` 回复标头,然后重置
连接(`SO_LINGER=0`)而不是发送正文。正文 `recv` 失败并返回
`ECONNRESET`,`recv_len` 保持为 0 → 重复释放。
**影响。** 宿主机进程中的 double-free / UAF → glibc abort
(`free(): double free detected in tcache 2`, exit 134在 ASAN 下会发生可靠的
崩溃。
**预期输出:** `victim exit=134` 且带有 `free(): double free detected`。
### AFC-5 — u64→u32 截断溢出
**位置:** `src/afc.c:308-309`(与 Bug #2 同行,不同入口)
**根本原因。** 64 位标头字段在使用前被强制转换为 `uint32_t`。
对端设置超过 4 GiB 的长度在 u64 下本应是无害的,但发生了静默回绕:
`entire_length = 0x1_0000_0030 → (u32) 0x30`, `this_length = 0x1_0000_0100 →
(u32) 0x100`。宿主机随后执行 `malloc(8)` 和 `recv(216)` —— 这是一种
*纯粹通过截断*引发的溢出。
**触发(对端):** 回复 `DATA`,带有 `entire_length = 0x1_0000_0030`,
`this_length = 0x1_0000_0100`,216 字节正文;受害端运行 `afc_read_directory`。
**影响。** 同属 Bug #2 类别:堆元数据破坏 / 崩溃。它是
共享的“AFC 接收长度验证”问题的 AFC-5 变体。
**预期输出:** `victim exit=134/139`(损坏的 top size / SEGV)。
### Bug #12 — 从短缓冲区进行的 8 字节 `memcpy`(handle 泄漏)
**位置:** `src/afc.c:868-872` (`afc_file_open`) 和 `src/afc.c:1099-1103`
(`afc_file_tell`)
```
if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) {
memcpy(handle, data, sizeof(uint64_t)); // only checks bytes > 0
```
**根本原因。** `bytes`(对端可控的 `current_count`)的检查条件为 `> 0`,
而不是 `>= sizeof(uint64_t)`。1-7 字节的响应会使得 `memcpy` 从
只接收了 `bytes` 字节的缓冲区中读取 8 字节。
**实际泄漏的内容(已验证)。** 在 64 位 glibc 下,`malloc(1)` 具有 24 字节的
可用区域,因此 8 字节的读取仍停留在 chunk 内部,并复制了接收数据之后的**陈旧堆内容**
—— 通常是当该 chunk 位于空闲链表上时的陈旧 tcache `next`
的低位字节。这不是活动标头,也不是
`main_arena`。在 ASAN 或其他分配器下,这是真正的 OOB 读取。
泄漏是可以观察到的,因为被污染的 handle 会被 `afc_file_read`
(`readinfo->handle`, `src/afc.c:906`) 回显。注意 `handle == 0` 会被拒绝
(`src/afc.c:896`),因此对端必须至少返回 1 个非零字节。
**触发(对端):** 回复 `FILE_OPEN`,`FILE_OPEN_RES` 为 1-7 字节;
受害端运行 `afc_file_open → afc_file_read → afc_file_close`。对端打印
`RECV handle=0x…` 和 `OOB_bytes_in_handle=…`。
**影响。** 堆**信息泄漏**(陈旧 chunk / 先前的空闲链表字节)被反射
回对端 —— 有助于在后续的 Bug #2 漏洞利用中绕过 ASLR;但
其本身不会导致崩溃。
## 服务家族(`poc/services_peer.py` + `poc/services_victim.c`)
独立的服务,相同的威胁模型(对端通过同一通道控制帧结构)。
### PLS-1 — 无上限的 plist 包长度
**位置:** `src/property_list_service.c:210-216`
```
pktlen = be32toh(pktlen);
content = (char*)malloc(pktlen);
if (!content) { ... return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR; }
```
**根本原因。** 对端的 4 字节大端序 `pktlen` 被直接用作
`malloc` 大小,**没有上限**。检查了 `malloc`,因此这是内存
耗尽,而不是溢出。可从 lockdown、restore、instproxy 和
所有由 plist 封装的服务访问(`property_list_service_receive_plist_with_timeout`,
`include/libimobiledevice/property_list_service.h:119`)。
**触发(对端):** 发送 `pktlen = 0xFFFFFFFF` 然后 RST
(`run.sh 8`, malloc 探测),或者发送 `pktlen = --size` 并流传
数据负载(`run.sh plsb`,接收时 RSS 飙升 + 占用已分配的内存)。
**影响。** 宿主机内存耗尽 / DoS。在启用了 overcommit 的内核上,4 GiB 的
分配会成功,并且客户端在阻塞时会一直持有它;`plsb` 直接
展示了 RSS 的增长(受害端会打印 `peak_rss`)。
### Ostrace — 无上限的 `rlen` → `malloc(rlen)`
**位置:** `src/ostrace.c:157-168`(以及位于约 243 行的工作循环)
```
if (msgtype == 1) rlen = be32toh(rlen);
else if (msgtype == 2) rlen = le32toh(rlen);
char* buf = (char*)malloc(rlen); // uncapped
res = ostrace_error(service_receive(client->parent, buf, rlen, &received));
```
**根本原因。** 对端可控的 `rlen`(msgtype 1 为大端序,2 为小端序)被
直接用作分配大小;没有上限,且 `malloc` 未被检查(NULL 稍后会被 `service_receive` 拒绝)。公开可达路径:`ostrace_get_pid_list` →
`ostrace_receive_plist`。
**触发(对端):** 读取 `PidList` 请求,然后回复 `msgtype=1`,
`rlen = 0xFFFFFFFF` + RST (`run.sh 9`), 或者 `rlen = --size` 并流传
(`run.sh ostraceb`, 分配探测)。
**影响。** 内存 DoS,与 PLS-1 同类。诚实声明(已验证):不同于
property_list_service(它会循环直到收到 `pktlen` 字节并使
缓冲区驻留),`ostrace_receive_plist` 执行**单次** `recv(rlen)`
(`src/ostrace.c:168`),因此巨大的 `rlen` 仅会产生瞬时的虚拟
分配 —— 驻留 RSS 保持平稳(没有 plsb 那样的飙升)。此 DoS 指的是
无上限的分配本身(在 overcommit 下巨大的 `malloc`;否则为 NULL + 优雅的
`SERVICE_E_INVALID_ARG`)。
### RP-1 — reverse-proxy Connect 主机解析
**位置:** `src/reverse_proxy.c:160-182`
```
if (bytes < 3) { ... return 0; }
if (buf[0] == 0 && buf[1] == 3) {
uint16_t *p = (uint16_t *)&buf[bytes - 2];
port = be16toh(*p);
buf[bytes - 2] = '\0';
host = strdup(&buf[3]); // hostlen (buf[2]) is NEVER validated
}
...
int sockfd = socket_connect(host, port); // device-driven TCP connect
```
**根本原因。** Connect 二进制布局为 `0 3 `。
仅要求 `bytes >= 3`;`buf[2]` (hostlen) 被**忽略**,因此 `host` 是
索引 3 和强制 NUL 之间的所有字节 —— 不受限的内容
成为了传递给 `socket_connect` 的主机名。畸形/乱码的长度 →
奇怪的主机解析 → 宿主机打开一个到攻击者选择的主机:端口的 TCP 连接
(从恶意对端的角度看类似于 SSRF)。
**触发(对端):** 完成 v2 握手(Ctrl `BeginCtrl` ↔ `ConnPort`,
然后 Conn `HelloConn` ↔ `{Command: HelloConn}`),发送 `cmd=0x105`,接着发送带有 `hostlen=3` 但具有 9 字节主机 `"127.0.0.1"` 以及连接端口的 Connect 负载。宿主机记录 `Connect request to 127.0.0.1:` 并连接
回对端(对端打印 `conn2: host connected back`)。
**影响。** 宿主机向攻击者选择的端点发起由设备驱动的
出站 TCP 连接;被错误解析的主机字节最终进入 DNS/connect 调用。
属于逻辑缺陷,而不是内存破坏(`strdup` 受到 1 MiB 缓冲区内注入的 NUL 限制)。
### DBG-1 — 无限响应增长
**位置:** `src/debugserver.c:450-471`
```
while ((checksum_length > 0)) {
res = debugserver_client_receive_internal_char(client, &data); // 1 byte
if (data == '#') receiving_checksum_response = 1;
if (buffer_size + 1 >= buffer_capacity) {
char* newbuffer = realloc(buffer, buffer_capacity+1024);
if (!newbuffer) { return DEBUGSERVER_E_UNKNOWN_ERROR; } // leak: buffer not freed
buffer = newbuffer; buffer_capacity += 1024;
}
buffer[buffer_size] = data; buffer_size += sizeof(char);
}
```
**根本原因。** 校验和循环不断增长 `buffer`,直到 `#` + 2 个校验和
字符到达。从不发送 `#` 的对端会强制不受限制的 `realloc(+1024)` 增长;
在 `realloc` 失败时,函数返回而未释放 `buffer`(泄漏)。
公开入口:`debugserver_client_receive_response`
(`include/libimobiledevice/debugserver.h:167`)。
**触发(对端):** 发送 ACK `+`, 前缀 `$`,然后大量泛洪数据字节**且没有 `#`**
(`run.sh 11`)。受害端的逐字符接收循环不断重新分配;RSS
持续增长,直到对端停止 / 进程退出。
**影响。** 内存增长型 DoS;错误路径泄漏。ASAN 复现记录在
realloc 路径中报出 `allocation-size-too-big`。
### WI — 未检查的 `realloc` + `memcpy`
**位置:** `src/webinspector.c:221-230`
```
if (!packet) {
packet = (char*)malloc(length * sizeof(char));
} else {
newpacket = (char*)realloc(packet, (packet_length + length) * sizeof(char));
packet = newpacket; // NULL not checked
}
memcpy(packet + packet_length, buffer, length); // NULL -> SIGSEGV
```
**根本原因。** 通过 `realloc` 重新组装部分消息;其结果被
赋值给 `packet` 时未检查 NULL。在分配失败时,旧
指针丢失(泄漏)并且 `memcpy` 解引用了 NULL(崩溃)。公开入口:
`webinspector_receive_with_timeout`
(`include/libimobiledevice/webinspector.h:131`)。
**触发(对端):**
- 正常路径 (`run.sh 12`):一个 `WIRPartialMessageKey` 数据块 + 一个
包含有效二进制 plist 的 `WIRFinalMessageKey` 数据块 → 客户端重新组装并
打印 plist(测试一次 realloc 路径)。
- 增长演示 (`run.sh wif`):大量部分数据块,没有终结块 → `packet` 无限
增长(内存 DoS;触发崩溃需要强制 `realloc` 失败,例如在 ASAN 的大小限制下)。
**影响。** OOM 下的堆泄漏;当 `realloc` 失败时发生可靠的 NULL-`memcpy` 崩溃;伴随无休止的部分流造成无限制的内存增长。
## 运行矩阵
| run.sh | 对端模式 | 受害端模式 | 预期宿主机行为 |
|--------|-----------|-------------|-------------------------|
| `1` | bug2 | dir | 崩溃(通过 Bug #2 链触发 Bug #1) |
| `2` | bug2 | dir | 崩溃:`corrupted top size` / SEGV |
| `3` | bug3 | dir | 优雅的 API 错误(对照组) |
| `4` | bug4 | dir | 依赖 OOM(可能会存活) |
| `5` | bug5 | key | SIGSEGV (exit 139) |
| `6` | afc4 | dfree | abort: `free(): double free detected` |
| `7` | afc5 | trunc | 崩溃:`corrupted top size` / SEGV |
| `8` | pls | pls | `UNKNOWN_ERROR` / 超时(无界 pktlen 探测) |
| `plsb` | plsb | pls | `peak_rss` 增长至 pktlen 大小(接收时保持缓冲区) |
| `9` | ostrace | ostrace | `UNKNOWN_ERROR` / 超时(无界 rlen 探测) |
| `ostraceb` | ostraceb | ostrace | 仅分配探测;RSS 保持平稳(单次 recv 设计) |
| `10` | rp | rp | `rp log: Connect request to 127.0.0.1:` + 连接回传 |
| `11` | dbg | dbg | RSS 增长;接收永不完成 |
| `12` | wi | wi | `got plist: …` (已重组) |
| `wif` | wif | wi | RSS 增长;接收超时 |
| `13` | leak | open-read | 对端:`RECV handle=0x…` + `OOB_bytes_in_handle=…` |
针对运行较慢的机器,可以调高 `TIMEOUT`(默认为 25 秒):
`TIMEOUT=60 ./poc/run.sh plsb`。
## 给维护者报告的备注
- 所有引用的代码在当前上游的 `master` 中均未更改 —— 这些不是
此检出版本的伪影。
- 修复方向:
1. `afc_receive_data`:要求 `sizeof(AFCPacket) <= this_length <=
entire_length`,在 `uint32_t` 强制转换前以 64 位验证所有大小,
限制最大数据包,检查 `malloc`,并且接收量永远不要超过分配量。
2. `afc_receive_data` 错误路径:在 `free(buf)` 之后立即 `return err`(并
设置 `buf = NULL`)。
3. `make_strings_list`:使用 `strnlen`/有界遍历进行解析,如
`make_dictionary` 那样;检查 `malloc``strdup`。
4. `afc_get_device_info_key`:要求 `*(ptr+1) != NULL` / 偶数列表长度。
5. `afc_file_open`/`afc_file_tell`:要求 `bytes >= sizeof(uint64_t)`。
6. `property_list_service` / `ostrace`:在 `malloc` 前限制 `pktlen` / `rlen`。
7. `reverse_proxy`:验证 `buf[2]` (hostlen) —— 要求
`bytes >= 3 + hostlen + 2`;使用带有 `hostlen` 的 `strndup`。
8. `debugserver`:限制最大响应大小;在 realloc 失败时释放 `buffer`;
如果 `#` 永不出现则触发超时。
9. `webinspector`:检查 `realloc`/`malloc`;失败时释放 + 返回;限制总
`packet_length`。
- 为每个服务添加响应模糊测试器(变异的长度、奇数 K/V 列表、短
handle 响应、无休止的部分流);ASAN 能够立即捕获 #2/#1/#5/AFC-4/#12。
标签:Cutter, libimobiledevice, Maven, PoC, XXE攻击, 云资产清单, 暴力破解, 漏洞分析, 漏洞验证, 路径探测, 逆向工具, 逆向工程