
Notas redactadas sobre CVE-2026-28618 / laboratorio StreamBox APV — escritura en el heap dentro de un objeto de sesión mediante un desajuste de altura de FRAME
CVE-2026-28618 en StreamBox — la misma clase de decodificador que el RCE de APV en Android explotado en el mundo real, convertido en una escritura de heap contra un objeto de sesión.
Este repositorio es un writeup público y censurado: las flags, los tokens de instancia y la clave HMAC están omitidos. El APK y make_clip.py pertenecen a Mobile Hacking Lab; no se replican aquí.

StreamBox es un pequeño reproductor de APV. APV es Advanced Professional Video (RFC 9924), el códec libre de regalías de Samsung, la misma familia que se distribuyó en el stack multimedia de Android. El planteamiento del laboratorio es una frase: el reproductor reproduce los clips compartidos al recibirlos.
SEND, VIEW o streambox://?url=… deposita un archivo en files/incoming.apv y se ejecuta NativeDec.loadClip(). Sin toque adicional en el clip.
El fallo es CVE-2026-28618: un desbordamiento de búfer de heap en dec_frm_prepare de OpenAPV. Misma clase, mismo decodificador que CVE-2026-0006, el RCE de APV de cero clics explotado en el mundo real a principios de este año.
El laboratorio empaqueta esa escritura como un juego. Desborda el plano Y codificado de 64×64, destroza un objeto de sesión adyacente, redirige el teardown hacia handlers[2], y el Worker devuelve la flag.
El kit son dos zips del laboratorio:
streambox-lab.apk.zip — el reproductormake_clip.py.zip — cómo se construyeron los clips de la librería de 64×64, y el bitstream que desbordas
PlayerActivity hace:
NativeDec.setVideoTitle(name);
status = NativeDec.loadClip(path);
// WebView bridge later calls Android.openTier(status)
openTier(1) es un impacto parcial (sesión tocada, token no coincide). openTier(2) es win(). PremiumActivity envía por POST el estado nativo al laboratorio:
POST /api/unlock
{
"instance_id": <from POST /api/instance>,
"tier": 3,
"session_hex": hex(sessionProof[64]),
"ticket": HMAC-SHA256(ticketKey, instance_id + ":" + session_hex)
}
Al arrancar, la app ya hizo POST /api/instance y NativeDec.setPlatinumToken(token). Ese token es lo que el desbordamiento tiene que escribir en la sesión.

arena = calloc(1, 0x206040);
session = arena + pad + 0x2000;
*(uint64_t *)session = 0x53545245414D424F; /* bytes: "OBMAERTS" */
El oapv_imgb_t está codificado como 64×64, YUV de 10 bits. El plano 0 (Y) empieza en arena+0. 64 × 64 × 2 = 0x2000. Con pad == 0, la sesión se sitúa en el primer byte después de Y.
oapvd_decode() escribe al ancho/alto del FRAME PBU. Un FRAME más alto que 64 escribe muestras de 10 bits directamente en session.
Tras el decode:
if (session->token == g_token) { /* +0x08 */
if (session->handler <= 2) /* +0x0c */
g_handlers[session->handler](); /* [2] == win() */
} else if (session->token != 0) {
g_premium = 1;
}
memcpy(g_session_proof, session, 64);
return g_platinum ? 2 : g_premium ? 1 : 0;

El generador del laboratorio dibuja 32 fotogramas de RGB de 64×64, convierte a yuv422p10le, y lanza el codificador de referencia OpenAPV:
oapv_app_enc -i anim.yuv -w 64 -h 64 -z 8 --input-csp 2 -d 10 -o out.apv -v 1
Cada clip incluido son 32 unidades de acceso de FRAME 64×64:
[u32be au_size] ['aPv1' + PBUs] × 32

El reproductor sigue asignando 64×64. Parchea cada frame_height de AU de 64 → 72:
python3 scripts/patch_frame_height.py clip_pulse.apv -o overflow_height72.apv --height 72
Compártelo (SEND / VIEW / streambox://?url=). La auto-reproducción es el exploit.
Un desbordamiento más limpio es editar H en make_clip.py a 72 o 128 y recodificar para que las filas Y extra sean datos de imagen reales. La fila 64 de un plano de 10 bits de 64 de ancho son 128 bytes:
OBMAERTS)g_token)2APV es con pérdida; los valores exactos de 10 bits a través de oapv_app_enc requieren QP 0 / casi sin pérdida.
PoC público relacionado para la clase de fallo padre: mobilehackinglab/CVE-2026-0006-openapv-poc.
El urllib de Python recibe Cloudflare 1010. curl con un UA móvil funciona.
El Worker rechaza el magic original con no overflow evidence: session magic intact. El ASCII STREAMBO (bytes distintos del uint64 LE) cuenta como escritura.

# fill TICKET_KEY in scripts/unlock.py from NativeDec.ticketKey()
python3 scripts/unlock.py
win() es lo que muestra el reproductor cuando loadClip devuelve 2:

dec_frm_prepareNotas de laboratorio autorizadas para el ejercicio StreamBox de Mobile Hacking Lab. Sin APK, sin tokens activos, sin flag. No ejecutes estas primitivas contra nada que no poseas o tengas permiso para probar.