Android Media Pipelines & Image Parsers का दुरुपयोग
Tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
डिलीवरी: मैसेजिंग ऐप्स ➜ MediaStore ➜ विशेषाधिकार प्राप्त पार्सर
आधुनिक OEM बिल्ड नियमित रूप से विशेषाधिकार प्राप्त मीडिया इंडेक्सर चलाते हैं जो “AI” या शेयरिंग फ़ीचर्स के लिए MediaStore को फिर से स्कैन करते हैं। April 2025 patch से पहले के Samsung firmware पर, com.samsung.ipservice Quram (/system/lib64/libimagecodec.quram.so) को लोड करता है और स्वचालित रूप से MediaStore में WhatsApp (या अन्य ऐप्स) द्वारा डाली गई किसी भी फ़ाइल को पार्स कर लेता है। व्यवहार में एक attacker एक DNG भेज सकता है जिसे IMG-*.jpg के रूप में छिपाया गया हो, पीड़ित के “download” (1-click) टैप करने का इंतजार कर सकता है, और विशेषाधिकार प्राप्त सेवा उस payload को पार्स कर देगी भले ही user कभी gallery न खोले।
$ 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], ...
मुख्य निष्कर्ष
- Delivery सिस्टम media re-parsing पर निर्भर करता है (chat client नहीं) और इसलिए वह उस प्रक्रिया के permissions विरासत में लेता है (gallery का full read/write access, नया media drop करने की क्षमता, आदि)।
MediaStoreके माध्यम से पहुँच योग्य कोई भी image parser (vision widgets, wallpapers, AI résumé features, आदि) दूर से पहुँच योग्य बन जाता है यदि attacker किसी लक्ष्य को मीडिया save करने के लिए राज़ी कर सकता है।
0-click DD+/EAC-3 decoding path (Google Messages ➜ mediacodec sandbox)
Modern messaging stacks भी transcription/search के लिए audio को auto-decode करते हैं। Pixel 9 पर, Google Messages आने वाले RCS/SMS audio को user के message खोलने से पहले Dolby Unified Decoder (UDC) में /vendor/lib64/libcodec2_soft_ddpdec.so को सौंप देता है, जिससे 0-click surface media codecs तक बढ़ जाता है।
प्रमुख parse बाधाएँ
- प्रत्येक DD+ syncframe में अधिकतम 6 blocks होते हैं; प्रत्येक block attacker-controlled skip data के
0x1FFbytes तक को skip buffer में copy कर सकता है (≈0x1FF * 6bytes प्रति frame)। - skip buffer को EMDF के लिए स्कैन किया जाता है:
syncword (0xX8)+emdf_container_length(16b) + variable-length fields।emdf_payload_sizeको एक unboundedvariable_bits(8)loop के साथ parse किया जाता है। - EMDF payload bytes को एक custom प्रति-फ्रेम “evo heap” bump allocator के अंदर allocate किया जाता है और फिर bit-reader द्वारा bounded
emdf_container_lengthसे byte-by-byte copy किया जाता है।
Integer-overflow → heap-overflow primitive (CVE-2025-54957)
ddp_udc_int_evo_mallocalloc_size+extraको 8 bytes पर align करता है viatotal_size += (8 - total_size) % total_sizeबिना wrap detection के। AArch64 पर0xFFFFFFFFFFFFFFF9..FFके पास के मान छोटेtotal_sizeमें shrink हो जाते हैं।- copy loop अभी भी
emdf_payload_sizeसे logicalpayload_lengthका उपयोग करता है, इसलिए attacker bytes undersized chunk के पार evo-heap डेटा को overwrite कर देते हैं। - Overflow length ठीक वही attacker-चयनित
emdf_container_lengthद्वारा सीमित है; overflow bytes attacker-controlled EMDF payload डेटा होते हैं। slab allocator हर syncframe पर reset होता है, जिससे predictable adjacency मिलती है।
Secondary read primitive
यदि emdf_container_length > skipl, तो EMDF parsing initialized skip bytes के पार पढ़ता है (OOB read)। अकेला यह zeros/known media को leak करता है, लेकिन adjacent heap metadata को corrupt करने के बाद यह corrupted region को वापस पढ़ सकता है ताकि exploit validate किया जा सके।
Exploitation recipe
- बड़े
emdf_payload_size(viavariable_bits(8)) वाला EMDF बनाएं ताकि allocator padding wrap करके एक छोटे chunk में आ जाए। - overflow length (≤ total skip data budget) के लिए
emdf_container_lengthसेट करें; overflow bytes को EMDF payload में रखें। - प्रति-फ्रेम evo heap को इस तरह shape करें कि small allocation decoder के static buffer (≈693 KB) या dynamic buffer (≈86 KB) के भीतर target structures से पहले बैठे।
- वैकल्पिक रूप से
emdf_container_length > skiplचुनें ताकि corruption के बाद skip buffer से overwritten डेटा पढ़कर verify किया जा सके।
Quram’s DNG Opcode Interpreter Bugs
DNG फ़ाइलें तीन opcode सूचियाँ embed करती हैं जो decode के अलग-अलग चरणों पर लागू होती हैं। Quram Adobe के API की नकल करता है, लेकिन इसका Stage-3 handler DeltaPerColumn (opcode ID 11) के लिए attacker-supplied plane bounds पर भरोसा करता है।
Failing plane bounds in DeltaPerColumn
- Attackers
plane=5125औरplanes=5123सेट करते हैं जबकि Stage-3 images केवल planes 0–2 (RGB) एक्सपोज़ करते हैं। - Quram
opcode_last_plane = image_planes + opcode_planescompute करता है बजायplane + countके, और यह कभी नहीं चेक करता कि resulting plane range image के अंदर फिट होता है या नहीं। - इसलिए loop
raw_pixel_buffer[plane_index]पर एक delta लिखता है एक पूरी तरह से नियंत्रित offset के साथ (उदाहरण के लिए, plane 5125 ⇒ offset5125 * 2 bytes/pixel = 0x2800)। प्रत्येक opcode targeted location में एक 16-bit float value (0x6666) जोड़ता है, जिससे एक सटीक heap OOB add primitive बनता है।
Turning increments into arbitrary writes
- exploit पहले Stage-3
QuramDngImage.bottom/rightको 480 malformedDeltaPerColumnoperations से corrupt करता है ताकि भविष्य के opcodes विशाल coordinates को in-bounds मानें। - फिर
MapTableopcodes (opcode 7) उन fake bounds पर लक्षित किए जाते हैं। सभी zeros वाली substitution table याDeltaPerColumnwith-Infdeltas का उपयोग करके attacker किसी भी region को zero कर देता है, फिर अतिरिक्त deltas apply करके exact values लिख देता है। - चूंकि opcode parameters DNG metadata के अंदर रहते हैं, payload सैकड़ों हजारों writes encode कर सकता है बिना सीधे process memory को छुए।
Heap Shaping Under Scudo
Scudo allocations को size द्वारा bucket करता है। Quram निम्न objects को identical 0x30-byte chunk sizes के साथ allocate करता है, इसलिए ये एक ही region (heap पर 0x40-byte spacing) में उतरते हैं:
- Stage 1/2/3 के लिए
QuramDngImagedescriptors QuramDngOpcodeTrimBoundsऔर vendorUnknownopcodes (ID ≥14, जिसमें ID 23 शामिल है)
Exploit allocations की sequencing करके chunks को deterministic तरीके से place करता है:
- Stage-1
Unknown(23)opcodes (20,000 entries) 0x30 chunks spray करते हैं जो बाद में free हो जाते हैं। - Stage-2 उन opcodes को free कर देता है और freed region के अंदर एक नया
QuramDngImageरखता है। - 240 Stage-2
Unknown(23)entries free किए जाते हैं, और Stage-3 तुरंत अपनेQuramDngImageऔर उसी आकार के नए raw pixel buffer को allocate करता है, उन spots को reuse करते हुए। - एक crafted
TrimBoundsopcode सूची 3 में पहले चलता है और एक और raw pixel buffer allocate करता है इससे पहले कि Stage-2 state free हो, जिससे “raw pixel buffer ➜ QuramDngImage” adjacency की गारंटी होती है। - 640 अतिरिक्त
TrimBoundsentries कोminVersion=1.4.0.1के रूप में चिह्नित किया जाता है ताकि dispatcher उन्हें skip करे, पर उनकी backing objects allocated रहती हैं और बाद में primitive targets बन जाती हैं।
यह choreography Stage-3 raw buffer को सीधे Stage-3 QuramDngImage से पहले रख देती है, इसलिए plane-based overflow descriptor के अंदर fields को flip कर देता है बजाय किसी random state को crash करने के।
Reusing Vendor “Unknown” Opcodes as Data Blobs
Samsung vendor-specific opcode IDs (उदा., ID 23) में high bit सेट छोड़ देता है, जो interpreter को structure allocate करने और execution skip करने का संकेत देता है। exploit उन dormant objects का दुरुपयोग attacker-controlled heaps के रूप में करता है:
- Opcode list 1 और 2 के
Unknown(23)entries contiguous scratchpads के रूप में payload bytes (JOP chain offset 0xf000 पर और shell command 0x10000 पर raw buffer के relative) संग्रहीत करने के लिए काम आते हैं। - क्योंकि interpreter सूची 3 को process करते समय अभी भी प्रत्येक object को एक opcode की तरह ट्रीट करता है, किसी एक object’s vtable को बाद में commandeer करना attacker data के execution शुरू करने के लिए पर्याप्त होता है।
Crafting Bogus MapTable Objects & Bypassing ASLR
MapTable objects TrimBounds से बड़े होते हैं, लेकिन एक बार layout corruption होने पर parser खुशी-खुशी extra parameters को out-of-bounds पढ़ लेता है:
- linear write primitive का उपयोग करके आंशिक रूप से एक
TrimBoundsvtable pointer को ओवरराइट करें एक craftedMapTablesubstitution table के साथ जो lower 2 bytes को पड़ोसीTrimBoundsvtable सेMapTablevtable पर map कर दे। समर्थित Quram builds के बीच केवल low bytes अलग होते हैं, इसलिए एक single 64K lookup table सात firmware versions और हर 4 KB ASLR slide को हँडल कर सकता है। TrimBoundsके बाकी fields (top/left/width/planes) को patch करें ताकि object बाद में execute होने पर एक मान्यMapTableजैसा व्यवहार करे।- zeroed memory पर fake opcode execute करें। क्योंकि substitution table pointer असल में किसी अन्य opcode के vtable को reference करता है, output bytes
libimagecodec.quram.soया उसके GOT से leaked low-order addresses बन जाते हैं। - अतिरिक्त
MapTablepasses लागू करके उन दो-बाइट leaks को उन gadgets की ओर offsets में बदला जाता है जैसे__ink_jpeg_enc_process_image+64,QURAMWINK_Read_IO2+124,qpng_check_IHDR+624, और libc का__system_property_getentry। attackers प्रभावी रूप से अपने sprayed opcode region के अंदर पूर्ण addresses rebuild कर लेते हैं बिना किसी native memory disclosure API के।
Triggering the JOP ➜ system() Transition
एक बार gadget pointers और shell command opcode spray में stage हो जाने पर:
- अंतिम wave के
DeltaPerColumnwrites Stage-3QuramDngImageके offset 0x22 पर0x0100जोड़ देते हैं, जिससे उसका raw buffer pointer 0x10000 से शिफ्ट हो जाता है और अब attacker command string को reference करता है। - interpreter 1040
Unknown(23)opcodes की tail को execute करना शुरू करता है। पहला corrupted entry इसका vtable forged table (offset 0xf000) से बदल चुका होता है, इसलिएQuramDngOpcode::aboutToApplyfake table सेqpng_read_data(4th entry) resolve कर लेता है। - chained gadgets यह करते हैं:
QuramDngImagepointer load करना, raw buffer pointer की ओर इशारा करने के लिए 0x20 जोड़ना, उसे dereference करना, परिणाम कोx19/x0में कॉपी करना, फिर GOT slots के माध्यम से jump करना जोsystemके लिए rewritten हैं। क्योंकि raw buffer pointer अब attacker string के बराबर है, अंतिम gadgetsystem(<shell command>)कोcom.samsung.ipserviceके अंदर execute कर देता है।
Notes on Allocator Variants
दो payload families मौजूद हैं: एक jemalloc के लिए tune किया गया, दूसरा scudo के लिए। वे adjacency हासिल करने के लिए opcode blocks के ordering में भिन्न होते हैं लेकिन एक ही logical primitives साझा करते हैं (DeltaPerColumn bug ➜ MapTable zero/write ➜ bogus vtable ➜ JOP)। Scudo की disabled quarantine 0x30-byte freelist reuse को deterministic बनाती है, जबकि jemalloc tile/subIFD sizing के माध्यम से size-class control पर निर्भर करता है।
References
- Project Zero – A look at an Android ITW DNG exploit
- Project Zero – Pixel 0-click: CVE-2025-54957 in Dolby UDC
Tip
AWS हैकिंग सीखें और अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।


