
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に起因する。
| イテレーション | 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 上位ハーフワード |
40回のイテレーション後、MIPS16e2 の RESTORE 命令が破壊された値をスタックから
$ra に再ロードし、jrc ra が制御を転送する。