
Writeup und Exploit für CVE-2024-34740, Integer-Überlauf in Androids BinaryXmlSerializer, der zu einem Datei-Schreibvorgang in system_server und anschließend zur Codeausführung in system_server von einer normal installierten App führt.

Korrekturen für das hier beschriebene Problem erschienen unter CVE-2024-34740 / A-307288067:
Innerhalb von Android system_server speichern viele Dienste ihren Zustand über Neustarts hinweg in XML-Dateien```
$ adb shell su 0 find /data/system -name '*.xml' | sort
/data/system/appops_accesses.xml
/data/system/cachequota.xml
/data/system/device_policies.xml
/data/system/device_policy_state.xml
/data/system/display-manager-state.xml
/data/system/input-manager-state.xml
/data/system/inputmethod/subtypes.xml
/data/system/install_sessions.xml
/data/system/job/jobs_1000.xml
/data/system/job/jobs_10131.xml
/data/system/log-files.xml
/data/system/netpolicy.xml
/data/system/notification_policy.xml
/data/system/overlays.xml
/data/system/packages.xml
/data/system/package-watchdog.xml
/data/system/sensor_privacy_impl.xml
/data/system/sensor_privacy.xml
/data/system/shortcut_service.xml
/data/system/users/0/app_idle_stats.xml
/data/system/users/0/appwidgets.xml
/data/system/users/0/package-restrictions.xml
/data/system/users/0/settings_global.xml
/data/system/users/0/settings_secure.xml
/data/system/users/0/settings_system.xml
/data/system/users/0/wallpaper_info.xml
/data/system/users/0.xml
/data/system/users/userlist.xml
/data/system/watchlist_settings.xml
Historisch gesehen handelte es sich dabei um einfache Text-XML-Dateien mit Einrückung, die Entwicklern ein einfaches Lesen ermöglichten. Allerdings wurde [in Android 12 eine neue binäre Version dieses Formats eingeführt, wobei angeführt wurde, dass 1,5 % der gesamten von `system_server` aufgewendeten Zeit auf diese XML-Operationen entfallen](https://android.googlesource.com/platform/frameworks/base/+/4ccea8796991d678ead4399130ec31edf63ff4fa%5E%21/)
Es sollte beachtet werden, dass dieses Format nur intern vom System verwendet wird und Dateien mit dem Magic-Wert `"ABX\x00"` besitzt. Es unterscheidet sich vom [Format, das innerhalb von APKs verwendet wird](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/libs/androidfw/ResourceTypes.cpp;l=1770;drc=d4e49e63519397789d284a03aea5fafc119cb1b0) für `AndroidManifest.xml`, `res/xml/*.xml`, `res/layout/*.xml` usw., das keinen expliziten „Magic-Wert“ besitzt, aber normalerweise mit `0300 0800` beginnt (was ein [Header](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h;l=608;drc=d4e49e63519397789d284a03aea5fafc119cb1b0) mit `type=RES_XML_TYPE` und `headerSize=8` ist).
Immer wenn das System eine dieser internen Zustands-XML-Dateien liest, [verwendet es den Magic-Wert `"ABX\0"` in der Datei, um entweder den Parser für die Binary-XML-Datei oder den regulären XML-Parser auszuwählen](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/util/Xml.java;l=188-192;drc=97a370a95275e79c69e79d7ead11aa38934a5575). Ob diese Dateien als Binary XML gespeichert werden, wird [über eine Systemeigenschaft gesteuert](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/util/Xml.java;drc=97a370a95275e79c69e79d7ead11aa38934a5575;l=74?q=Xml.java) und ist standardmäßig aktiviert.
Wenn Binary-XML-Dateien verwendet werden, kann man ihren Inhalt beispielsweise über `adb shell su 0 abx2xml /data/system/packages.xml -` lesen.
Eine der Funktionen dieses binären Formats besteht darin, typisierte Zugriffsmethoden bereitzustellen. So bietet der Serializer die Methode `attributeInt(String namespace, String name, int value)`, die den Wert als binäre Ganzzahl schreibt und so den Umweg über String vermeidet, der eine neue Allokation und ein anschließendes Objekt für die Garbage Collection bedeuten würde.
Ein weiterer Typ, der direkt serialisiert werden kann, ist Byte-Array.```java
@Override
public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)
throws IOException {
if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64);
mOut.writeInternedUTF(name);
mOut.writeShort(value.length);
mOut.write(value);
return this;
}
Es gibt auch eine ähnliche Methode attributeBytesHex, die sich nur durch das geschriebene TYPE_*-Tag unterscheidet. Dieses Tag wird vom Tool abx2xml verwendet, um ein Byte-Array in die passende String-Darstellung zu konvertieren.
mOut ist eine Instanz von FastDataOutput, die Funktionen von Java's DataOutputStream bereitstellt. writeByte/writeShort/writeInt/writeUTF/write verwenden dasselbe Format wie das standardmäßige DataOutputStream.
Ähnlich wie bei Parcel werden bei einer Abweichung während des Schreibens/Lesens nachfolgend gelesene Daten von falschen Offsets übernommen. Im Gegensatz zu Parcel geben Fehler bei der Verwendung von BinaryXmlSerializer/BinaryXmlPullParser dem Angreifer jedoch nicht die Möglichkeit, gelesene Daten willkürlich zu manipulieren (der Angreifer kann in diesem Fall keine neuen Tag-/Attributnamen/-werte einführen).
Fehler innerhalb der BinaryXmlSerializer-Klasse selbst oder in FastDataOutput jedoch schon.
Wenn wir in der obigen Methode versuchen würden, ein Byte-Array mit der Länge 65536 zu schreiben, würden wir die Länge mit writeShort() schreiben, was effektiv 0 schreibt, wonach der eigentliche Array-Inhalt geschrieben wird.
Um diese Abweichung auszunutzen, müssen wir eine Datei wählen, in der wir ein beliebiges Byte-Array in attributeBytesBase64 oder attributeBytesHex injizieren können. Außerdem muss eine Änderung dieser Datei für den Angreifer wertvoll sein.
Die Klasse PackageInstaller bietet die Möglichkeit, ein Paket für die Installation vorzubereiten. Ohne jegliche Berechtigungen kann jede App ein neues APK schreiben, das in ein temporäres Verzeichnis installiert werden soll. Sobald alles für die Installation Notwendige geschrieben wurde, kann die installierende App commit() PackageInstaller.Session aufrufen, was bedeutet, dass sie keine weiteren Änderungen an den Installationsdateien vornehmen kann und die Session entweder für die Benutzerfreigabe oder die tatsächliche Installation bereit ist.
Der Zustand dieser Vorgänge wird in /data/system/install_sessions.xml gespeichert. Die Installer-App kann zum Beispiel die Hälfte eines großen APK in das temporäre Verzeichnis herunterladen, das vom Package Manager Service für ihre PackageInstaller.Session erstellt wurde. Nach einem Neustart kann sie den Download fortsetzen, die restliche Hälfte schreiben und die Installation committen.