
CVE-2024-20154の技術解説記事。MediaTek MT6769 NB-IoTベースバンドファームウェアにおけるスタックベースのバッファオーバーフローを分析し、リバースエンジニアリングとエクスプロイトチェーンを扱う。
分類: CWE-121 — スタックベースのバッファオーバーフロー
深刻度: Critical (MediaTek セキュリティ速報) · 8.8 High、攻撃ベクター: 隣接 (CISA-ADP)
種類: リモートコード実行 — ユーザー操作不要、事前関連付け不要
開示: MediaTek セキュリティ速報、2025年1月6日 https://corp.mediatek.com/product-security-bulletin/January-2025
分析対象: Samsung Galaxy A14 SM-A145R — MT6769ファミリー (Helio G80)、MediaTekの影響を受けるチップセットリスト内 - ファームウェアは安全な条件下でエミュレートされた。
ステータス: 修正済み。
これは私にとって初めて公開したベースバンド研究だった。私は通信インフラ、 合法的傍受の仲介レイヤー、スティングレイやIMSIキャッチャーの分析、 組み込みデバイスセキュリティとは縁遠いバックグラウンドを持っており、セルラーモデムに対する 深いファームウェアリバースエンジニアリングを行ったことはなかった。私は、構造化された分析 手法がターゲットを問わず適応できること、そして特定のプラットフォームへの習熟が 厳密なチェーン追跡によって代替可能であることを自分自身に証明したかった。NB-IoTが際立っていたのは、 それが真に危険な交差点に位置しているからだ。このプロトコルは制約のあるIoTデバイス向けに設計されており、 攻撃対象領域は事前関連付け段階にあり、モデムスタックは携帯電話のユーザーが何をしていようと それを処理する。
修正済みファームウェアが分析され、脆弱なパターンが存在しないことが確認されたとき、 特定の機能をターゲットにする前にファームウェアの大量分析に使用されたAIシステムは、
再構築されたバグクラス、条件、影響を受けるファームウェアファミリーを、CVE-2024-20154の説明と
独立して一致させた。
技術的な結論はアナリスト自身のものである。
あなたのポケットの中の電話には、少なくとも2台の別々のコンピュータが入っている。あなたが操作する 一方はAndroidを実行している。もう一方 — ベースバンド — は完全に独立して動作し、すべての無線 通信を処理し、その上のオペレーティングシステムからはほぼ完全に見えない。Androidは 完全にパッチ適用済みかもしれない。ブラウザはサンドボックス化されているかもしれない。ユーザーは 悪意のあるリンクを一度もタップしないかもしれない。脆弱なコードが、アプリケーションプロセッサが関与する前に 無線信号を処理するモデムファームウェアの中にあるなら、そんなことはすべて問題にならない。
CVE-2024-20154はまさにその種の脆弱性である。
不正な形式のNB-IoTシステム情報ブロードキャストは、MediaTekモデムファームウェアに、攻撃者が制御する スケジューリングカウントを受け入れさせ、そのカウントを一切クランプすることなくRRCからL1への設定 パスを通して運ばせ、最終的にNB-IoTブロードキャストチャネルハンドラ内のスタック書き込み ループのループ境界として使用させる。カウントが宛先 配列の容量を超えると、ループはそれらを越えて書き込み、スタック上の保存されたレジスタに到達し、 保存されたリターンアドレスを上書きする。その後、関数は破損した値を リターンアドレスレジスタに復元し、そこへジャンプする。
深刻度をこのレベルにしている要因:
この脆弱性は、MediaTekの2025年1月6日のセキュリティ速報で Critical深刻度評価とともに公開され、とりわけLR12Aモデムファミリーに影響を与えた。Samsungは この修正を2025年2月のセキュリティメンテナンスリリースに組み込んだ。
本記事は武器化されたエクスプロイトを公開するものではなく、ここに 公開された内容から再現可能なものでもない。 目的は、チェーンがどこで破綻するのか、なぜ各レイヤーが それを止められなかったのか、そしてライブモデムにデバッガをアタッチできないときに ベースバンドのバグを責任を持って検証するために何が必要かを示すことである。
主要ターゲット: Samsung Galaxy A14 (SM-A145R)。無線サブシステムは、MT6769チップセット ファミリー (Helio G80) のMediaTekベースバンドプロセッサによって駆動される。MT6769ファミリーは、 CVE-2024-20154についてMediaTekの影響を受けるチップセットリストに明示的に 記載されている。``` AP/CP firmware: A145RXXU1AWD1 Modem software: MOLY LR12A.R3.TC10.6M.A14.PR.SP.V1.P5 Build date: 2023-04-18
ベースバンドファームウェアはAndroidコードではありません。これはSoCの無線サブシステム上にある独立した組み込みシステムであり、独自のCPU、独自のRTOS、独自のメモリ空間を持ち、Androidプロセスサンドボックスの外側に存在します。
### 2.2 モデムアーキテクチャ
抽出されたバイナリの解析により、モデムプロセッサはリトルエンディアンモードでMIPS16e2圧縮命令を備えたMIPS32を実行していることが示されています。MIPS16e2は、組み込みコードのサイズ削減のための16ビットエンコーディング拡張であり、Helio世代のベースバンドに対するMediaTekのアプローチと一致しており、このSoCファミリーに関する独立した公開ベースバンド研究によって確認されています。
オペレーティングシステムはNucleus RTOSであり、タスクスケジューリング、IPCメッセージキュー、およびプールベースのメモリアロケータを提供します。カーネル/ユーザー特権分離はなく、タスク間のメモリ保護ユニットの強制もなく、ハードウェアスタックガード機構もありません。
この記事のすべてのアドレスは、Ghidraでベース`0x90000000`としてロードされた仮想アドレスです。
### 2.3 緩和策(解析されたビルドで観測)
| 緩和策 | 状態 | 効果 |
|---|---|---|
| ASLR | なし | ファームウェアアドレスは静的で、イメージから予測可能 |
| スタックカナリア | なし | `SAVE`/`RESTORE`はガード値なしで呼び出し先保存レジスタを格納する |
| NX / W^X | なし | スタックメモリが実行可能 |
| CFI | なし | 戻りアドレスがいかなるポリシーに対しても検証されない |
### 2.4 解析アプローチ
3つの並行トラック:
**静的解析。** Samsungファームウェアパッケージ → CPパーティション抽出 → `md1img.img` → Ghidra(MIPS LE 32ビット、ベース`0x90000000`)、NCC Groupの`mtk_bp`ツールセットを使用してファームウェアデバッグセクションから復元されたMediaTekエンジニアリングシンボル付き。
**動的検証。** Unicorn Engine(MIPS32エミュレーション)を使用して、2つのフェーズにわたって特定のファームウェアルーチンを分離して実行しました。フェーズ1では、ネイティブ命令ペアを介して`si_count`のクランプされていないコピーをチャネルコンテキストに証明しようとしました。フェーズ2では、実際のファームウェアバイト上で脆弱なループを実行し、ファームウェア自身の命令が保存された戻りアドレスを破壊することを確認しました。フェーズ1が完全にネイティブで実行できなかった箇所では — CPHYディスパッチパスが必要とするRTOSサービスオブジェクト環境が再構築されなかったため — 副作用を直接モデル化し、すべての出力でそのようにラベル付けしました。
**無線側の検証。** ZMQループバックを備えたsrsRAN 4G — ソフトウェアのみ、RF放射なし — により、テストペイロードがNB-IoT PHYエンコーディングとトランスポートブロック配信を経ても存続することを確認しました。
---
## 3. 攻撃表面:NB-IoTとSIB1-NB
### 3.1 事前関連付け攻撃表面
NB-IoT(Narrowband Internet of Things)は3GPP Release 13であり、既存のライセンスLTEスペクトルを使用して制約されたIoTデバイスを接続するように設計されています。これは、消費者向けスマートフォンを含む幅広い現代のセルラーSoCに実装されています。
RRC_IDLE中、RRC接続が確立される前に、サービスを検索しているデバイスは以下を行います:
1. セルのタイミング信号(NPSS/NSSS)と同期する
2. NPBCHを介してMaster Information Blockをデコードする(640 ms送信ウィンドウ)
3. NPDSCHからSIB1-NBをデコードする(2560 msスケジュール)
4. SIB1-NBのスケジューリング情報を使用して、追加のシステム情報ブロックを特定する
ステップ3で、モデムは認証していないエンティティからのメッセージを、いかなる接続やユーザー操作の前にも処理します。通常のセル選択条件を満たす不正な送信機が処理されます。```
+------------------+ +---------------------+
| Rogue Base Stn | | Target UE (Modem) |
+--------+---------+ +----------+----------+
| |
| NPSS/NSSS sync |
|--------------------------------------->|
| MIB-NB (640 ms cycle) |
|--------------------------------------->|
| SIB1-NB (malformed, si_count > 8) |
|--------------------------------------->| ← vulnerability triggered
| [no RRC connection established] |
SIB1-NB は 3GPP TS 36.331 で定義されています。その schedulingInfoList フィールドは、セルがブロードキャストする System Information メッセージの数を保持しており、仕様により最大 8 エントリ(1..maxSI-Message-NB-r13 = 8)に制限されています。これはプロトコル層の制約です。メモリ安全性の制約 — リスト長が宛先配列の容量を超えてはならないという制約 — は、ファームウェアによって別途強制されなければなりません。
それは行われていませんでした。
ファームウェアは Samsung CP パッケージから入手し、NCC Group の mtk_bp ツールセットを使用して抽出しました:```
md1img.img → md1_extract.py → 000_md1rom (17.8 MB code image)
→ 017_md1_dbginfo (XZ-compressed CATI debug symbols)
CATI デバッグセクションは `mtk_dbg_extract.py symbols` で展開および解析され、その後
`ImportSymbolsScript.py` を介して Ghidra にインポートされました。その結果、モデムスタック全体
— ERRC レイヤー、L1 チャネル管理、IPC サブシステム、および NB-IoT BCCH ハンドラチェーン —
にわたって完全な内部関数名が得られ、セマンティクスに基づくチェーンの再構築が可能になりました。
この記事内のすべての関数名は、ファームウェアイメージから抽出された MediaTek 自身の
埋め込みデバッグシンボルに由来します。
---
## 5. 脆弱性
### 5.1 脆弱なループ
`el1_ch_nbcch_resume_req` (`0x90213940`) は NB-IoT ブロードキャストチャネル再開イベントを
処理します。その MIPS16e2 関数プロローグ:```asm
90213940: save 0xE8, ra, s0-s1
SAVE 命令は sp を 0xE8 だけデクリメントし、呼び出し先保存レジスタを下方へ格納します:```
old_sp (= new_sp + 0xE8)
new_sp + 0xE4 saved ra ← overflow target
new_sp + 0xE0 saved s1
new_sp + 0xDC saved s0
new_sp + 0x98 si_sched_arr [34 halfwords = 68 bytes]
new_sp + 0x78 si_type_arr [32 bytes]
new_sp + 0x00 ← stack pointer after SAVE
実際のファームウェアバイナリのGhidra逆コンパイルより:```c
for (uVar6 = 0; uVar6 < (byte)param_2[0x40a]; uVar6 = uVar6 + 1) {
si_type_arr[uVar6] = /* SI type byte */; // 1 byte/iter, base new_sp+0x78
si_sched_arr[uVar6] = /* SI schedule halfword */; // 2 bytes/iter, base new_sp+0x98
}
param_2[0x40a] は ch_ctx[+0x40A] です — チャネルコンテキストの BSS 構造体内の永続バイトです。
ループ境界は直接使用され、配列の容量との事前比較は行われません。
ストリーム A(ハーフワード sh 書き込み)は new_sp+0x98 から始まり、反復ごとに 2 バイトずつ進みます。
これは反復 38 で new_sp+0xE4 にある保存された RA に到達します:```
new_sp + 0x98 + i×2 = new_sp + 0xE4
i = (0xE4 - 0x98) / 2 = 0x4C / 2 = 38
Stream B(バイト `sb` の書き込み)は `new_sp+0x78` から始まり、RA スロットに到達するにはイテレーション 108 が必要です:```
new_sp + 0x78 + i = new_sp + 0xE4
i = 0xE4 - 0x78 = 108
si_count = 40(デモンストレータ値、オーバーフロー閾値38を超えるように選択)の場合、
ループは40回実行される。ストリームBはRAスロットに到達しない。RAの破壊は
完全にストリームAに起因する。
40回のイテレーション後、MIPS16e2 の RESTORE 命令が破壊された値をスタックから
$ra に再ロードし、jrc ra が制御を転送する。
ch_ctx[+0x40A] は 0x90213444 の el1_ch_nbcch_start によって書き込まれる。間に何も
挟まない2つの連続するMIPS命令:```asm
; el1_ch_nbcch_start @ 0x90213444
lbu v0, 0x99(s0) ; read IPC_msg[+0x99] = si_count from CPHY_CFG_REQ
sb v0, 0x40A(s1) ; write to ch_ctx[+0x40A] — no clamp, no mask, no compare
### 5.4 ERRCビルダー — レイヤーA
CPHY_CFG_REQバッファは、デコードされたSIB1-NBからERRCレイヤーで構築されます。関数
`errc_chm_l1_set_bcch_si_reception`は`IPC_msg[+0x99]`を書き込みます:```c
// errc_chm_l1_set_bcch_si_reception — Layer A
// Loop bound: decoded schedulingInfoList entry count from SIB1-NB
while (bVar3 < *(byte *)(param_3 + 0x44) && (param_2 != 0)) {
bVar3++;
if (uVar2 != param_2) {
*param_5 = *param_5 + 1; // CPHY_CFG_REQ[+0x99]++ — no upper bound check
}
}
ループの上限はSIB1-NBからデコードされたエントリ数である。カウンタはデコードされたエントリごとに1回インクリメントされ、デコードされたエントリ数だけ繰り返され、最大値のガードは存在しない。
CPHY_CFG_REQバッファが設定されると、ERRCはルーティングキーとしてsap_id = 0x501Fを指定してL1にディスパッチする:```
el1_ch_rcv_ilm (sap 0x501F)
→ el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C]
→ el1_chmgm_nbcch_handler
→ el1_ch_nbcch_main
→ el1_ch_nbcch_cphy_cfg_req_process ← validates cell identity, no si_count check
→ el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp
### 5.6 クランプの3層にわたる不在
| 層 | 機能 | アドレス | クランプの有無 |
|---|---|---|---|
| A — ERRCビルダー | `errc_chm_l1_set_bcch_si_reception` | ERRC範囲 | **なし** |
| B — L1コピー | `el1_ch_nbcch_start` | `0x90213444` | **なし** |
| C — L1ループ | `el1_ch_nbcch_resume_req` | `0x90213940` | **なし** |
いずれか1つの層でのチェックが1つでもあれば、この連鎖は断ち切られていたはずである。
### 5.7 根本原因
1つの不変条件が破られている:
> SIスケジューリングエントリの数は、決して宛先配列の容量を超えてはならない。
3GPPは意図されたプロトコル上の上限(8エントリ)を提供している。ファームウェアは、カウントがインデックスやループ限界となるすべての層で、メモリ安全性の上限を強制する必要があった。脆弱なビルドでは、カウントはSIB1-NBブロードキャストフィールドからERRCデコーダを通り、CPHY_CFG_REQメッセージに入り、IPC境界を越えてL1タスクに入り、チャネルコンテキストBSSに入り、スタック書き込みループに至るまで、どの層でもクランプされることなく伝播した。
---
## 6. コールチェーン — どのように発見されたか
### 6.1 2つのパスの混同
構造的に類似しているが異なる2つのパスが、0x760バイトの設定バッファを`el1_ch_nbcch_main`に届ける可能性がある:
| パス | ソース | `[+0x99]`の値 | 関連性 |
|---|---|---|---|
| パスA(ERRC → L1 IPC) | ERRCがデコードされたSIB1-NBからCPHY_CFG_REQを構築 | OTAからの`schedulingInfoList.count` | **脆弱なパス** |
| パスB(L1内部) | `el1_ch_scs_ind_send`が内部IPCボディを構築 | ハードコードされた`1` | 脆弱ではない |
パスBはメッセージフォーマットを確認した — バイト`+0x99`は`el1_ch_nbcch_start`が消費するSIカウントである。そのカウントは常に1にハードコードされているため、オーバーフローすることはできない。外部から影響を受けるパスはパスAである。
### 6.2 ライターの探索
オフセット`+0x99`に書き込む命令をファームウェアからパターン検索すると、ノイズが発生した:T1(直接`sb`、約100ヒット)、T2(分割ベース、5ヒット)、T3(計算オフセット、0)、T4(重複する`sh`/`sw`、約465)。ERRCのチャネル管理関数は`msg_send6`のクロスリファレンスリストに存在しなかった。それはERRCが`errc_com_send_msg`を使用しているためである。エミュレーションプローブにより、書き込みがERRC側であることが確認された:L1ディスパッチャからUnicornハーネスを実行し、バッファの`+0x99`オフセットへの書き込みを監視しても、L1側からは何も捕捉されなかった。```
[RUN] dispatcher=0x90214418 watching IPC_msg+0x99
NO writes to IPC_msg+0x99 caught from dispatcher.
Write happened before el1_ch_nbcch_main — confirmed ERRC-side.
errc_com_send_msg 内の sap_id = 0x501F を追跡することで、el1_chmgm_errc_cfg_req_in_idle へのルーティングが特定された。これは CPHY_CFG_REQ ポインタを L1_ctx[+0x323C] に格納し、下流のディスパッチを開始する。
SIB1-NB schedulingInfoList.count (demonstrator: 40) │ ▼ [ERRC task] errc_chm_ch_ctrl_req_hdlr → errc_chm_call_ctrl → errc_chm_l1_main → errc_chm_l1_call_ctrl → errc_chm_l1_snd_cphy_cfg_req ← allocates 0x760-byte CPHY_CFG_REQ → errc_chm_l1_set_cphy_req_nbcch_cfg → errc_chm_l1_set_bcch_inf → errc_chm_l1_set_bcch_si_reception ← Layer A: CPHY_CFG_REQ[+0x99] = 40 → errc_com_send_msg(sap=0x501F) ← IPC to L1 │ ▼ [L1 task] el1_ch_rcv_ilm (sap 0x501F) → el1_chmgm_errc_cfg_req_in_idle ← stores CPHY_CFG_REQ @ L1_ctx[+0x323C] → el1_chmgm_nbcch_handler → el1_ch_nbcch_main → el1_ch_nbcch_cphy_cfg_req_process ← no si_count validation → el1_ch_nbcch_start @ 0x90213444 ← Layer B: lbu + sb, no clamp │ ▼ ch_ctx[0x40A] = 40 (persists in BSS) │ ▼ [state machine advances to 0x0B, event 0x2C] el1_ch_nbcch_resume_req @ 0x90213940 ← Layer C: loop bound from ch_ctx[0x40A] │ ▼ stack overflow → jrc ra → PC = attacker-controlled
---
## 7. 検証
この特定の SM-A145R モデルは、通常の出荷ビルド動作では脆弱な NB-IoT コードパスを実行しないと考えられる。そのため、直接的なハードウェア再現ではなく、ハイブリッドエミュレーションと静的解析が用いられた。
**静的に証明済み。** ファームウェアバイナリには脆弱な命令ペアが含まれている。コールチェーンはシンボル、クロスリファレンス、およびデコンパイルされた関数本体から再構築された。
**エミュレーション内でネイティブ実行済み。** `el1_ch_nbcch_resume_req` 内のループは、Unicorn Engine (MIPS32) 上で実際の MediaTek ファームウェアバイトに対して実行された。ファームウェア自身の `sh` 命令が `0x90213B02` で保存されたリターンアドレススロットに書き込んだ。`RESTORE` 命令が破損した値を `$ra` にロードし、`jrc ra` が制御を転送した。
**明示的にモデル化済み。** `el1_ch_nbcch_start` 内の `lbu`/`sb` コピーは、完全にネイティブで実行することができなかった。なぜなら `el1_ch_nbcch_cphy_cfg_req_process` 内の RTOS コールバックテーブルディスパッチパスが、フラットエミュレータが提供しないライブの Nucleus ヒープオブジェクトを期待していたためである。フェーズ 2 のレジュームハンドラ (`el1_ch_nbcch_resume_req`) は BSS 常駐のチャネルコンテキストからのみ読み取り、同じディスパッチパスに到達しない。これがフェーズ 2 が同じ足場を必要とせずネイティブで実行された理由である。フェーズ 1 の副作用 — `IPC_msg[+0x99]` から `ch_ctx[+0x40A]` への 1 バイトの書き込み — は直接モデル化され、`[PHASE1-MODEL]` とラベル付けされた。
**主張しない。** 完全なエンドツーエンドの無線ハードウェア再現。
### 7.1 耐タンパ性
ハーネスは 1 つのルールを強制した: フックが保存されたリターンアドレススロットにプルーフマーカーを書き込むことは許可されなかった。ファームウェア以外のすべてのメモリ書き込みが追跡された。```
[PROOF-W] saved_RA write: pc=0x90213b02 addr=new_sp+0xE4 value=0xbeef
[PROOF-W] saved_RA write: pc=0x90213b02 addr=new_sp+0xE6 value=0xdead
[ANTI-TAMPER] no hook wrote RA=0xDEADBEEF — firmware only
anti_tamper_fail = False
0x90213B02 はループ本体内部の sh 命令です。ファームウェアはこれらのバイトを
予測されたスタックオフセットに配置しました。リトルエンディアン格納では、new_sp+0xE4 と
new_sp+0xE6 にあるハーフワード 0xBEEF と 0xDEAD が結合して [ef be ad de] = 0xDEADBEEF になります。
[REGS] RA = 0xdeadbeef ← firmware wrote this; decisive proof PC = 0x00000000 ← Unicorn unmapped-fetch artifact, not a hardware exception vector
[STACK] new_sp+0xE4: [ef be ad de] ← little-endian 0xDEADBEEF
[PC-EXPLAIN] PC=0 is an unmapped-fetch artifact; decisive proof is RA=0xDEADBEEF + stack bytes [ef be ad de] + [PROOF-JRC] CONFIRMED: saved RA = 0xDEADBEEF
### 7.3 ZMQ配信
テストペイロードがNB-IoT PHYエンコーディングおよびトランスポートブロック配信を経ても維持されることを確認するため、ZMQループバック(RF放射なし)を備えたsrsRAN 4Gを使用した。ペイロードは意図的に非準拠のベクターであり、`schedulingInfoList`のASN.1 SIZE制約を緩和して40エントリを許可し、pycrateのラウンドトリップデコードによりバイト14のカウントフィールドを確認した。```
SIB1 received
SIB2 activated
exit 0
これによりトランスポート層での配信が確認される。ファームウェア側のASN.1の挙動は、 Layer Aの静的解析によって確立されている。
el1_chタスクは1つのスタックを持つ。フェーズ1とフェーズ2は、同じタスクによって
順次処理される2つの別個のIPCイベントであり、その間でスタックは完全に巻き戻される。カウントは
スタック上ではなく、チャネルコンテキストのBSSに永続する:```
EVENT: CPHY_CFG_REQ (Phase 1)
el1_ch_nbcch_start
lbu v0, 0x99(s0)
sb v0, 0x40A(s1) ← ch_ctx[0x40A] = attacker value, written to BSS
returns — stack fully unwound
EVENT: resume (state 0x0B, msg 0x2C) (Phase 2) el1_ch_nbcch_resume_req ← frame 0xE8, reads ch_ctx[0x40A] as loop bound loop × 40 → saved RA corrupted jrc ra → attacker-controlled PC
`ch_ctx[0x40A]` は BSS に存在し、モデムがリセットされるか、後続のチャネル設定によって上書きされるまで、攻撃者の値を保持し続けます。
### 8.2 スタックフレーム```
old_sp (= new_sp + 0xE8)
new_sp + 0xE4 saved ra
new_sp + 0xE0 saved s1
new_sp + 0xDC saved s0
new_sp + 0x98 si_sched_arr [34 halfwords = 68 bytes]
new_sp + 0x78 si_type_arr [32 bytes]
フレームサイズはエミュレーション計測により確認済み。配列位置はエミュレーション結果により確認済み — RA はイテレーション 38 で書き込まれており、si_sched_arr が new_sp+0x98 から始まることと一致する。
| ビルド | モデムファームウェア | ビルド日 |
|---|---|---|
| 脆弱版 | A145RXXU1AWD1、MOLY LR12A...V1.P5 | 2023-04-18 |
| パッチ版 | A145RXXUDDZC2、MOLY LR12A...V3.P8 | 2025-04-23 |
ビルド日は両方のイメージから md1_dbginfo メタデータを抽出して確認済み。パッチ ID:
MOLY00720348 · Issue ID: MSV-2392。
el1_ch_nbcch_start(脆弱版バイナリでは 0x90213444): lbu/sb 命令ペアが
存在しない。IPC_msg[+0x99] から ch_ctx[+0x40A] への直接コピーが削除されている。
el1_ch_nbcch_resume_req(脆弱版バイナリでは 0x90213940): ch_ctx[0x40A] に対する
スタック書き込みループが存在しない。信頼できないバイトが固定サイズのスタック配列に対する
ループ境界となるアーキテクチャはもはや存在しない。関数本体は別のディスパッチ構造に
置き換えられている。
errc_chm_l1_set_bcch_si_reception: 無制限のカウンタループが検証指向のヘルパー呼び出しに
置き換えられている。
パッチ版バイナリに存在し、脆弱版バイナリには存在しない 2 つの関数:``` el1_ch_nbcch_param_check el1_ch_scell_param_check
単一行の境界チェックは、同じアドレスの既存関数内に追加される数個の命令として現れるはずである。パッチ適用済みバイナリが示しているのはアーキテクチャ上の改訂である。NBCCH スケジューリングパスは再設計され、`si_count` をループ境界として使うパターンがパス内のどこにも存在しなくなった。
### 10.4 CVE の帰属
ここで説明する脆弱性は、MediaTek が 2025 年 1 月 6 日に公開した CVE-2024-20154 に一致する。確認の根拠:
- 影響を受けるファームウェアファミリ (LR12A) が MediaTek のブリテンに一致する。
- 脆弱性クラス — スタックオーバーフロー、境界チェックの欠如、悪意ある基地局からの RCE、ユーザー操作不要 — が CVE の説明および NVD レコードに一致する。
- パッチ適用済みファームウェアは、脆弱と特定されたコード構造を正確に除去している。
- パッチ ID MOLY00720348 が MediaTek のブリテンおよび Android Security Bulletin (A-376809176) から確認された。
- AI 支援による分析は、手動確認の前に、再構築されたパターンを独立に CVE-2024-20154 に一致させた。
---
## 11. 倫理と責任ある開示
### 11.1 本記事に含まれないもの
武器化されたエクスプロイトは含まれない。ファームウェアバイナリの内容は含まれない。不正なペイロードバイトは含まれない。稼働中のデバイスに対して脆弱性をトリガーするための手順は含まれない。実際に動作する攻撃を再現するために必要な情報 — 特定のモデムデコーダ向けの完全なペイロード構築、完全な Phase 1 エミュレーションのための RTOS ヒープオブジェクトの足場、無線設定 — は意図的に欠落させている。
### 11.2 ZMQ ループバックとエミュレーションが倫理的なアプローチである理由
ZMQ ループバックとは、信号が無線で送信されることが一切なかったことを意味する。実デバイスは標的にされていない。キャリアネットワークは関与していない。この実証は、アナリストが所有するハードウェア上の完全に閉じたソフトウェア環境で実行される。これは、事前関連付け段階の無線脆弱性を検証するための正しいアプローチである — 不正なブロードキャストを送信すれば、範囲内のあらゆるデバイスに影響を与えることになる。
Unicorn エミュレーションは、脆弱な挙動がファームウェアバイナリ自体に存在することを、特定のデバイス状態や無線環境に依存せず、再現可能に示す。これは単一のハードウェアクラッシュよりも技術的に強い主張であり、無線で何かを配備することを避けている。
### 11.3 MediaTek の知的財産
すべての分析は、消費者向けデバイスから正当に入手したファームウェア、および Samsung が公開リリースしたファームウェアパッケージに対して実施された。独自のドキュメントは使用していない。MediaTek の内部構造体定義および IPC メッセージフォーマットは、メモリ安全性の失敗を説明するために必要な範囲でのみ記述している。それらを仕様として公開するものではない。
---
| イテレーション | sh の書き込み先 | 影響 |
|---|
| 0–33 | si_sched_arr[0..33] | 範囲内 |
| 34–35 | new_sp+0xDC — 保存された s0 | s0 が破壊される |
| 36–37 | new_sp+0xE0 — 保存された s1 | s1 が破壊される |
| 38 | new_sp+0xE4 — 保存された ra [15:0] | RA 下位ハーフワード |
| 39 | new_sp+0xE6 — 保存された ra [31:16] | RA 上位ハーフワード |
| ゲート | 条件 | チェック箇所 |
|---|
| NB-IoT アクティブパス | cfg_type == 1 | el1_ch_nbcch_cphy_cfg_req_process |
| チャネル未完了 | done_flag == 0 | ch_ctx[0x438] |
ステートマシン 0x0B | NBCCH がレジューム状態 | el1_ch_nbcch_main ディスパッチ |
| si_count が非ゼロ | ch_ctx[0x40A] > 0 | ループ条件 |
| バンドクラス ≤ 2 | 有効な NB-IoT モード | el1_ch_nbcch_resume_req のエントリ |
el1_chmgm_cell_info_get が非ゼロ | セルがサービス表に存在 | el1_ch_nbcch_start 内で呼び出し |
| 関数 | アドレス | 役割 | クランプ? |
|---|
errc_chm_l1_set_bcch_si_reception | ERRC 範囲 | CPHY_CFG_REQ[+0x99] を書き込む | なし |
el1_ch_nbcch_cphy_cfg_req_process | 0x90213F80 | CPHY 設定を L1 にルーティング | N/A — si_count を読み取らない |
el1_chmgm_cell_info_get | 0x9020E0D0 | EARFCN/PCI を検証 | N/A |
el1_ch_nbcch_start | 0x90213444 | カウントを BSS にコピー | なし |
el1_ch_nbcch_resume_req | 0x90213940 | カウントをループ境界として使用 | なし |