Abuso de pipelines de medios y analizadores de imágenes en Android
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Delivery: Messaging Apps ➜ MediaStore ➜ Privileged Parsers
Las builds OEM modernas suelen ejecutar indexadores de medios privilegiados que vuelven a escanear MediaStore para funciones de “AI” o de compartición. En el firmware de Samsung anterior al parche de abril de 2025, com.samsung.ipservice carga Quram (/system/lib64/libimagecodec.quram.so) y analiza automáticamente cualquier archivo que WhatsApp (u otras apps) deje en MediaStore. En la práctica, un atacante puede enviar un DNG disfrazado como IMG-*.jpg, esperar a que la víctima toque “descargar” (1-click), y el servicio privilegiado analizará la carga útil incluso si el usuario nunca abre la galería.
$ 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], ...
Conclusiones clave
- La entrega depende del re-procesado del sistema de medios (no del cliente de chat) y por tanto hereda los permisos de ese proceso (acceso completo de lectura/escritura a la galería, capacidad de agregar nuevos medios, etc.).
- Cualquier parser de imágenes accesible a través de
MediaStore(vision widgets, wallpapers, funciones de resumen de IA, etc.) se vuelve accesible remotamente si el atacante convence a la víctima de guardar medios.
Quram’s DNG Opcode Interpreter Bugs
Los archivos DNG incrustan tres listas de opcodes aplicadas en diferentes etapas de decodificación. Quram copia la API de Adobe, pero su manejador de Stage-3 para DeltaPerColumn (opcode ID 11) confía en los límites de plano suministrados por el atacante.
Límites de plano inválidos en DeltaPerColumn
- Los atacantes establecen
plane=5125yplanes=5123aunque las imágenes Stage-3 solo exponen planos 0–2 (RGB). - Quram calcula
opcode_last_plane = image_planes + opcode_planesen vez deplane + count, y nunca comprueba si el rango de planos resultante encaja dentro de la imagen. - Por tanto el bucle escribe un delta en
raw_pixel_buffer[plane_index]con un desplazamiento completamente controlado (p. ej., plane 5125 ⇒ offset5125 * 2 bytes/pixel = 0x2800). Cada opcode suma un valor float de 16 bits (0x6666) a la ubicación objetivo, produciendo una primitiva precisa de suma OOB en el heap.
Convertir incrementos en escrituras arbitrarias
- El exploit primero corrompe
QuramDngImage.bottom/rightde Stage-3 usando 480 operacionesDeltaPerColumnmalformadas para que opcodes posteriores traten coordenadas enormes como válidas. MapTableopcodes (opcode 7) se dirigen luego a esos límites falsos. Usando una tabla de sustitución de ceros o unDeltaPerColumncon deltas-Inf, el atacante pone a cero cualquier región y después aplica deltas adicionales para escribir valores exactos.- Porque los parámetros de los opcodes viven dentro de los metadatos DNG, el payload puede codificar cientos de miles de escrituras sin tocar directamente la memoria del proceso.
Heap Shaping Under Scudo
Scudo agrupa las allocations por tamaño. Quram asigna los siguientes objetos con tamaños de chunk idénticos de 0x30 bytes, por lo que caen en la misma región (espaciado de 0x40 bytes en el heap):
QuramDngImagedescriptors for Stage 1/2/3QuramDngOpcodeTrimBoundsand vendorUnknownopcodes (ID ≥14, including ID 23)
El exploit encadena las asignaciones para colocar los chunks de forma determinista:
- Los
Unknown(23)opcodes de Stage-1 (20,000 entradas) rocían chunks de 0x30 que luego se liberan. - Stage-2 libera esos opcodes y coloca un nuevo
QuramDngImagedentro de la región liberada. - Se liberan 240 entradas
Unknown(23)de Stage-2, y Stage-3 asigna inmediatamente suQuramDngImagemás un nuevo raw pixel buffer del mismo tamaño, reutilizando esos espacios. - Un
TrimBoundsconfeccionado se ejecuta primero en la lista 3 y asigna otro raw pixel buffer antes de liberar el estado de Stage-2, garantizando la adyacencia “raw pixel buffer ➜ QuramDngImage”. - 640 entradas adicionales
TrimBoundsestán marcadasminVersion=1.4.0.1para que el dispatcher las salte, pero sus objetos subyacentes permanecen asignados y más tarde se convierten en objetivos primitivos.
Esta coreografía coloca el raw buffer de Stage-3 inmediatamente antes del QuramDngImage de Stage-3, de modo que el overflow basado en planos modifica campos dentro del descriptor en lugar de provocar fallos en estados aleatorios.
Reusing Vendor “Unknown” Opcodes as Data Blobs
Samsung mantiene el bit alto activado en los IDs de opcode específicos del vendor (p. ej., ID 23), lo que instruye al intérprete para allocate la estructura pero omitir la ejecución. El exploit abusa de esos objetos dormidos como heaps controlados por el atacante:
- Las entradas
Unknown(23)de las listas de opcode 1 y 2 sirven como pads contiguos para almacenar bytes del payload (JOP chain en offset 0xf000 y un comando shell en 0x10000 relativo al raw buffer). - Porque el intérprete todavía trata cada objeto como un opcode cuando se procesa la lista 3, tomar el control del vtable de un objeto después es suficiente para empezar a ejecutar los datos del atacante.
Crafting Bogus MapTable Objects & Bypassing ASLR
Los objetos MapTable son más grandes que TrimBounds, pero una vez que llega la corrupción de layout, el parser lee con gusto parámetros extra fuera de límites:
- Usar la primitiva de escritura lineal para sobrescribir parcialmente un puntero vtable de
TrimBoundscon una tabla de sustituciónMapTablecreada que mapea los 2 bytes bajos de un vtableTrimBoundsvecino al vtable deMapTable. Solo los bytes bajos difieren entre builds de Quram soportados, así que una sola tabla de búsqueda de 64K puede manejar siete versiones de firmware y cada desplazamiento de ASLR de 4 KB. - Parchear el resto de campos de
TrimBounds(top/left/width/planes) para que el objeto se comporte como unMapTableválido cuando se ejecute más tarde. - Ejecutar el opcode falso sobre memoria puesta a cero. Como el puntero a la tabla de sustitución en realidad referencia el vtable de otro opcode, los bytes de salida se convierten en direcciones de orden bajo leaked de
libimagecodec.quram.soo su GOT. - Aplicar pases adicionales de
MapTablepara convertir esos leaks de dos bytes en offsets hacia gadgets como__ink_jpeg_enc_process_image+64,QURAMWINK_Read_IO2+124,qpng_check_IHDR+624y la entrada__system_property_getde libc. Los atacantes efectivamente reconstruyen direcciones completas dentro de su región de opcodes rociada sin APIs nativas de divulgación de memoria.
Triggering the JOP ➜ system() Transition
Una última oleada de escrituras DeltaPerColumn suma 0x0100 al offset 0x22 del QuramDngImage de Stage-3, desplazando su puntero de raw buffer en 0x10000 para que ahora haga referencia a la cadena de comando del atacante.
- El intérprete comienza a ejecutar la cola de 1040 opcodes
Unknown(23). La primera entrada corrompida tiene su vtable reemplazado con la tabla forjada en offset 0xf000, así queQuramDngOpcode::aboutToApplyresuelveqpng_read_data(la 4ª entrada) desde la tabla falsa. - Los gadgets encadenados realizan: cargar el puntero
QuramDngImage, sumar 0x20 para apuntar al puntero del raw buffer, desreferenciarlo, copiar el resultado enx19/x0, y luego saltar a través de slots GOT reescritos asystem. Como el puntero del raw buffer ahora equivale a la cadena del atacante, el gadget final ejecutasystem(<shell command>)dentro decom.samsung.ipservice.
Notes on Allocator Variants
Existen dos familias de payloads: una ajustada para jemalloc y otra para Scudo. Difieren en cómo se ordenan los bloques de opcode para lograr adyacencia, pero comparten las mismas primitivas lógicas (DeltaPerColumn bug ➜ MapTable zero/write ➜ bogus vtable ➜ JOP). La cuarentena deshabilitada de Scudo hace que la reutilización de freelist de 0x30 bytes sea determinista, mientras que jemalloc se basa en el control de clase de tamaño mediante el dimensionado de tile/subIFD.
Referencias
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks

