Missbrauch von Android Media-Pipelines & Image-Parsern
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Zustellung: Messaging-Apps ➜ MediaStore ➜ Privilegierte Parser
Moderne OEM-Builds führen regelmäßig privilegierte Media-Indexer aus, die MediaStore für “AI” oder Sharing-Funktionen erneut scannen. Auf Samsung-Firmware vor dem Patch vom April 2025 lädt com.samsung.ipservice Quram (/system/lib64/libimagecodec.quram.so) und parst automatisch jede Datei, die WhatsApp (oder andere Apps) in den MediaStore ablegt. In der Praxis kann ein Angreifer eine DNG senden, die als IMG-*.jpg getarnt ist, darauf warten, dass das Opfer auf “download” tippt (1-Klick), und der privilegierte Dienst parst die Nutzlast, selbst wenn das Opfer die Galerie nie öffnet.
$ file IMG-2025-02-10.jpeg
TIFF image data ...
$ exiftool IMG-2025-02-10.jpeg | grep "Opcode List"
Opcode List 1 : [opcode 23], [opcode 23], ...
Kernaussagen
- Die Zustellung beruht auf dem erneuten Parsen durch das System-Media-Subsystem (nicht durch den Chat-Client) und erbt damit dessen Berechtigungen (voller Lese-/Schreibzugriff auf die Galerie, Möglichkeit, neue Medien abzulegen usw.).
- Jeder Image-Parser, der über
MediaStoreerreichbar ist (vision widgets, wallpapers, AI résumé features usw.), wird remote zugänglich, wenn ein Angreifer ein Ziel dazu bringt, Medien zu speichern.
0-click DD+/EAC-3 decoding path (Google Messages ➜ mediacodec sandbox)
Moderne Messaging-Stacks dekodieren außerdem automatisch audio für Transkription/Suche. Auf dem Pixel 9 übergibt Google Messages eingehendes RCS/SMS-Audio an den Dolby Unified Decoder (UDC) in /vendor/lib64/libcodec2_soft_ddpdec.so bevor der Benutzer die Nachricht öffnet, wodurch die 0-click-Angriffsfläche auf Media-Codecs ausgeweitet wird.
Wesentliche Parse-Einschränkungen
- Jeder DD+ syncframe hat bis zu 6 Blocks; jeder Block kann bis zu
0x1FFBytes angreifer-kontrollierte skip data in einen Skip-Buffer kopieren (≈0x1FF * 6Bytes pro Frame). - Der Skip-Buffer wird auf EMDF gescannt:
syncword (0xX8)+emdf_container_length(16b) + variable-length fields.emdf_payload_sizewird mit einer unbeschränktenvariable_bits(8)-Schleife geparst. - EMDF-Payload-Bytes werden in einem per-Frame benutzerdefinierten “evo heap” bump-Allocator alloziert und dann byteweise aus einem Bit-Reader kopiert, der durch
emdf_container_lengthbegrenzt ist.
Integer-overflow → heap-overflow primitive (CVE-2025-54957)
ddp_udc_int_evo_mallocrichtetalloc_size+extraauf 8 Bytes aus viatotal_size += (8 - total_size) % total_sizeohne Wrap-Detection. Werte nahe0xFFFFFFFFFFFFFFF9..FFschrumpfen auf AArch64 zu einem winzigentotal_size.- Die Kopierschleife verwendet weiterhin die logische
payload_lengthausemdf_payload_size, sodass Angreifer-Bytes evo-heap-Daten über das zu kleine Chunk hinaus überschreiben. - Die Overflow-Länge wird präzise durch den Angreifer wählbaren
emdf_container_lengthbegrenzt; die Overflow-Bytes sind angreifer-kontrollierte EMDF-Payload-Daten. Der Slab-Allocator wird jedes Syncframe zurückgesetzt, was vorhersehbare Nachbarschaften erlaubt.
Sekundäres Lese-Primitive
Wenn emdf_container_length > skipl, liest die EMDF-Parsing-Logik über initialisierte Skip-Bytes hinaus (OOB read). Alleinstehend leaked das nur Nullen/bekannte Mediendaten, aber nach der Korruption angrenzender Heap-Metadaten kann es die korrumpierte Region zurücklesen, um den Exploit zu validieren.
Ausnutzungsablauf
- EMDF so konstruieren, dass
emdf_payload_sizegroß ist (viavariable_bits(8)), sodass die Allocator-Padding-Operation wrappt und ein kleines Chunk entsteht. emdf_container_lengthauf die gewünschte Overflow-Länge setzen (≤ insgesamt verfügbares Skip-Data-Budget); Overflow-Bytes in der EMDF-Payload platzieren.- Den per-Frame evo heap so formen, dass die kleine Allokation vor Zielstrukturen im statischen Decoder-Buffer (≈693 KB) oder im dynamischen Buffer (≈86 KB), der pro Decoder-Instanz einmalig alloziert wird, liegt.
- Optional
emdf_container_length > skiplwählen, um nach der Korruption überschriebenen Daten aus dem Skip-Buffer zurückzulesen.
Quram’s DNG Opcode Interpreter Bugs
DNG-Dateien betten drei Opcode-Listen ein, die in verschiedenen Dekodierstufen angewendet werden. Quram kopiert Adobes API, aber sein Stage-3-Handler für DeltaPerColumn (opcode ID 11) vertraut angreifer-gesendeten plane-Bounds.
Fehlende Prüfungen der Plane-Bounds in DeltaPerColumn
- Angreifer setzen
plane=5125undplanes=5123, obwohl Stage-3-Bilder nur Plane 0–2 (RGB) exposen. - Quram berechnet
opcode_last_plane = image_planes + opcode_planesanstelle vonplane + countund prüft nie, ob der resultierende Plane-Bereich innerhalb des Bildes liegt. - Die Schleife schreibt daher ein Delta in
raw_pixel_buffer[plane_index]mit einem vollständig kontrollierten Offset (z.B. plane 5125 ⇒ Offset5125 * 2 bytes/pixel = 0x2800). Jeder Opcode addiert einen 16-Bit-Float-Wert (0x6666) an die Zielposition und liefert so ein präzises Heap-OOB-Add-Primitive.
Inkremente in beliebige Writes verwandeln
- Der Exploit korrumpiert zuerst
QuramDngImage.bottom/rightin Stage-3 mittels 480 malformedDeltaPerColumn-Operationen, sodass nachfolgende Opcodes riesige Koordinaten als in-bounds betrachten. MapTable-Opcodes (opcode 7) werden dann auf diese gefälschten Bounds gerichtet. Mit einer Substitutions-Tabelle aus Nullen oder einemDeltaPerColumnmit-Inf-Deltas nullt der Angreifer beliebige Regionen und wendet danach zusätzliche Deltas an, um exakte Werte zu schreiben.- Weil die Opcode-Parameter in den DNG-Metadaten leben, kann das Payload hunderttausende Writes codieren, ohne direkt Prozessspeicher zu modifizieren.
Heap-Shaping unter Scudo
Scudo bucketed Allokationen nach Größe. Quram allokiert zufällig die folgenden Objekte mit identischen 0x30-Byte-Chunks, sodass sie in derselben Region landen (0x40-Byte-Abstand auf dem Heap):
QuramDngImage-Deskriptoren für Stage 1/2/3QuramDngOpcodeTrimBoundsund vendorUnknownopcodes (ID ≥14, einschließlich ID 23)
Der Exploit sequenziert Allokationen, um deterministisch Chunks zu platzieren:
- Stage-1
Unknown(23)-Opcodes (20.000 Einträge) sprühen 0x30-Chunks, die später freed werden. - Stage-2 freed diese Opcodes und platziert ein neues
QuramDngImagein den freigegebenen Regionen. - 240 Stage-2
Unknown(23)-Einträge werden freed, und Stage-3 allokiert sofort seinQuramDngImageplus einen neuen raw pixel buffer gleicher Größe und reused diese Plätze. - Ein konstruiertes
TrimBounds-Opcode läuft zuerst in Liste 3 und allokiert noch einen raw pixel buffer, bevor Stage-2-State freed wird, was “raw pixel buffer ➜ QuramDngImage”-Adjazenz garantiert. - Zusätzlich 640
TrimBounds-Einträge werden mitminVersion=1.4.0.1markiert, sodass der Dispatcher sie überspringt, ihre zugrundeliegenden Objekte aber alloziert bleiben und später primitive Ziele werden.
Diese Choreographie setzt den Stage-3-Raw-Buffer unmittelbar vor das Stage-3-QuramDngImage, sodass der plane-basierte Overflow Felder im Deskriptor umschreibt statt zufälligen State zum Absturz zu bringen.
Vendor-“Unknown”-Opcodes als Datenblöcke wiederverwenden
Samsung lässt das High-Bit in vendor-spezifischen Opcode-IDs gesetzt (z.B. ID 23), was den Interpreter anweist, die Struktur zu alloziieren, aber die Ausführung zu überspringen. Der Exploit missbraucht diese ruhenden Objekte als angreifer-kontrollierte Heaps:
- Opcode-Liste 1 und 2
Unknown(23)-Einträge dienen als zusammenhängende Scratchpads zum Speichern von Payload-Bytes (JOP-Chain bei Offset 0xf000 und ein Shell-Command bei 0x10000 relativ zum raw buffer). - Weil der Interpreter jedes Objekt beim Verarbeiten von Liste 3 trotzdem als Opcode behandelt, reicht es später, die vtable eines Objekts zu kapern, um damit begonnene Angreifer-Ausführung zu starten.
Konstruiere gefälschte MapTable-Objekte & ASLR umgehen
MapTable-Objekte sind größer als TrimBounds, aber sobald die Layout-Korruption ankommt, liest der Parser gern zusätzliche Parameter out-of-bounds:
- Verwende das lineare Write-Primitive, um teilweise einen
TrimBounds-vtable-Pointer mit einer gefälschtenMapTable-Substitutionstabelle zu überschreiben, die die unteren 2 Bytes von einer benachbartenTrimBounds-vtable auf dieMapTable-vtable mappt. Nur die Low-Bytes unterscheiden sich zwischen unterstützten Quram-Builds, sodass eine einzelne 64K Lookup-Tabelle sieben Firmware-Versionen und jeden 4 KB ASLR-Slide abdeckt. - Patch den Rest der
TrimBounds-Felder (top/left/width/planes), damit das Objekt später wie eine gültigeMapTablereagiert. - Führe das gefälschte Opcode über nullgesetzten Speicher aus. Weil der Substitutionstabelle-Pointer tatsächlich auf die vtable eines anderen Opcodes zeigt, werden die Output-Bytes zu leaked Low-Order-Adressen aus
libimagecodec.quram.sooder dessen GOT. - Wende zusätzliche
MapTable-Durchläufe an, um jene Zwei-Byte-Leaks in Offsets zu Gadgets wie__ink_jpeg_enc_process_image+64,QURAMWINK_Read_IO2+124,qpng_check_IHDR+624und libc’s__system_property_get-Entry zu konvertieren. Die Angreifer bauen so effektiv vollständige Adressen innerhalb ihrer gesprayten Opcode-Region wieder auf, ohne native Memory-Disclosure-APIs.
JOP ➜ system()-Übergang auslösen
Sobald Gadget-Pointer und Shell-Command im Opcode-Spray platziert sind:
- Eine finale Welle von
DeltaPerColumn-Writes addiert0x0100zu Offset 0x22 des Stage-3-QuramDngImage, verschiebt dessen raw buffer Pointer um 0x10000, sodass er nun auf den Angreifer-Command-String zeigt. - Der Interpreter beginnt, das Ende von 1040
Unknown(23)-Opcodes auszuführen. Der erste korrumpierte Eintrag hat seine vtable durch die gefälschte Tabelle bei Offset 0xf000 ersetzt, sodassQuramDngOpcode::aboutToApplyqpng_read_data(den 4. Eintrag) aus der Fake-Tabelle resolved. - Die verketteten Gadgets führen aus: lade den
QuramDngImage-Pointer, addiere 0x20, um auf den raw buffer Pointer zu zeigen, dereferenziere ihn, kopiere das Ergebnis inx19/x0, und springe dann durch GOT-Slots, die aufsystemumgeschrieben wurden. Weil der raw buffer Pointer jetzt auf den Angreifer-String zeigt, führt das finale Gadgetsystem(<shell command>)innerhalb voncom.samsung.ipserviceaus.
Hinweise zu Allocator-Varianten
Es existieren zwei Payload-Familien: eine für jemalloc abgestimmt, die andere für scudo. Sie unterscheiden sich darin, wie Opcode-Blöcke geordnet werden, um Adjazenz zu erreichen, teilen aber die gleichen logischen Primitives (DeltaPerColumn-Bug ➜ MapTable zero/write ➜ bogus vtable ➜ JOP). Scudos deaktivierte Quarantine macht die Wiederverwendung von 0x30-Byte-Freelists deterministisch, während jemalloc auf Size-Class-Kontrolle via tile/subIFD-Sizing angewiesen ist.
References
- Project Zero – A look at an Android ITW DNG exploit
- Project Zero – Pixel 0-click: CVE-2025-54957 in Dolby UDC
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


