Abusing Android Media Pipelines & Image Parsers
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.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Delivery: Messaging Apps ➜ MediaStore ➜ Privileged Parsers
Τα σύγχρονα OEM builds τρέχουν τακτικά διαδικασίες ευρετηρίασης μέσων με προνόμια που επανασκανάρουν το MediaStore για δυνατότητες “AI” ή κοινής χρήσης. Σε Samsung firmware πριν από το patch του Απριλίου 2025, το com.samsung.ipservice φορτώνει την Quram (/system/lib64/libimagecodec.quram.so) και αναλύει αυτόματα οποιοδήποτε αρχείο το WhatsApp (ή άλλες εφαρμογές) τοποθετεί στο MediaStore. Στην πράξη, ένας επιτιθέμενος μπορεί να στείλει ένα DNG μεταμφιεσμένο ως IMG-*.jpg, να περιμένει το θύμα να πατήσει “download” (1-click), και η υπηρεσία με προνόμια θα αναλύσει το payload ακόμη κι αν ο χρήστης δεν ανοίξει ποτέ την 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], ...
Σημαντικά συμπεράσματα
- Η παράδοση βασίζεται στην επανα-ανάλυση (re-parsing) των συστημικών media (όχι του chat client) και έτσι κληρονομεί τα δικαιώματα αυτής της διεργασίας (πλήρης πρόσβαση ανάγνωσης/εγγραφής στη συλλογή, δυνατότητα τοποθέτησης νέων πολυμέσων, κ.λπ.).
- Οποιοσδήποτε image parser προσβάσιμος μέσω του
MediaStore(vision widgets, wallpapers, AI résumé features, κ.λπ.) γίνεται απομακρυσμένα προσβάσιμος εάν ο επιτιθέμενος καταφέρει να πείσει το θύμα να αποθηκεύσει media.
0-click DD+/EAC-3 διαδρομή αποκωδικοποίησης (Google Messages ➜ mediacodec sandbox)
Τα σύγχρονα messaging stacks αποκωδικοποιούν επίσης αυτόματα τον ήχο για μεταγραφή/αναζήτηση. Σε Pixel 9, τα Google Messages παραδίδουν εισερχόμενο RCS/SMS audio στον Dolby Unified Decoder (UDC) μέσα στο /vendor/lib64/libcodec2_soft_ddpdec.so πριν ο χρήστης ανοίξει το μήνυμα, διευρύνοντας την 0-click επιφάνεια προς media codecs.
Βασικοί περιορισμοί ανάλυσης
- Κάθε DD+ syncframe έχει έως 6 blocks· κάθε block μπορεί να αντιγράψει έως
0x1FFbytes από ελεγχόμενα από τον επιτιθέμενο skip data σε έναν skip buffer (≈0x1FF * 6bytes ανά frame). - Ο skip buffer σαρώνονται για EMDF:
syncword (0xX8)+emdf_container_length(16b) + μεταβλητού μήκους πεδία. Τοemdf_payload_sizeαναλύεται με έναν απεριόριστο βρόχοvariable_bits(8). - Τα bytes του payload του EMDF δεσμεύονται μέσα σε έναν custom per-frame “evo heap” bump allocator και στη συνέχεια αντιγράφονται byte-προς-byte από έναν bit-reader που οριοθετείται από το
emdf_container_length.
Υπερχείλιση-integer → heap-overflow primitive (CVE-2025-54957)
- Η
ddp_udc_int_evo_mallocευθυγραμμίζει τοalloc_size+extraστα 8 bytes μέσωtotal_size += (8 - total_size) % total_sizeχωρίς ανίχνευση wrap. Τιμές κοντά στο0xFFFFFFFFFFFFFFF9..FFσυρρικνώνουν τοtotal_sizeσε πολύ μικρό μέγεθος σε AArch64. - Ο βρόχος αντιγραφής εξακολουθεί να χρησιμοποιεί το λογικό
payload_lengthαπό τοemdf_payload_size, οπότε τα bytes του επιτιθέμενου υπεργράφουν δεδομένα του evo-heap πέρα από το υποβαθμισμένο chunk. - Το μήκος overflow περιορίζεται με ακρίβεια από το
emdf_container_lengthπου επιλέγει ο επιτιθέμενος· τα overflow bytes είναι ελεγχόμενα από τον επιτιθέμενο EMDF payload δεδομένα. Ο slab allocator επαναφέρεται κάθε syncframe, δίνοντας προβλέψιμη γειτνίαση.
Δευτερεύων primitive ανάγνωσης
Εάν emdf_container_length > skipl, η ανάλυση EMDF διαβάζει πέρα από τα αρχικοποιημένα skip bytes (OOB read). Αφότου μόνο του leaks μηδενικά/γνωστά μέσα, αλλά μετά τη φθορά του γειτονικού heap metadata μπορεί να διαβάσει πίσω την καταχωρισμένη περιοχή για να επικυρώσει το exploit.
Συνταγή εκμετάλλευσης
- Δημιουργήστε EMDF με τεράστιο
emdf_payload_size(μέσωvariable_bits(8)) ώστε η στοίβα ευθυγράμμισης του allocator να τυλίξει σε μικρό chunk. - Ορίστε
emdf_container_lengthστο επιθυμητό μήκος overflow (≤ συνολικό budget skip data); τοποθετήστε bytes overflow στο EMDF payload. - Σχηματίστε το per-frame evo heap ώστε η μικρή κατανομή να βρίσκεται πριν από στοχευμένες δομές μέσα στο στατικό buffer του decoder (≈693 KB) ή στο δυναμικό buffer (≈86 KB) που δεσμεύεται μία φορά ανά decoder instance.
- Προαιρετικά επιλέξτε
emdf_container_length > skiplγια να διαβάσετε πίσω υπεγραμμένα δεδομένα από τον skip buffer μετά τη φθορά.
Σφάλματα του Quram DNG Opcode Interpreter
Αρχεία DNG ενσωματώνουν τρεις λίστες opcode που εφαρμόζονται σε διαφορετικά στάδια αποκωδικοποίησης. Ο Quram αντιγράφει το API της Adobe, αλλά ο Stage-3 χειριστής του για το DeltaPerColumn (opcode ID 11) εμπιστεύεται attacker-supplied όρια των plane.
Αποτυχία ορίων plane στο DeltaPerColumn
- Οι επιτιθέμενοι θέτουν
plane=5125καιplanes=5123παρόλο που οι εικόνες Stage-3 αποκάλυπταν μόνο planes 0–2 (RGB). - Ο Quram υπολογίζει
opcode_last_plane = image_planes + opcode_planesαντί γιαplane + count, και ποτέ δεν ελέγχει αν το προκύπτον εύρος planes χωράει μέσα στην εικόνα. - Ο βρόχος επομένως γράφει ένα delta στο
raw_pixel_buffer[plane_index]με πλήρως ελεγχόμενο offset (π.χ., plane 5125 ⇒ offset5125 * 2 bytes/pixel = 0x2800). Κάθε opcode προσθέτει μία 16-bit float τιμή (0x6666) στην στοχευμένη θέση, αποδίδοντας ένα ακριβές heap OOB add primitive.
Μετατροπή των αυξήσεων σε αυθαίρετες εγγραφές
- Το exploit αρχικά χαλάει τα
QuramDngImage.bottom/rightτου Stage-3 χρησιμοποιώντας 480 κακοσχηματισμένεςDeltaPerColumnλειτουργίες ώστε μελλοντικά opcodes να θεωρήσουν τεράστιες συντεταγμένες ως εντός ορίων. - Τα
MapTableopcodes (opcode 7) κατόπιν στοχεύονται σε εκείνα τα ψεύτικα όρια. Χρησιμοποιώντας έναν substitution πίνακα πλήρη μηδενικών ή έναDeltaPerColumnμε-Infdeltas, ο επιτιθέμενος μηδενίζει οποιαδήποτε περιοχή και στη συνέχεια εφαρμόζει πρόσθετα deltas για να γράψει ακριβείς τιμές. - Επειδή οι παράμετροι των opcode ζουν μέσα στα DNG metadata, το payload μπορεί να κωδικοποιήσει εκατοντάδες χιλιάδες εγγραφές χωρίς να αγγίξει άμεσα τη μνήμη της διεργασίας.
Σχηματισμός heap υπό Scudo
Το Scudo ομαδοποιεί τις δεσμεύσεις κατά μέγεθος. Ο Quram τυχαίνει να δεσμεύει τα ακόλουθα αντικείμενα με ταυτόσημα 0x30-byte chunk sizes, επομένως προσγειώνονται στην ίδια περιοχή (0x40-byte κενά στη στοίβα):
- Περιγραφείς
QuramDngImageγια Stage 1/2/3 QuramDngOpcodeTrimBoundsκαι vendorUnknownopcodes (ID ≥14, συμπεριλαμβανομένου του ID 23)
Το exploit ακολουθεί σειρές δεσμεύσεων για να τοποθετήσει deterministically chunks:
- Stage-1
Unknown(23)opcodes (20,000 εγγραφές) ψεκάζουν 0x30 chunks που απελευθερώνονται αργότερα. - Το Stage-2 απελευθερώνει αυτά τα opcodes και τοποθετεί ένα νέο
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ώστε ο dispatcher να τις παραλείψει, αλλά τα υποκείμενα αντικείμενα παραμένουν δεσμευμένα και αργότερα γίνονται primitive targets.
Αυτή η χορογραφία τοποθετεί το raw buffer του Stage-3 αμέσως πριν από το Stage-3 QuramDngImage, έτσι το overflow βάσει planes αναστρέφει πεδία μέσα στον περιγραφέα αντί να προκαλέσει τυχαίο crash.
Επαναχρησιμοποίηση vendor “Unknown” Opcodes ως Data Blobs
Η Samsung αφήνει το high bit ενεργό στα vendor-specific opcode IDs (π.χ. ID 23), το οποίο δίνει εντολή στον interpreter να δεσμεύσει τη δομή αλλά να παραλείψει την εκτέλεση. Το exploit καταχράται αυτά τα αδρανή αντικείμενα ως ελεγχόμενους από τον επιτιθέμενο χώρους:
- Οι εγγραφές
Unknown(23)στη λίστα opcode 1 και 2 λειτουργούν ως συνεχή scratchpads για αποθήκευση bytes payload (JOP chain στη μετατόπιση 0xf000 και μια shell εντολή στο 0x10000 σχετική με το raw buffer). - Επειδή ο interpreter εξακολουθεί να αντιμετωπίζει κάθε αντικείμενο ως opcode όταν επεξεργάζεται η λίστα 3, η κατάληψη του vtable ενός αντικειμένου αρκεί αργότερα για να αρχίσει η εκτέλεση attacker data.
Κατασκευή ψευδών MapTable αντικειμένων & παράκαμψη ASLR
Τα MapTable αντικείμενα είναι μεγαλύτερα από τα TrimBounds, αλλά μόλις επέλθει η φθορά της διάταξης, ο parser ευχαρίστως διαβάζει επιπλέον παραμέτρους εκτός ορίων:
- Χρησιμοποιήστε το linear write primitive για να μερικώς υπεγράψετε έναν pointer vtable του
TrimBoundsμε έναν κατασκευασμένο substitution πίνακαMapTableπου αντιστοιχίζει τα χαμηλότερα 2 bytes από το γειτονικό vtableTrimBoundsστο vtable τουMapTable. Μόνο τα χαμηλά bytes διαφέρουν μεταξύ των υποστηριζόμενων Quram builds, οπότε ένας ενιαίος 64K lookup πίνακας μπορεί να χειριστεί επτά εκδόσεις firmware και κάθε 4 KB ASLR slide. - Επιδιορθώστε τα υπόλοιπα πεδία του
TrimBounds(top/left/width/planes) ώστε το αντικείμενο να συμπεριφέρεται σαν έγκυροMapTableόταν εκτελεστεί αργότερα. - Εκτελέστε το ψεύτικο opcode πάνω σε μηδενισμένη μνήμη. Επειδή ο pointer του substitution table στην πραγματικότητα αναφέρεται στο vtable ενός άλλου opcode, τα output bytes γίνονται leaked low-order addresses από το
libimagecodec.quram.soή το GOT του. - Εφαρμόστε επιπλέον περάσματα
MapTableγια να μετατρέψετε αυτές τις δι-πλευρικές διαρροές σε offsets προς gadgets όπως__ink_jpeg_enc_process_image+64,QURAMWINK_Read_IO2+124,qpng_check_IHDR+624και τη libc__system_property_getείσοδο. Οι επιτιθέμενοι ουσιαστικά ανασυστήνουν πλήρεις διευθύνσεις μέσα στην ψεκαζόμενη περιοχή opcode χωρίς εγγενείς native memory disclosure APIs.
Ενεργοποίηση της μετάβασης JOP ➜ system()
Μόλις οι pointers προς gadgets και η shell εντολή τοποθετηθούν μέσα στο opcode spray:
- Ένα τελικό κύμα
DeltaPerColumnεγγραφών προσθέτει0x0100στη μετατόπιση 0x22 του Stage-3QuramDngImage, μετατοπίζοντας το pointer του raw buffer κατά 0x10000 ώστε τώρα να αναφέρεται στη συμβολοσειρά εντολής του επιτιθέμενου. - Ο interpreter αρχίζει να εκτελεί την ουρά από 1040
Unknown(23)opcodes. Η πρώτη κατεστραμμένη εγγραφή έχει το vtable της αντικαταστημένο με τον παραποιημένο πίνακα στη μετατόπιση 0xf000, έτσιQuramDngOpcode::aboutToApplyεπιλύειqpng_read_data(την 4η εγγραφή) από τον ψεύτικο πίνακα. - Τα αλυσιδωτά gadgets κάνουν: φορτώνουν τον pointer
QuramDngImage, προσθέτουν 0x20 για να δείξουν στον pointer του raw buffer, τον αποαποστηχούν, αντιγράφουν το αποτέλεσμα σεx19/x0, και μετά πηδούν μέσω GOT slots που έχουν ξαναγραφεί σεsystem. Επειδή ο pointer του raw buffer τώρα δείχνει στη συμβολοσειρά του επιτιθέμενου, το τελικό gadget εκτελείsystem(<shell command>)μέσα στοcom.samsung.ipservice.
Σημειώσεις για παραλλαγές allocator
Υπάρχουν δύο οικογένειες payload: μία ρυθμισμένη για jemalloc και μία για scudo. Διαφέρουν στο πώς παραγγέλνονται τα blocks των opcode για να επιτευχθεί η γειτνίαση, αλλά μοιράζονται τα ίδια λογικά primitives (σφάλμα DeltaPerColumn ➜ MapTable zero/write ➜ bogus vtable ➜ JOP). Η απενεργοποιημένη quarantine του Scudo κάνει την επαναχρησιμοποίηση freelist 0x30-byte ντετερμινιστική, ενώ ο 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.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.


