Зловживання медіа-конвеєрами Android та парсерами зображень
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Доставка: додатки обміну повідомленнями ➜ MediaStore ➜ привілейовані парсери
Сучасні OEM build-и регулярно запускають привілейовані індексатори медіа, які повторно сканують MediaStore для функцій “AI” або обміну. У прошивках Samsung до патчу квітня 2025 року com.samsung.ipservice завантажує Quram (/system/lib64/libimagecodec.quram.so) і автоматично парсить будь-який файл, який WhatsApp (або інші додатки) поміщають у MediaStore. На практиці атакуючий може надіслати DNG, замаскований як IMG-*.jpg, зачекати, поки жертва натисне “download” (1-click), і привілейована служба розпарсить payload навіть якщо користувач ніколи не відкриває галерею.
$ 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], ...
Ключові висновки
- Доставка покладається на повторний парсинг системних медіа (не на чат-клієнт) і тому успадковує дозволи цього процесу (повний доступ для читання/запису до галереї, можливість додавати нові медіа тощо).
- Будь-який image parser, до якого можна дістатися через
MediaStore(vision widgets, wallpapers, AI résumé features тощо), стає віддалено доступним, якщо нападник переконає ціль зберегти медіа.
0-click DD+/EAC-3 decoding path (Google Messages ➜ mediacodec sandbox)
Сучасні messaging stacks також авто-декодують audio для транскрипції/пошуку. На Pixel 9, Google Messages передає вхідний RCS/SMS audio до Dolby Unified Decoder (UDC) у /vendor/lib64/libcodec2_soft_ddpdec.so перш ніж користувач відкриє повідомлення, розширюючи 0-click поверхню до медіа codec-ів.
Ключові обмеження парсингу
- Кожен DD+ syncframe має до 6 блоків; кожен блок може скопіювати до
0x1FFбайт керованих нападником skip data у skip buffer (≈0x1FF * 6байт на фрейм). - skip buffer сканується на EMDF:
syncword (0xX8)+emdf_container_length(16b) + поля змінної довжини.emdf_payload_sizeпарситься за допомогою необмеженого циклуvariable_bits(8). - EMDF payload bytes виділяються в кастомному per-frame “evo heap” bump-алокаторі, а потім копіюються по байту з bit-reader, обмеженого
emdf_container_length.
Integer-overflow → heap-overflow примітива (CVE-2025-54957)
ddp_udc_int_evo_mallocвирівнюєalloc_size+extraдо 8 байт черезtotal_size += (8 - total_size) % total_sizeбез перевірки wrap. Значення поблизу0xFFFFFFFFFFFFFFF9..FFстискаються до крихітногоtotal_sizeна AArch64.- Цикл копіювання все ще використовує logical
payload_lengthзemdf_payload_size, тож байти нападника перезаписують дані evo-heap поза зменшеним чанком. - Довжина переповнення точно обмежена обраним нападником
emdf_container_length; байти переповнення контролюються EMDF payload. slab-алокатор скидається кожен syncframe, що дає передбачувану суміжність.
Secondary read примітива
Якщо emdf_container_length > skipl, парсинг EMDF читає за межі ініціалізованих skip байтів (OOB read). Саме по собі це виливає нулі/відомі медіа, але після пошкодження суміжної heap-метаданих воно може прочитати назад пошкоджену ділянку для валідації експлойту.
Exploitation recipe
- Сконструювати EMDF з великим
emdf_payload_size(черезvariable_bits(8)), щоб padding алокатора обернувся у малий chunk. - Встановити
emdf_container_lengthна бажану довжину переповнення (≤ загального бюджету skip data); помістити байти переповнення в EMDF payload. - Сформувати per-frame evo heap так, щоб мала алокація опинилася перед цільовими структурами всередині статичного буфера декодера (≈693 KB) або динамічного буфера (≈86 KB), який виділяється один раз на екземпляр декодера.
- Опційно вибрати
emdf_container_length > skipl, щоб після корупції прочитати назад перезаписані дані зі skip buffer.
Quram’s DNG Opcode Interpreter Bugs
DNG файли вбудовують три списки opcode-ів, що застосовуються на різних стадіях декоду. Quram копіює Adobe API, але його Stage-3 handler для DeltaPerColumn (opcode ID 11) довіряє attacker-supplied bounds для plane.
Failing plane bounds in DeltaPerColumn
- Нападники ставлять
plane=5125іplanes=5123хоча Stage-3 зображення експонують лише planes 0–2 (RGB). - Quram обчислює
opcode_last_plane = image_planes + opcode_planesзамістьplane + count, і ніколи не перевіряє, чи поміщається отриманий діапазон plane в межі зображення. - Тому цикл записує delta в
raw_pixel_buffer[plane_index]з повністю керованим зсувом (наприклад, plane 5125 ⇒ зсув5125 * 2 bytes/pixel = 0x2800). Кожен opcode додає 16-bit float значення (0x6666) до цільової локації, даючи точну heap OOB add-примітиву.
Turning increments into arbitrary writes
- Експлойт спочатку коруптує Stage-3
QuramDngImage.bottom/rightза допомогою 480 malformedDeltaPerColumnоперацій, так що майбутні opcode-и трактують величезні координати як in-bounds. MapTableopcode-и (opcode 7) потім спрямовуються на ці фейкові bounds. Використовуючи substitution table з усіх нулів абоDeltaPerColumnз deltas-Inf, нападник знуляє будь-яку ділянку, а потім застосовує додаткові deltas для запису точних значень.- Оскільки параметри opcode-ів живуть в DNG metadata, payload може кодувати сотні тисяч записів без прямого маніпулювання пам’яттю процесу.
Heap Shaping Under Scudo
Scudo групує алокації за розміром. Quram випадково виділяє такі об’єкти з ідентичним розміром chunk 0x30, тож вони потрапляють у ту ж область (0x40-байтні інтервали в heap):
QuramDngImageдескриптори для Stage 1/2/3QuramDngOpcodeTrimBoundsта vendorUnknownopcode-и (ID ≥14, включаючи ID 23)
Експлойт послідовно виділяє, щоб детерміновано розмістити чанки:
- Stage-1
Unknown(23)opcode-и (20,000 записів) спреять 0x30 чанків, які пізніше звільняються. - Stage-2 звільняє ті opcode-и і поміщає новий
QuramDngImageвсередину звільненої області. - 240 Stage-2
Unknown(23)записів звільняються, і Stage-3 одразу алокує свійQuramDngImageплюс новий raw pixel buffer того ж розміру, повторно використовуючи ці місця. - Сконструйований
TrimBoundsopcode виконується першим у списку 3 і алокує ще один raw pixel buffer перш ніж звільнити Stage-2 стан, гарантуючи суміжність “raw pixel buffer ➜ QuramDngImage”. - Додаткові 640
TrimBoundsзаписів позначеніminVersion=1.4.0.1, тому диспетчер їх пропускає, але їхні backing objects лишаються алокованими і пізніше стають цільовими примітивами.
Ця хореографія ставить Stage-3 raw buffer безпосередньо перед Stage-3 QuramDngImage, тож plane-based overflow змінює поля всередині дескриптора замість того, щоб аварійно падати на випадковий стан.
Reusing Vendor “Unknown” Opcodes as Data Blobs
Samsung залишає high bit встановленим у vendor-specific opcode IDs (наприклад, ID 23), що інструктує інтерпретатор алокувати структуру, але пропустити виконання. Експлойт зловживає цими dormant об’єктами як attacker-controlled heap:
- Opcode list 1 і 2
Unknown(23)записи служать як суміжні scratchpad-и для зберігання payload байтів (JOP chain на offset 0xf000 і shell command на 0x10000 відносно raw buffer). - Оскільки інтерпретатор все ще трактує кожний об’єкт як opcode коли обробляється list 3, підкоригувати vtable одного об’єкта потім достатньо, щоб почати виконувати дані нападника.
Crafting Bogus MapTable Objects & Bypassing ASLR
MapTable об’єкти більші за TrimBounds, але коли корупція layout відбувається, парсер охоче читає додаткові параметри OOB:
- Використати linear write-примітив для часткового перезапису
TrimBoundsvtable pointer скрафченоюMapTablesubstitution table, яка відображає нижчі 2 байти з сусідньогоTrimBoundsvtable доMapTablevtable. Лише low bytes відрізняються між підтримуваними Quram збірками, тож одна 64K lookup таблиця може покрити сім firmware версій і кожен 4 KB ASLR slide. - Заштопати решту полів
TrimBounds(top/left/width/planes), щоб об’єкт поводився як валіднийMapTableпри його виконанні пізніше. - Виконати фейковий opcode над знеціненим (zeroed) пам’яттю. Оскільки pointer substitution table фактично посилається на vtable іншого opcode-а, вихідні байти стають leaked низько-ординатними адресами з
libimagecodec.quram.soабо його GOT. - Застосувати додаткові проходи
MapTable, щоб перетворити ці двобайтові leaks в офсети до гаджетів, таких як__ink_jpeg_enc_process_image+64,QURAMWINK_Read_IO2+124,qpng_check_IHDR+624, і libc-ний__system_property_getentry. Нападники фактично відбудовують повні адреси всередині свого спреєного opcode регіону без нативних API для memory disclosure.
Triggering the JOP ➜ system() Transition
Коли вказівники гаджетів і shell command розміщені всередині opcode spray:
- Остання хвиля
DeltaPerColumnзаписів додає0x0100до офсету 0x22 Stage-3QuramDngImage, зсуваючи його raw buffer pointer на 0x10000 так, що він тепер вказує на attacker command string. - Інтерпретатор починає виконувати хвіст з 1040
Unknown(23)opcode-ів. Перший корумпований запис має vtable замінену на підроблену таблицю на offset 0xf000, тожQuramDngOpcode::aboutToApplyрезолвитьqpng_read_data(4-й запис) з фейкової таблиці. - Ланцюжок гаджетів виконує: завантажує pointer
QuramDngImage, додає 0x20 щоб вказати на raw buffer pointer, дерефенсує його, копіює результат вx19/x0, потім переходить через GOT слоти перезаписані наsystem. Оскільки raw buffer pointer тепер рівний attacker string, фінальний гаджет виконуєsystem(<shell command>)всерединіcom.samsung.ipservice.
Notes on Allocator Variants
Існує дві сім’ї payload-ів: одна налаштована для jemalloc, інша для scudo. Вони відрізняються порядком блоків opcode-ів для досягнення суміжності, але поділяють ті ж логічні примітиви (DeltaPerColumn bug ➜ MapTable zero/write ➜ bogus vtable ➜ JOP). Scudo з вимкненою quarantine робить повторне використання freelist для 0x30-байтних чанків детермінованим, тоді як jemalloc покладається на контроль size-class через tile/subIFD sizing.
References
- Project Zero – A look at an Android ITW DNG exploit
- Project Zero – Pixel 0-click: CVE-2025-54957 in Dolby UDC
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


