
kfd, short for kernel file descriptor, is a project to read and write kernel memory on Apple devices.
简要免责声明:我无意添加对其他设备和 iOS 版本的偏移量。
kfd,即 kernel file descriptor(内核文件描述符)的缩写,是一个在 Apple 设备上读写内核内存的项目。它利用各种可利用的漏洞来获取悬空 PTE(页表项),这被称为 PUAF 原语,即 physical use-after-free(物理释放后使用)的缩写。然后,它会在这些物理页内重新分配某些内核对象,并通过悬空 PTE 从用户空间直接操纵它们,以实现 KRKW 原语,即 kernel read/write(内核读写)的缩写。漏洞利用代码完全包含在一个库 libkfd 中,但该项目还包含针对 iOS 和 macOS 的简单可执行包装器。libkfd 的公共 API 非常小巧且直观:
enum puaf_method {
puaf_physpuppet,
puaf_smith,
puaf_landa,
};
enum kread_method {
kread_kqueue_workloop_ctl,
kread_sem_open,
};
enum kwrite_method {
kwrite_dup,
kwrite_sem_open,
};
u64 kopen(u64 puaf_pages, u64 puaf_method, u64 kread_method, u64 kwrite_method);
void kread(u64 kfd, u64 kaddr, void* uaddr, u64 size);
void kwrite(u64 kfd, void* uaddr, u64 kaddr, u64 size);
void kclose(u64 kfd);
kopen() 在概念上打开一个"内核文件描述符"。它接受以下 4 个参数:
puaf_pages:具有悬空 PTE 的目标物理页数量。puaf_method:用于获取 PUAF 原语的方法,具有以下选项:
puaf_physpuppet:
puaf_smith:
puaf_landa:
kread_method:用于获取初始 kread() 原语的方法。kwrite_method:用于获取初始 kwrite() 原语的方法。如果漏洞利用成功,kopen() 会返回一个 64 位不透明文件描述符。实际上,这只是一个指向 libkfd 所需结构的用户空间指针。但是,由于该结构不应在库外部访问,因此它以不透明整数的形式返回。如果漏洞利用失败,该库将打印一条错误消息,睡眠 30 秒,然后以状态码 1 退出。它会睡眠 30 秒,因为对于某些需要在 KRKW 之后进行清理的 PUAF 方法(例如 puaf_smith),内核可能会在退出时触发 panic(崩溃)。
kread() 和 kwrite() 分别是用户空间中与 copyout() 和 copyin() 等价的操作。请注意,kread_method 和 kwrite_method 的选项在单独的文章中进行了描述。此外,这些方法提供的初始原语可用于引导出更强大的 KRKW 原语。最后,kclose() 只是关闭内核文件描述符。它们都将 kopen() 返回的不透明整数作为第一个参数。
在 Xcode 中,打开项目的根文件夹并连接你的 iOS 设备。
在终端中,导航到项目的根文件夹。
(可选)要提高全局和每进程的文件描述符限制(这将提高成功率,尤其是在连续多次运行时),请输入命令 make s 并输入 sudo 密码。
make b。make r。make br。本 README 对 kfd 项目进行了总体概述。一旦实现了 PUAF 原语,漏洞利用的其余部分就是通用的。因此,我将漏洞利用的公共部分集中到一篇专门的文章中:
此外,我将用于实现 PUAF 原语的漏洞利用中特定于漏洞的部分拆分到了不同的文章中,以下按发现的先后顺序列出:
但是,请注意,这些文章是为已经熟悉 XNU 虚拟内存系统的读者编写的。