Abuser des pipelines médias Android & des parseurs d’images
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Delivery: Messaging Apps ➜ MediaStore ➜ Privileged Parsers
Les builds OEM modernes exécutent régulièrement des indexeurs média privilégiés qui rescannent MediaStore pour des fonctionnalités d’IA ou de partage. Sur les firmwares Samsung antérieurs au patch d’avril 2025, com.samsung.ipservice charge Quram (/system/lib64/libimagecodec.quram.so) et analyse automatiquement tout fichier que WhatsApp (ou d’autres apps) place dans MediaStore. En pratique, un attaquant peut envoyer un DNG déguisé en IMG-*.jpg, attendre que la victime appuie sur “download” (1-clic), et le service privilégié analysera le payload même si l’utilisateur n’ouvre jamais la galerie.
$ 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], ...
Points clés
- La livraison dépend de la réanalyse média du système (pas du client de chat) et hérite donc des permissions de ce processus (accès complet lecture/écriture à la galerie, capacité à déposer de nouveaux médias, etc.).
- Tout parseur d’images accessible via
MediaStore(vision widgets, fonds d’écran, fonctionnalités AI résumé, etc.) devient accessible à distance si l’attaquant parvient à convaincre la cible d’enregistrer un média.
Bugs de l’interpréteur d’opcodes DNG de Quram
Les fichiers DNG intègrent trois listes d’opcodes appliquées à différents stades de décodage. Quram recopie l’API d’Adobe, mais son gestionnaire Stage-3 pour DeltaPerColumn (opcode ID 11) fait confiance aux limites de plans fournies par l’attaquant.
Bornes de plan non valides dans DeltaPerColumn
- Les attaquants définissent
plane=5125etplanes=5123alors que les images Stage-3 n’exposent que les plans 0–2 (RGB). - Quram calcule
opcode_last_plane = image_planes + opcode_planesau lieu deplane + count, et ne vérifie jamais si la plage de plans résultante tient dans l’image. - La boucle écrit donc un delta dans
raw_pixel_buffer[plane_index]avec un offset entièrement contrôlé (par ex. plane 5125 ⇒ offset5125 * 2 bytes/pixel = 0x2800). Chaque opcode ajoute une valeur float 16-bit (0x6666) à l’emplacement ciblé, fournissant une primitive précise d’addition OOB sur le heap.
Transformer des incréments en écritures arbitraires
- L’exploit corrompt d’abord
QuramDngImage.bottom/rightde Stage-3 en utilisant 480 opérationsDeltaPerColumnmalformées pour que les opcodes suivants traitent des coordonnées énormes comme étant in-bounds. - Des opcodes
MapTable(opcode 7) sont ensuite dirigés vers ces limites falsifiées. En utilisant une table de substitution composée de zéros complets ou unDeltaPerColumnavec des deltas-Inf, l’attaquant met à zéro n’importe quelle région, puis applique des deltas supplémentaires pour écrire des valeurs exactes. - Parce que les paramètres d’opcode résident dans les métadonnées DNG, le payload peut encoder des centaines de milliers d’écritures sans toucher directement la mémoire du processus.
Modelage du heap sous Scudo
Scudo regroupe les allocations par taille. Quram alloue par hasard les objets suivants avec des chunks de 0x30 bytes identiques, ils atterrissent donc dans la même région (espacement de 0x40 bytes sur le heap) :
QuramDngImagedescriptors for Stage 1/2/3QuramDngOpcodeTrimBoundsand vendorUnknownopcodes (ID ≥14, including ID 23)
L’exploit orchestre les allocations pour placer les chunks de façon déterministe :
- Les opcodes Stage-1
Unknown(23)(20 000 entrées) pulvérisent des chunks 0x30 qui seront plus tard freed. - Stage-2 libère ces opcodes et place un nouveau
QuramDngImagedans la région libérée. - 240 entrées Stage-2
Unknown(23)sont freed, et Stage-3 alloue immédiatement sonQuramDngImageplus un nouveau raw pixel buffer de la même taille, réutilisant ces emplacements. - Un
TrimBoundsconstruit s’exécute en premier dans la liste 3 et alloue encore un raw pixel buffer avant de free l’état Stage-2, garantissant l’adjacence “raw pixel buffer ➜ QuramDngImage”. - 640 entrées supplémentaires
TrimBoundssont marquéesminVersion=1.4.0.1de sorte que le dispatcher les ignore, mais leurs objets sous-jacents restent alloués et deviennent plus tard des cibles primitives.
Cette chorégraphie place le buffer brut de Stage-3 immédiatement avant le QuramDngImage de Stage-3, de sorte que l’overflow basé sur les plans inverse des champs à l’intérieur du descripteur au lieu de crasher un état aléatoire.
Réutilisation des opcodes vendor “Unknown” comme blobs de données
Samsung laisse le bit de poids fort activé dans les IDs d’opcodes vendor-specific (par ex. ID 23), ce qui ordonne à l’interpréteur d’allouer la structure mais d’en sauter l’exécution. L’exploit abuse de ces objets dormants comme heaps contrôlés par l’attaquant :
- Les entrées
Unknown(23)des listes d’opcodes 1 et 2 servent de scratchpads contigus pour stocker des octets de payload (chaîne JOP à offset 0xf000 et une commande shell à 0x10000 relative au raw buffer). - Parce que l’interpréteur traite toujours chaque objet comme un opcode lorsqu’il parcourt la liste 3, s’emparer du vtable d’un objet suffit ensuite pour commencer à exécuter des données contrôlées.
Création d’objets MapTable falsifiés & contournement de l’ASLR
Les objets MapTable sont plus grands que TrimBounds, mais une fois la corruption de layout appliquée, le parser lit volontiers des paramètres supplémentaires hors-bounds :
- Utiliser la primitive d’écriture linéaire pour écraser partiellement un pointeur de vtable de
TrimBoundspar une table de substitutionMapTableforgée qui mappe les 2 octets bas depuis le vtableTrimBoundsvoisin vers le vtableMapTable. Seuls les octets bas diffèrent entre les builds Quram supportés, donc une seule table de lookup 64K peut couvrir sept versions de firmware et chaque slide ASLR de 4 KB. - Patch le reste des champs
TrimBounds(top/left/width/planes) pour que l’objet se comporte comme unMapTablevalide quand il sera exécuté. - Exécuter l’opcode falsifié sur une mémoire mise à zéro. Parce que le pointeur de table de substitution référence en réalité le vtable d’un autre opcode, les octets de sortie deviennent des adresses bas-ordre leaked depuis
libimagecodec.quram.soou son GOT. - Appliquer des passes
MapTablesupplémentaires pour convertir ces fuites de 2 octets en offsets vers des gadgets tels que__ink_jpeg_enc_process_image+64,QURAMWINK_Read_IO2+124,qpng_check_IHDR+624, et l’entrée__system_property_getde libc. Les attaquants reconstruisent ainsi des adresses complètes à l’intérieur de leur région d’opcode pulvérisée sans API de disclosure native.
Déclencher la transition JOP ➜ system()
Une fois les pointeurs de gadgets et la commande shell placés dans le spray d’opcodes :
- Une dernière vague d’écritures
DeltaPerColumnajoute0x0100à l’offset 0x22 duQuramDngImagede Stage-3, décalant son pointeur de raw buffer de 0x10000 pour qu’il référence désormais la chaîne de commande de l’attaquant. - L’interpréteur commence à exécuter la queue de 1040 opcodes
Unknown(23). La première entrée corrompue a son vtable remplacé par la table forgée à l’offset 0xf000, si bien queQuramDngOpcode::aboutToApplyrésoutqpng_read_data(la 4ème entrée) à partir du fake table. - Les gadgets chaînés effectuent : charger le pointeur
QuramDngImage, ajouter 0x20 pour pointer sur le pointeur du raw buffer, le déréférencer, copier le résultat dansx19/x0, puis sauter via des slots GOT réécrits verssystem. Comme le pointeur du raw buffer vaut désormais la chaîne de l’attaquant, le gadget final exécutesystem(<shell command>)à l’intérieur decom.samsung.ipservice.
Remarques sur les variantes d’allocateur
Deux familles de payload existent : une ajustée pour jemalloc, l’autre pour scudo. Elles diffèrent dans l’ordre des blocs d’opcodes pour obtenir l’adjacence mais partagent les mêmes primitives logiques (bug DeltaPerColumn ➜ MapTable zero/write ➜ vtable falsifié ➜ JOP). La quarantine désactivée de Scudo rend la réutilisation de freelist 0x30-byte déterministe, tandis que jemalloc s’appuie sur le contrôle de classes de taille via le tile/subIFD sizing.
Références
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks

