前言
最近在倒腾 Android 逆向相关,期间了解了一个比较有意思的漏洞(CVE_2024_0044),这个漏洞可以突破 Android 12/13 系统提权备份应用数据(例如:提取微信数据,难怪最近各厂家先后突破 Android 12/13 提权备份,乐~)。正好我的手机还是 Android 13 系统,遂复现了一下,发现漏洞存在并成功利用,以及利用漏洞提取出微信聊天等数据。
详细信息
在 Android 12 和 13 上,通过 pm install
的 -i
标志设置时,新安装应用程序的“Installer package name”未经过清理。无论是 pm[1] 还是底层的 PackageInstallerService[2] 都没有检查它是否包含特殊字符,更不用说它是否引用了已安装的软件包。
尽管在写入 /data/system/packages.xml
时,安装程序包名称中的特殊字符会被无害地转义,但在写入 /data/system/packages.list
时 却没有进行转义[3] ,这会以简单的换行和空格分隔格式复制了某些软件包的元数据。通过提供带有换行符和空格的名称,具有 ADB shell 访问权限的攻击者可以将任意数量的虚假字段和条目注入到 packages.list
中。
packages.list
的一个用户是 run-as
(还有如 simpleperf_app_runner[4] ,但 run-as
是该问题造成的最大安全威胁),它允许 ADB shell 在给定应用程序的上下文中运行代码。run-as 旨在拒绝不可调试的应用程序,但它会从 packages.list
查询应用程序的可调试性(以及其 UID
、SELinux
上下文和数据目录)。通过相关注入使得保留后者但更改前者的伪造条目,攻击者可以绕过可调试性检查并成为系统上的几乎任何应用程序。
我们之所以说“几乎”,是因为 run-as
确实有一些额外的纵深防御检查,其中最值得注意的是即使 packages.list
显示它应该这样做,它也不会去假设非应用程序 UID(包括 system
用户,以及保留最高特权的应用程序),也不会假设与真实应用程序相同的 SELinux
上下文,因为它只考虑 fromRunAs=true
的 seapp_contexts[5] ,这对非特权应用程序没有影响,因为 runas_app[6] 严格来说比 untrusted_app[7] 更有特权,但它确实阻止攻击者执行针对 priv_app[8] 或 platform_app[9] 上的操作——即使是作为通常可以执行的应用程序。
问题还因为 run-as
中的另一个逻辑错误而加剧,该错误使其可以针对 privapps
。通常情况下,在 check_data_path()
中的检查会禁止这种操作,该函数试图确保:
-
应用程序数据目录的每个父级都由系统拥有。 -
数据目录本身由应用程序UID拥有。
由于 run-as
不允许对 privapp_data_file
进行 stat()
状态检查操作,上述的第 2 点检查对于具有 UID 不匹配(如果伪造应用程序具有错误的数据目录)或权限被拒绝(如果伪造应用程序的数据目录正确)的 privapp
应该失败。然而,执行每个检查的 check_directory()[10] 辅助函数包含一个针对路径 /data/user/0
的特殊情况。尽管仅允许该路径成为符号链接,但这种特殊情况也无意中跳过了 UID 的验证。因此,通过将假冒应用的数据路径设置为/data/user/0
,攻击者可以满足 run-as
的内部安全检查。一旦进入 runas_app
,他们就可以读取和写入 privapp_data_file
,因为 Android 有点令人困惑地允许任何应用程序这样做。
在具有 Google 移动服务(GMS)的 Android 设备上,攻击者通过写 /data/user_de/0/com.google.android.gms/app_chimera/m/*/oat/
中的缓存 ODEX/VDEX 文件(这些文件包含 GMS 加载的未签名可执行代码),可以在 GMS 中获得持久性(在此过程中升级到 gmscore_app
)。其中一些代码还会加载到使用 Google API 的应用程序中,也允许在这些地方保持持久性。这本身不是一个漏洞,但确实强调了在 privapp
数据目录中强制执行 W|X 的重要性。
漏洞复现
漏洞的整个利用过程也很简单,主要就 4 步,本次复现设备是个人的 Redmi K40 设备,系统版本:Xiaomi HyperOS 1.0.6.0.TKHCNXM(Android 13),本次以微信 APP 为例,复现步骤如下:
1、利用 ADB Shell 查看微信 UID:
2、推送任意一个 app 到 /data/local/tmp
目录下:
3、执行相关 POC ,这里将下述的 UID 替换为微信的 UID( victim
这个名称也是可以更改):
将上述的代码在 ADB Shell 命令框中运行,效果如下:
上述的 victim [uid] 1 /data/user/0 default:targetSdkVersion=28 none 0 0 1 @null
解释如下:
-
第三个字段,数字 1
表示该包是否可调试。 -
第四个字段, /data/user/0
是成为privapps
所需的数据路径,如上述分析所说。 -
第五个字段则用于派生 SELinux
域,并设置为适用于任何针对 Target API >= 28 的应用程序的通用值。 -
其他字段对于 run-as
来说并不重要。
4、切换为微信用户:
可见此时的 shell
已经是微信 UID
了。通过命令也可查看目标应用数据(其它应用没有权限),如图所示:
提取数据
上述操作我们成功获得目标应用权限,但是这个用户只有应用目录的权限,没法在其他目录创建文件,因此我们再借助另一个 ADB Shell 终端,先把文件创建好再写入数据,如下:
拉取数据:
后续若取消提权,只需要把操作过程中安装的 test.apk
卸载即可。
在 Android 14 中,PackageInstallerService
确保了安装程序包名称引用已安装的软件包,因此该漏洞已修复。
因文章可能二次修改,点击下方 阅读原文 即可直达个人博客阅读原文。
参考资料
pm: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java;l=3062
[2]PackageInstallerService: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java;l=643-653
[3]却没有进行转义: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:frameworks/base/services/core/java/com/android/server/pm/Settings.java;l=2805
[4]simpleperf_app_runner: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/extras/simpleperf/simpleperf_app_runner/simpleperf_app_runner.cpp;l=85
[5]seapp_contexts: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/sepolicy/private/seapp_contexts;l=177-178
[6]runas_app: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/sepolicy/private/runas_app.te
[7]untrusted_app: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/sepolicy/private/untrusted_app_all.te
[8]priv_app: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/sepolicy/private/priv_app.te
[9]platform_app: https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/sepolicy/private/platform_app.te
[10]check_directory(): https://cs.android.com/android/platform/superproject/+/android-13.0.0_r74:system/core/run-as/run-as.cpp;l=73-96
[11]Bypassing the ‘run-as’ debuggability check on Android via newline injection: https://rtx.meta.security/exploitation/2024/03/04/Android-run-as-forgery.html
[12]Extracting WhatsApp Database (or any app data) from Android 12/13 using CVE-2024-0044: https://tinyhack.com/2024/06/07/extracting-whatsapp-database-or-any-app-data-from-android-12-13-using-cve-2024-0044/?s=03
原文始发于微信公众号(小杨学安全):CVE-2024-0044,致使 Android 12/13 提权那些事