深入探索Fuchsia OS:Zircon微内核漏洞利用与Rootkit植入实战

本文详细记录了作者对Google开发的Fuchsia OS及其Zircon微内核的安全研究,包括系统构建、内核调试、KASAN使用、漏洞利用开发,以及通过堆喷和vtable篡改实现控制流劫持,最终成功植入内核Rootkit的全过程。

内核黑客邂逅Fuchsia OS

Fuchsia是由Google开发的通用开源操作系统,基于C++编写的Zircon微内核,目前正处于积极开发阶段。开发者称Fuchsia专注于安全性、可更新性和性能。作为Linux内核黑客,我决定从攻击者的角度审视Fuchsia OS。本文记录了我的实验过程。

摘要

  • 首先概述Fuchsia操作系统及其安全架构。
  • 展示如何从源代码构建Fuchsia并创建运行其上的简单应用。
  • 深入Zircon微内核:描述Zircon内核开发工作流,展示使用GDB和QEMU进行调试的方法。
  • Zircon微内核漏洞利用开发实验:
    • 模糊测试尝试
    • 利用C++对象的内存破坏
    • 内核控制流劫持
    • 向Fuchsia OS植入Rootkit
  • 最后进行漏洞利用演示。

本研究过程中发现的Fuchsia安全问题已遵循负责任披露流程处理。

什么是Fuchsia OS

Fuchsia是通用开源操作系统。Google大约在2016年开始开发此OS,2020年12月向公众贡献者开放,2021年5月正式在Nest Hub设备上发布Fuchsia。该系统支持arm64和x86-64架构,目前处于活跃开发状态,因此我决定对其进行安全实验。

Fuchsia设计面向连接设备生态系统(IoT、智能手机、PC),因此开发者特别关注安全性和可更新性,形成了独特的安全架构:

  1. 无用户概念,基于能力:内核资源以对象形式暴露给应用,需要相应能力才能交互。软件应获得最小必要能力,本地权限提升(LPE)概念与GNU/Linux系统不同。
  2. 基于微内核:大量功能从Zircon微内核移至用户空间,减小了内核攻击面。Zircon实现的服务较单体内核少,但系统调用超过170个,远超典型微内核。
  3. 沙箱隔离:应用和系统服务以组件形式运行在独立沙箱中,进程间通信(IPC)需显式声明。无全局文件系统,各组件使用自己的本地命名空间。
  4. 软件交付与更新机制:组件通过URL标识,可按需解析、下载和执行,旨在使软件包像网页一样保持最新。

这些安全特性使Fuchsia OS成为有趣的研究目标。

初尝试

Fuchsia文档提供了详细的入门教程。通过以下命令构建x86_64开发工具的工作站产品:

1
2
3
$ fx clean
$ fx set workstation.x64 --with-base //bundles:tools
$ fx build

构建完成后,可通过FEMU(基于QEMU的Fuchsia模拟器)启动系统。

创建新组件

Fuchsia应用称为组件。创建C++组件模板:

1
$ fx create component --path src/a13x-pwns-fuchsia --lang cpp

组件清单需配置stdout日志转发。构建并测试新组件后,可见组件通过URL解析、下载并执行。

Zircon内核开发工作流

Zircon C++源代码是Fuchsia源码的一部分,位于zircon/kernel子目录。调试需在QEMU中运行,但非英语控制台区域设置会导致错误。应用补丁后,可通过GDB调试Zircon微内核。

调试时发现Zircon GDB脚本因处理大符号文件(110MB)而卡住,移除-readnow参数后修复。

接近Fuchsia安全:启用KASAN

KASAN(内核地址消毒剂)用于检测内存错误。编译支持KASAN的Zircon内核:

1
2
$ fx set core.x64 --with-base //bundles:tools --with-base //src/a13x-pwns-fuchsia --variant=kasan
$ fx build

为测试KASAN,在TimerDispatcher代码中注入合成漏洞:当计时器截止值以31337结尾时,无论引用计数如何都释放对象。用户空间组件触发此漏洞后,KASAN成功检测到Use-After-Free错误并生成详细报告。

Fuchsia的Syzkaller(已失效)

尝试使用Syzkaller进行模糊测试时,由于Fuchsia不寻常的软件交付机制,无法构建包含syz-executor组件的镜像。Syzkaller集成自2020年后已失效,向相关开发者报告后未获回复。

研究策略思考

缺乏模糊测试时,内核漏洞发现需要深入代码库知识和攻击面理解。鉴于首次研究投入资源不合理且Fuchsia生产就绪度低于预期,决定推迟零日漏洞搜索,转而利用合成漏洞开发PoC利用。

发现Zircon堆喷利用原语

利用策略是通过堆喷覆盖已释放的TimerDispatcher对象。选择Zircon FIFO作为堆喷原语,因其满足:非特权组件可用、分配内核对象、从用户空间复制数据。

通过zx_fifo_create()创建多个FifoDispatcher对象,数据缓冲区大小与TimerDispatcher相同(248字节)。填充堆喷数据后,成功覆盖目标对象。

C++对象解剖

Zircon C++对象布局复杂。通过实验发现,对象开头存储vtable指针,控制流劫持比Linux内核更简单。

Zircon KASLR绕过

控制流劫持需知内核符号地址。尝试通过内核日志读取指针时,发现zx_debuglog_create()存在权限检查缺陷,允许非特权组件读取内核日志。报告后获CVE-2022-0882。

进一步发现尽管启用KASLR,内核指针在每次启动时均相同,KASLR实际未生效。已报告此已知问题。

Zircon中的C++ vtable

vtable指针位于对象开头。通过GDB查看TimerDispatcher vtable,发现非内核地址的奇怪值。汇编代码显示vtable使用32位值偏移计算实际方法地址。

伪造vtable获胜

尽管vtable指针运算怪异,仍决定伪造vtable实现控制流劫持。为简化实验,在QEMU中禁用SMAP/SMEP,在用户空间创建假vtable。通过调整堆喷数据,使vtable指针指向伪造表,计算偏移后成功跳转至攻击函数。

Fuchsia中攻击什么?

获得内核任意代码执行后,考虑攻击目标。尝试伪造ZX_RSRC_KIND_ROOT资源未果。意识到作为微内核,权限提升需攻击IPC通信,决定改为向Zircon植入Rootkit。

Fuchsia系统调用

Zircon系统调用通过syscall表处理,x86_64架构下使用x86_syscall()函数。查表发现系统调用表位于0xffffffff003c49f8,共176个项。

向Zircon植入Rootkit

首次实验覆盖整个syscall表为0x41。通过修改CR0的WP位禁用写保护。随后考虑如何劫持系统调用:无法像Linux那样通过内核模块实现,决定覆盖内核函数assert_fail_msg()作为钩子代码区域。

zx_process_create()编写rootkit钩子,使用汇编保存寄存器、调用内核printf()、恢复寄存器后跳转至原系统调用。利用pwn()函数将钩子代码复制到内核的assert_fail_msg()地址,并修改syscall表相应项。

同时为zx_process_exit()添加类似钩子。Rootkit成功植入后,会在进程创建和退出时向内核日志打印消息。

漏洞利用演示

实现进程创建和退出时的rootkit钩子,成功在内核日志中输出定制消息。

结论

本次研究涵盖了Fuchsia OS及其Zircon微内核的多个方面,包括系统构建、内核调试、漏洞利用开发和rootkit植入。作为早期公开的Fuchsia安全研究之一,希望为操作系统安全社区提供微内核漏洞利用与防御的实用见解,激发更多内核黑客兴趣。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计