Evil Parcel Schwachstellenanalyse

Einführung


Mitte April veröffentlichten wir Nachrichten über den Trojaner Android.InfectionAds.1 , der mehrere kritische Sicherheitslücken in Android ausnutzte. Mit CVE-2017-13156 (auch als Janus bekannt ) kann Malware APK-Dateien infizieren, ohne die digitale Signatur zu beschädigen. Der andere ist CVE-2017-13315. Es gibt dem Trojaner erweiterte Berechtigungen, sodass er Anwendungen unabhängig vom Benutzer installieren und deinstallieren kann. Eine detaillierte Analyse von Android.InfectionAds.1 finden Sie in unserer Virenbibliothek . Während wir hier sind, werden wir die Sicherheitsanfälligkeit CVE-2017-13315 ansprechen und sehen, was sie bewirkt.

CVE-2017-13315 gehört zur Gruppe der Sicherheitslücken, die als EvilParcel bezeichnet werden. Sie sind in verschiedenen Android-Systemklassen zu finden. Fehler in diesen Klassen ermöglichen es, Informationen während des Datenaustauschs zwischen Apps und dem System zu ersetzen. Malware, die die EvilParcel-Schwachstellen ausnutzt, erhält daher höhere Berechtigungen und kann Folgendes:

  • Installieren und Entfernen von Anwendungen mit Berechtigungen ohne Bestätigung durch Benutzer;
  • Infizieren von auf dem Gerät installierter Software und Ersetzen sauberer Originale durch infizierte Kopien, wenn diese zusammen mit anderen Schwachstellen verwendet werden;
  • Zurücksetzen der Sperrbildschirm-PIN auf Android-Geräten.

Derzeit sind uns 7 Sicherheitslücken dieses Typs bekannt:
  • CVE-2017-0806 (Fehler in der GateKeeperResponse-Klasse), veröffentlicht im Oktober 2017;
  • CVE-2017-13286 (Fehler in der OutputConfiguration-Klasse, veröffentlicht im April 2018;
  • CVE-2017-13287 (Fehler in der VerifyCredentialResponse-Klasse), veröffentlicht im April 2018;
  • CVE-2017-13288 (Fehler in der PeriodicAdvertizingReport-Klasse), veröffentlicht im April 2018;
  • CVE-2017-13289 (Fehler in der ParcelableRttResults-Klasse), veröffentlicht im April 2018;
  • CVE-2017-13311 (Fehler in der SparseMappingTable-Klasse), veröffentlicht im Mai 2018;
  • CVE-2017-13315 (Fehler in der DcParamObject-Klasse), veröffentlicht im Mai 2018.

Alle stellen eine Bedrohung für Geräte dar, auf denen Android 5.0 - 8.1 ausgeführt wird, ohne dass ein Sicherheitsupdate für Mai 2018 (oder höher) installiert ist.

Voraussetzungen für EvilParcel-Schwachstellen


Mal sehen, wie EvilParcel-Schwachstellen auftreten können. Zunächst müssen wir uns einige Funktionen der Android-Anwendungen ansehen. Alle Android-Programme interagieren miteinander und mit dem Betriebssystem, indem sie Intent-Objekte senden und empfangen. Diese Objekte können eine beliebige Anzahl von Schlüssel-Wert-Paaren innerhalb eines Bundle-Objekts enthalten.

Beim Übertragen einer Absicht wird ein Bundle-Objekt in ein in Parcel eingeschlossenes Byte-Array konvertiert (serialisiert) und nach dem Lesen von Schlüsseln und Werten aus einem serialisierten Bundle automatisch deserialisiert.

Im Bundle ist der Schlüssel die Zeichenfolge, und der Wert kann fast alles sein. Beispielsweise kann es sich um einen primitiven Typ, eine Zeichenfolge oder einen Container mit primitiven Typen oder Zeichenfolgen handeln. Es kann auch ein Paketobjekt sein.

Somit kann das Bundle ein Objekt eines beliebigen Typs enthalten, der die Parcelable-Schnittstelle implementiert. Dazu müssen wir die Methoden writeToParcel () und createFromParcel () implementieren, um das Objekt zu serialisieren und zu deserialisieren.

Um unseren Standpunkt zu veranschaulichen, erstellen wir ein einfaches serialisiertes Bundle. Wir werden einen Code schreiben, der drei Schlüssel-Wert-Paare in das Bundle einfügt und es serialisiert:


Abbildung 1. Struktur eines serialisierten Bündelobjekts

Beachten Sie die Besonderheiten der Bundle-Serialisierung:

  • Alle Schlüssel-Wert-Paare werden nacheinander geschrieben.
  • Der Wertetyp wird vor jedem Wert angegeben (13 für das Bytearray, 1 für die Ganzzahl, 0 für die Zeichenfolge usw.).
  • Datengröße variabler Länge wird vor den Daten angegeben (Länge für die Zeichenfolge, Anzahl der Bytes für das Array);
  • Alle Werte sind 4 Byte ausgerichtet.


Alle Schlüssel und Werte werden nacheinander in das Bundle geschrieben, sodass beim Zugriff auf einen Schlüssel oder Wert eines serialisierten Bundle-Objekts dieses vollständig deserialisiert und auch alle enthaltenen Parcelable-Objekte initialisiert werden.

Also, was könnte das Problem sein? Das Problem ist, dass einige Systemklassen, die Parcelable implementieren, möglicherweise Fehler in den Methoden createFromParcel () und writeToParcel () enthalten. In diesen Klassen unterscheidet sich die Anzahl der in createFromParcel () gelesenen Bytes von der Anzahl der in writeToParcel () geschriebenen Bytes. Wenn Sie ein Objekt dieser Klasse in einem Bundle platzieren, ändern sich die Objektgrenzen innerhalb des Bundles nach der erneuten Initialisierung. Dies schafft die Voraussetzungen für die Ausnutzung einer EvilParcel-Sicherheitsanfälligkeit.

Sehen wir uns ein Beispiel für eine Klasse an, die diesen Fehler enthält:

class Demo implements Parcelable { byte[] data; public Demo() { this.data = new byte[0]; } protected Demo(Parcel in) { int length = in.readInt(); data = new byte[length]; if (length > 0) { in.readByteArray(data); } } public static final Creator<Demo> CREATOR = new Creator<Demo>() { @Override public Demo createFromParcel(Parcel in) { return new Demo(in); } }; @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(data.length); parcel.writeByteArray(data); } } 

Wenn die Datenarraygröße 0 ist, wird beim Erstellen eines Objekts ein int (4 Byte) in createFromParcel () gelesen und zwei int (8 Byte) in writeToParcel () geschrieben. Das erste int wird durch expliziten Aufruf von writeInt geschrieben. Das zweite int wird beim Aufruf von writeByteArray () geschrieben, da die Arraylänge immer vor dem Array in Parcel geschrieben wird (siehe Abbildung 1).

Situationen, in denen die Größe des Datenarrays gleich 0 ist, sind ziemlich selten. Aber selbst wenn dies passiert, läuft das Programm weiter, wenn Sie jeweils nur ein serialisiertes Objekt übertragen (in unserem Beispiel das Demo-Objekt). Daher bleiben solche Fehler in der Regel unbemerkt.

Jetzt versuchen wir, ein Demo-Objekt mit einer Array-Länge von Null im Bundle zu platzieren:


Abbildung 2. Das Ergebnis des Hinzufügens eines Demo-Objekts mit der Länge Null zum Bundle

Wir serialisieren das Objekt:


Abbildung 3. Das Bundle-Objekt nach der Serialisierung

Versuchen wir nun, es zu deserialisieren:


Abbildung 4. Das Bundle-Objekt nach der Deserialisierung

Was bekommen wir? Schauen wir uns das Paketfragment an:


Abbildung 5. Paketstruktur nach Bundle-Deserialisierung

In den Abbildungen 4 und 5 sehen wir, dass während der Deserialisierung anstelle von zwei int ein int in der createFromParcel-Methode gelesen wurde. Daher wurden alle nachfolgenden Werte aus dem Bundle falsch gelesen. Der 0x0-Wert bei 0x60 wurde als Länge des nächsten Schlüssels gelesen. Der 0x1-Wert bei 0x64 wurde als Schlüssel gelesen. Der 0x31-Wert bei 0x68 wurde als Werttyp gelesen. Paket hat keine Werte vom Typ 0x31, daher meldet readFromParcel () sorgfältig eine Ausnahme.

Wie kann dies im wirklichen Leben genutzt werden und zu einer Verwundbarkeit werden? Mal sehen! Der obige Fehler in den Parcelable-Systemklassen ermöglicht die Erstellung von Bundles, die sich während der ersten und wiederholten Deserialisierung unterscheiden können. Um dies zu demonstrieren, ändern wir das vorherige Beispiel:

 Parcel data = Parcel.obtain(); data.writeInt(3); // 3 entries data.writeString("vuln_class"); data.writeInt(4); // value is Parcelable data.writeString("com.drweb.testbundlemismatch.Demo"); data.writeInt(0); // data.length data.writeInt(1); // key length -> key value data.writeInt(6); // key value -> value is long data.writeInt(0xD); // value is bytearray -> low(long) data.writeInt(-1); // bytearray length dummy -> high(long) int startPos = data.dataPosition(); data.writeString("hidden"); // bytearray data -> hidden key data.writeInt(0); // value is string data.writeString("Hi there"); // hidden value int endPos = data.dataPosition(); int triggerLen = endPos - startPos; data.setDataPosition(startPos - 4); data.writeInt(triggerLen); // overwrite dummy value with the real value data.setDataPosition(endPos); data.writeString("A padding"); data.writeInt(0); // value is string data.writeString("to match pair count"); int length = data.dataSize(); Parcel bndl = Parcel.obtain(); bndl.writeInt(length); bndl.writeInt(0x4C444E42); // bundle magic bndl.appendFrom(data, 0, length); bndl.setDataPosition(0); 

Dieser Code erstellt ein serialisiertes Bundle, das eine anfällige Klasse enthält. Nun wollen wir sehen, was wir nach der Ausführung dieses Codes erhalten:


Abbildung 6. Erstellen eines Bundles mit einer anfälligen Klasse

Nach der ersten Deserialisierung enthält dieses Bundle die folgenden Schlüssel:


Abbildung 7. Nach der Deserialisierung eines Bundles mit einer anfälligen Klasse

Jetzt werden wir das Bundle erneut serialisieren, dann erneut deserialisieren und uns die Liste der Schlüssel ansehen:


Abbildung 8. Ergebnis der Reserialisierung und Deserialisierung eines Bundles mit einer anfälligen Klasse

Was sehen wir? Das Bundle enthält jetzt den versteckten Schlüssel (mit dem Zeichenfolgenwert "Hi there!"), Der vorher nicht vorhanden war. Schauen wir uns das Paketfragment dieses Bundles an, um herauszufinden, warum dies passiert ist:


Abbildung 9. Paketstruktur eines Bundle-Objekts mit einer anfälligen Klasse nach zwei Serialisierungs- und Deserialisierungszyklen

Hier können wir den ganzen Punkt der EvilParcel-Schwachstellen erkennen. Wir können speziell ein Bundle erstellen, das eine anfällige Klasse enthält. Durch Ändern der Grenzen dieser Klasse können beliebige Objekte in diesem Bundle platziert werden. Zum Beispiel eine Absicht, die erst nach der zweiten Deserialisierung im Bundle erscheint. Dies hilft, eine Absicht vor den Sicherheitsmechanismen des Betriebssystems zu verbergen.

EvilParcel ausnutzen


Android.InfectionAds.1 nutzte CVE-2017-13315, um Software unabhängig von Gerätebesitzern zu installieren und zu entfernen. Aber wie?

Im Jahr 2013 wurde der Fehler 7699048 , auch als Launch AnyWhere bekannt, entdeckt. Es ermöglichte Anwendungen von Drittanbietern, beliebige Aktivitäten für einen privilegierteren Systembenutzer zu starten. In der folgenden Abbildung finden Sie den Aktionsmechanismus:


Abbildung 10. Bedienung des Fehlers 7699048

Eine ausnutzende Anwendung kann diese Sicherheitsanfälligkeit verwenden, um den Kontoauthentifizierungsdienst zu implementieren, mit dem dem Betriebssystem neue Konten hinzugefügt werden sollen. Der Fehler 7699048 hilft den Exploit-Startaktivitäten beim Installieren, Entfernen, Ersetzen von Anwendungen sowie beim Zurücksetzen der PIN oder der Mustersperre und verursacht viel mehr Probleme.

Google Inc. hat diesen Verstoß beseitigt, indem der Start willkürlicher Aktivitäten von AccountManager verboten wurde. Jetzt ermöglicht AccountManager nur das Starten von Aktivitäten, die von derselben Anwendung stammen. Zu diesem Zweck wird die digitale Signatur der Software, die die Aktivität initiiert hat, überprüft und mit der Signatur der Anwendung abgeglichen, in der sich die Aktivität befindet. Es sieht so aus:

 if (result != null && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) { /* * The Authenticator API allows third party authenticators to * supply arbitrary intents to other apps that they can run, * this can be very bad when those apps are in the system like * the System Settings. */ int authenticatorUid = Binder.getCallingUid(); long bid = Binder.clearCallingIdentity(); try { PackageManager pm = mContext.getPackageManager(); ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId); int targetUid = resolveInfo.activityInfo.applicationInfo.uid; if (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authenticatorUid, targetUid)) { throw new SecurityException( "Activity to be started with KEY_INTENT must " + "share Authenticator's signatures"); } } finally { Binder.restoreCallingIdentity(bid); } } 

Es scheint, dass das Problem gelöst wurde, aber es ist nicht so einfach. Es stellte sich heraus, dass die bekannte Sicherheitsanfälligkeit EvilParcel CVE-2017-13315 eine Problemumgehung bietet! Wie wir bereits wissen, überprüft das System nach dem Reparieren von Launch AnyWhere die digitale Signatur der Anwendung. Wenn es erfolgreich überprüft wurde, wird das Bundle an IAccountManagerResponse.onResult () übertragen. Gleichzeitig wird onResult () über den IPC-Mechanismus aufgerufen, sodass das Bundle erneut serialisiert wird. Während der Implementierung von onResult () geschieht Folgendes:

 /** Handles the responses from the AccountManager */ private class Response extends IAccountManagerResponse.Stub { public void onResult(Bundle bundle) { Intent intent = bundle.getParcelable(KEY_INTENT); if (intent != null && mActivity != null) { // since the user provided an Activity we will silently start intents // that we see mActivity.startActivity(intent); // leave the Future running to wait for the real response to this request } //<.....> } //<.....> } 

Anschließend extrahiert das Bundle den Intent-Schlüssel und die Aktivität wird ohne Überprüfung gestartet.
Um eine beliebige Aktivität mit Systemberechtigungen zu starten, müssen Sie lediglich ein Bundle mit dem Feld Intent erstellen, das bei der ersten Deserialisierung ausgeblendet wird und während der wiederholten Deserialisierung angezeigt wird.
Wie wir bereits wissen, können EvilParcel-Schwachstellen diese Aufgabe tatsächlich ausführen.

Im Moment wurden alle bekannten Schwachstellen dieses Typs innerhalb der anfälligen Parcelable-Klassen behoben. In Zukunft werden jedoch möglicherweise neue anfällige Klassen angezeigt. Die Bundle-Implementierung und der Mechanismus zum Hinzufügen neuer Konten sind weiterhin dieselben wie zuvor. Sie ermöglichen es uns weiterhin, genau diesen Exploit zu erstellen, wenn wir alte oder neue anfällige Paketklassen erkennen. Darüber hinaus werden diese Klassen immer noch manuell implementiert, und der Programmierer muss sicherstellen, dass die Länge des serialisierten Parcelable-Objekts gleich bleibt, was bei allem, was dies impliziert, ein menschlicher Faktor ist. Wir hoffen jedoch, dass es so wenige Fehler wie möglich gibt und die EvilParcel-Schwachstellen keine Bedrohung für Android-Benutzer darstellen.

Sie können Ihr Mobilgerät mithilfe unseres Dr.Web Security Space für Android auf EvilParcel-Schwachstellen überprüfen. Der integrierte Sicherheitsprüfer meldet die erkannten Probleme und empfiehlt Möglichkeiten, sie zu beheben.

Source: https://habr.com/ru/post/de457610/


All Articles