滥用 Android 媒体管线与图像解析器
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 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
交付路径: 消息应用 ➜ MediaStore ➜ 特权解析器
现代 OEM 构建通常会运行特权媒体索引器,它们会重新扫描 MediaStore 以支持 “AI” 或共享功能。在未修补到 2025 年 4 月补丁之前的 Samsung 固件上,com.samsung.ipservice 会加载 Quram (/system/lib64/libimagecodec.quram.so) 并自动解析 WhatsApp(或其他应用)放入 MediaStore 的任何文件。实际上,攻击者可以发送一个伪装成 IMG-*.jpg 的 DNG,等待受害者点击 “download”(1-click),即使用户从未打开图库,该特权服务也会解析该载荷。
$ 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], ...
关键要点
- 交付依赖于系统对媒体的重新解析(而不是 chat client),因此继承了该过程的权限(对图库的完全读/写访问、放置新媒体的能力等)。
- 任何通过
MediaStore可访问的 image parser(vision widgets、wallpapers、AI résumé features 等)如果攻击者能够说服目标保存媒体,就会变成可远程触达的目标。
Quram’s DNG Opcode Interpreter Bugs
DNG 文件在不同的解码阶段嵌入三组 opcode 列表。Quram 复制了 Adobe 的 API,但其针对 DeltaPerColumn(opcode ID 11)的 Stage-3 处理器信任攻击者提供的 plane 边界。
在 DeltaPerColumn 中失效的 plane 边界
- 攻击者将
plane=5125和planes=5123,尽管 Stage-3 图像只暴露 planes 0–2(RGB)。 - Quram 计算
opcode_last_plane = image_planes + opcode_planes而不是plane + count,并且从不检查结果的 plane 范围是否适合图像。 - 因此循环会向
raw_pixel_buffer[plane_index]写入一个具有完全可控偏移的 delta(例如 plane 5125 ⇒ 偏移5125 * 2 bytes/pixel = 0x2800)。每个 opcode 向目标位置添加一个 16-bit float 值 (0x6666),从而产生一个精确的堆 OOB add 原语。
将增量变为任意写
- 利用 480 个畸形的
DeltaPerColumn操作,利用者首先损坏 Stage-3 的QuramDngImage.bottom/right,使未来的 opcode 将巨大的坐标当作在界内处理。 - 然后将
MapTableopcodes(opcode 7)指向那些伪造的边界。使用全零的 substitution table 或带有-Infdelta 的DeltaPerColumn,攻击者可以将任意区域清零,然后再应用额外的 delta 来写入精确值。 - 因为 opcode 参数存在于 DNG 元数据中,payload 可以在不直接触碰进程内存的情况下编码数十万次写入。
Heap Shaping Under Scudo
Scudo 按大小对分配进行分桶。Quram 恰好将以下对象以相同 0x30 字节的 chunk サイズ 分配,因此它们落在同一区域(堆上以 0x40 字节间距):
QuramDngImage描述符,用于 Stage 1/2/3QuramDngOpcodeTrimBounds和 厂商Unknownopcodes(ID ≥14,包括 ID 23)
利用按顺序分配来确定性地放置 chunk:
- Stage-1
Unknown(23)opcodes(20,000 条目)喷洒 0x30 chunk,随后这些 chunk 被释放。 - Stage-2 释放这些 opcode 并在已释放区域内放置一个新的
QuramDngImage。 - 240 个 Stage-2
Unknown(23)条目被释放,Stage-3 立即在这些位置重用并分配其QuramDngImage以及一个相同大小的新 raw pixel buffer。 - 一个精心构造的
TrimBoundsopcode 在列表 3 中首先运行并在释放 Stage-2 状态之前分配了另一个 raw pixel buffer,从而保证了 “raw pixel buffer ➜ QuramDngImage” 的相邻性。 - 另外 640 个
TrimBounds条目被标记为minVersion=1.4.0.1,调度器因此跳过它们的执行,但它们的 backing objects 保持分配状态并在稍后成为原语目标。
该编排将 Stage-3 的 raw buffer 放在 Stage-3 QuramDngImage 之前,因此基于 plane 的溢出会翻转描述符内的字段,而不是随机崩溃其他状态。
Reusing Vendor “Unknown” Opcodes as Data Blobs
Samsung 在厂商特定的 opcode ID 中保留高位(例如 ID 23),这会指示解释器 allocate 结构但跳过执行。利用者将这些休眠对象当作攻击者可控的堆来滥用:
- Opcode 列表 1 和 2 的
Unknown(23)条目作为连续的 scratchpad,用于存储 payload 字节(JOP chain 在相对于 raw buffer 的偏移 0xf000,shell 命令 在 0x10000)。 - 因为解释器在处理列表 3 时仍将每个对象视为 opcode,占据一个对象的 vtable 即足以开始执行攻击者的数据。
Crafting Bogus MapTable Objects & Bypassing ASLR
MapTable 对象比 TrimBounds 更大,但一旦布局被破坏,解析器会高兴地从越界位置读取额外参数:
- 使用线性写入原语部分覆盖一个
TrimBounds的 vtable 指针,替换为一个伪造的MapTablesubstitution table,该表将相邻TrimBoundsvtable 的低 2 字节映射到MapTablevtable。受支持的 Quram 构建之间低字节差异很小,因此单个 64K 查找表可以覆盖七个固件版本以及每个 4 KB 的 ASLR slide。 - 修补
TrimBounds的其余字段(top/left/width/planes),使该对象在稍后执行时表现得像一个有效的MapTable。 - 在被清零的内存上执行这个伪造 opcode。因为 substitution table 指针实际上引用了另一个 opcode 的 vtable,输出字节会变成 leaked 来自
libimagecodec.quram.so或其 GOT 的低位地址。 - 再次应用
MapTable通过将这两个字节的泄露转换为指向 gadget 的偏移,例如__ink_jpeg_enc_process_image+64、QURAMWINK_Read_IO2+124、qpng_check_IHDR+624和 libc 的__system_property_get条目。攻击者实际上在其喷洒的 opcode 区域内重建了完整地址,而无需本地内存泄露 API。
Triggering the JOP ➜ system() Transition
一旦 gadget 指针和 shell 命令在 opcode 喷洒区就绪:
- 最后一波
DeltaPerColumn写入将 Stage-3QuramDngImage的偏移 0x22 加上0x0100,将其 raw buffer 指针移动 0x10000,从而使其现在引用攻击者的命令字符串。 - 解释器开始执行尾部的 1040 个
Unknown(23)opcode。第一个被破坏的条目其 vtable 被替换为位于偏移 0xf000 的伪造表,因此QuramDngOpcode::aboutToApply将解析出假表中的qpng_read_data(第 4 项)。 - 链接的 gadget 执行:加载
QuramDngImage指针,加 0x20 指向 raw buffer 指针,解引用它,将结果复制到 x19/x0,然后通过被重写为system的 GOT 插槽跳转。因为 raw buffer 指针现在等于攻击者的字符串,最终的 gadget 将在com.samsung.ipservice内执行system(<shell command>)。
Notes on Allocator Variants
存在两类 payload:一类针对 jemalloc 调优,另一类针对 scudo。它们在如何对 opcode blocks 排序以实现相邻性上有所不同,但共享相同的逻辑原语(DeltaPerColumn bug ➜ MapTable zero/write ➜ bogus vtable ➜ JOP)。Scudo 的禁用隔离(quarantine)使得 0x30 字节 freelist 重用变得确定性,而 jemalloc 则依赖于通过 tile/subIFD 大小来控制 size-class。
References
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 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks

