dng_render_task::ProcessArea 中的越界写入(Adobe DNG SDK / Android)可通过 Android 的公共图像解码 API 从普通 DNG 文件触发,并已在 Galaxy S25 上使用手机自带的 /system/lib64/libdng_sdk.so 复现。
DNG_REQUIRE(srcArea.Size() == dstArea.Size()) + srcArea 索引)#12 AImageDecoder_decodeImage /system/lib64/libjnigraphics.so
#11 android::ImageDecoder::decode /system/lib64/libhwui.so
#09 SkCodec::getPixels /system/lib64/libhwui.so
#08 SkRawCodec::onGetPixels /system/lib64/libhwui.so
#07 dng_render::Render() /system/lib64/libdng_sdk.so
#06 SkDngHost::PerformAreaTask /system/lib64/libhwui.so
#00 dng_render_task::ProcessArea /system/lib64/libdng_sdk.so <-- 漏洞位置
ProcessArea 将一块瓦片大小的临时缓冲区映射到 srcArea 上,却使用 dstArea 坐标对其进行索引。由于 srcArea = dstArea + fSrcOffset,且 fSrcOffset 是文件的 DefaultCropOrigin —— 在每张真实相机 DNG 中均为非零值 —— 目标指针会因 fSrcOffset * rowStep * pixelSize 而偏离出分配区域,掩码回读操作便写入该处。这是一个位移问题,而非整数溢出,因此无需超大分配:这正是它在手机上可被触达的原因。
01-vulnerability/ 存在漏洞和已修复版本的 dng_render.cpp,以及 2471->2502 的差异补丁
02-poc/ 生成器、加载器、探针(源码)+ 预编译的 arm64 二进制
03-samples/ DNG 文件
04-evidence/ ASAN 日志、设备 tombstone、探针输出
05-analysis/ 根因、生成器、相邻对象测量、RCE 差距分析
超越早期结论的工作:通过测量推翻其中两项论断,填补了“损坏的指针是否被使用”的空白,并精确定位了利用链停止的原因。请先阅读 06-rce-lab/README.md;evidence/*.md 文件是各实验的详细报告,src/ 和 apk/ 是可复现的测试框架。
adb push 02-poc/bin-arm64/poc_aimg 03-samples/trigger_natural_croporigin.dng /data/local/tmp/
adb shell "cd /data/local/tmp && chmod 755 poc_aimg && ./poc_aimg trigger_natural_croporigin.dng"
# -> 段错误,tombstone 帧位于 libdng_sdk.so 内
重新构建 arm64 加载器需要使用 Android 自带的 dng_sdk 编译标志(来自 Android.bp),否则结构体布局将与出厂库不匹配:
-DUNIX_ENV=1 -DqDNGBigEndian=0 -DqDNGThreadSafe=1 -DqDNGUseLibJPEG=1 \
-DqDNGUseXMP=0 -DqDNGValidateTarget=1 -DqDNGUsingSanitizer=1 -DqLinux=1 -DqAndroid=1
对应 CVE-2026-27280(DNG SDK 1.7.1 2471 及更早版本,CWE-787,CVSS 3.1 7.8 高危),发布于 2026-03-10 —— 通过版本范围和类别匹配,未经 Adobe 点名该函数确认。
已在真实 Android 解码路径上、在补丁更新至 2026-01-01 的设备上证实:
攻击者可控目标地址的越界写入(4 字节粒度,双向,与 ASLR 无关);可通过 AImageDecoder 从普通 DNG 触达,已演示在缩略图加载器中杀死 Samsung Gallery;对相邻对象的静默确定性破坏;损坏的指针到达 free()(N1 闭合);由 DNG 格式表达的堆喷射(ImageStats × SubIFD);将写入瞄准这些喷射对象,6/10 对比 0/10。
在 Android 路径上无法实现 RCE,且根因只有一个: 代码只能写入单个值 0x3F800000。一切皆由此而来 —— 写入是连续的(无法跨越 Scudo 头部),没有可写的零值(无法破坏长度/引用计数),且保留标签的部分覆盖恰好只有一个固定目标偏移。一个值对随机化的 256 MB 保留区只有一次机会,无论喷射多少或并发多高都无法增加机会。在桌面 SDK 上可写集合为 256 个值 → 在约 67 MB 的区间内有 256 次机会,这就是 7.8 评分在桌面端正确的原因。
从早期结论中撤回(05-analysis/05-exploitability-verdict.md),已被测量证伪:“真实解码器不提供喷射原语” 和 “重叠无法在单次解码内部操控”。阻碍并非 PAC、BTI 或 Scudo 的校验和 —— 而是单一可写值,这是代码本身的属性,Adobe 的 2502 修复通过改用 srcArea 索引从根源上消除了它。
未构建任何可用的利用程序,此处也未发布任何利用程序。
| 文件 | 作用 |
|---|
trigger_natural_croporigin.dng | 自然几何(DefaultCropOrigin = 8,8);使 AImageDecoder 崩溃 |
benign_reference.dng | 同一文件但原点为 0 —— 可正常解码,用于探测堆 |
silent_corruption.dng | 小尺寸类别:越界写入但不崩溃(5/5) |
far_write_crash.dng | 大位移:明显触发故障 |
| 文件 | 内容 |
|---|
01-root-cause.md | 漏洞、修复方案、写入形态 |
02-dng-generator.md | 触发文件的构建方式、两个调节旋钮、陷阱 |
03-neighbours.md | 可控性数据、缓冲区相邻对象、缓解措施 |
04-what-is-missing-for-rce.md | 已证实的内容(P1-P8)、未证实的内容(N1-N3)、剩余步骤 |
05-exploitability-verdict.md | 早期结论 —— 已被 06-rce-lab 取代,存档备查 |
| 文件 | 内容 |
|---|
EXP1-stride-vs-scudo.md | 步长与 Scudo 头部:抽象上可行,在 Android 路径上不可行(planes==1) |
EXP2-N1-corrupted-pointer-used.md | 损坏的指针到达 free() —— N1 已闭合 |
EXP2-real-process.md | 在真实 Samsung Gallery 进程中的写入,无任何植入 |
EXP-imagestats-spray.md | 早期结论认为不可能的堆喷射,由 DNG 格式表达 |
EXP-aimed-spray.md | 将写入瞄准喷射对象:6/10 对比 0/10 |
EXP-small-class-in-app.md | 真实应用进程内可触达的代码指针 |
EXP-band-commit.md / EXP-concurrency.md | 为何提交目标失败:一个可写值 = 一次机会 |
EXP-write-read-mismatch.md | 第二个缺陷 + ProcessArea 的完整源码审计 |
EXP-value-1.0f.md | 1.0f 作为数据项的路径,结构性闭合 |