IoT Security 11 · ファームウェア抽出とデバッグポート

Chapter 11

ファームウェア抽出とデバッグポート

この章がなぜ必要なのか——攻撃は、ほぼ必ずここから始まるから.

09 章のサイドチャネルも、10 章のフォールトも、 まずファームウェアを読んで、狙う場所を特定するところから始まる。

そして実務では——ファームウェアを読まれた時点で、 ハードコードされた鍵やパスワードが出てきて、それで終わることが非常に多い。

ここを塞ぐことが、費用対効果の最も高い対策である。

この章で使う既出の用語(定義は各リンク先). 数万円(01 章 2 節)、物理攻撃(04 章 6 節)、OTFDEC(06 章 6 節)、Secure(07 章 3 節)、TrustZone(07 章 2 節)、サイドチャネル(07 章 8 節)、フォールト(07 章 8 節)、両方(07 章 3 節)、必要(09 章 6 節)

1. ファームウェアはどこから漏れるか

ファームウェアを手に入れる経路 — 安い順に塞ぐ公開ファイルメーカーのサポートサイトから更新ファイルを落とす0 円UART コンソールテストパッドに USB シリアルを繋いで起動ログとシェルを取る数百円SPI フラッシュクリップを挟んで基板上から読む、または外して読む数千円JTAG / SWDデバッグポートからメモリを読む数千円グリッチ保護ビットの読み出しを飛ばす(10 章)数万円チップ解析開封して FIB・レーザー・プロービング数百万円〜上の 3 つは道具代がほぼゼロ。ここを塞がずに高度な対策をしても意味がない
攻撃者は必ず一番安い経路から来る。費用対効果の高い対策は、実はいちばん地味なところにある

デバッグポートとファームウェア抽出経路

各経路をクリックすると、攻撃の手順と対策が表示される。

経路難度必要なもの
メーカーの公開ファームウェア★(最も簡単)ブラウザ
OTA の通信を傍受★ネットワーク解析
UART コンソール★USB シリアル変換(数百円)
SWD / JTAG★★デバッガ(数千円)
外付け SPI/NAND フラッシュを読む★★クリップ、プログラマ(数千円)
ISP / ブートローダモード(工場書き込みモード。6 節)★★ベンダのツール
保護をグリッチで突破★★★グリッチ装置(数万円、10 章)
チップ開封 + プロービング★★★★★専用ラボ(数百万円〜)

上から 5 つは、すべて「設定ミス」で開く.

つまり追加の部品コストをかけずに塞げる。 ここを塞がずに暗号アクセラレータの議論をしても意味がない。

2. 経路 1: 公開ファームウェアと OTA

最も見落とされる経路である。

状況問題
サポートサイトで更新ファイルを配布誰でもダウンロードして解析できる
OTA が平文 HTTP通信を傍受すれば手に入る
OTA が暗号化されていないTLS で運ばれても、ファイル自体は平文
# 攻撃者がやること(イメージ)
$ binwalk firmware.bin          # 中身の構造を調べる
$ binwalk -e firmware.bin       # ファイルシステムを展開
$ strings firmware.bin | grep -i -E 'key|passwd|secret|token|BEGIN'
$ grep -r "AWS" extracted/      # クラウドの認証情報を探す

対策:

対策内容章
OTA イメージを暗号化する機器だけが復号できる形にする13
機器ごとに違う鍵で暗号化難しいが、可能な場合もある13
とにかく秘密を埋め込まない最も重要。鍵は実行時にプロビジョニングされたものを使う06, 12

「暗号化すれば安全」ではない.

OTA イメージを暗号化しても、全機器が同じ鍵で復号するなら、 1 台から鍵を取れば全イメージが復号できる。

だから「イメージの暗号化」は時間稼ぎであって、根本対策ではない。 根本対策は「ファームウェアに秘密を含めないこと」である。

秘密(機器固有鍵、証明書)は、 工場でのプロビジョニング(12 章)か、初回起動時の生成で入れる。 ファームウェアイメージには入れない。

3. 経路 2: UART コンソール

基板を見ると、4 ピンのパターン(VCC・GND・TX・RX)がよく残っている。

  1. 基板のテストパッドやピンヘッダを探す
  2. USB シリアル変換を繋ぎ、ボーレートを総当たりする(9600〜921600)
  3. 起動ログが流れてくる → ブートローダの種類、カーネル、ファイルシステム構成が分かる
  4. Enter を押す → シェルプロンプトが出ることがある
  5. ブートローダで起動を中断 → 起動引数を書き換えて init=/bin/sh
よくある問題対策
起動ログに詳細情報が出る量産ビルドではログレベルを下げる
シェルが出る量産ビルドではコンソールを無効化する
パスワードがあるが弱い/共通機器固有にするか、そもそも無効化する
ブートローダで停止できるブートローダの対話機能を無効化する
パッドが残っている量産基板ではパッドを削除する、または結線を切る
/* ビルド設定で切り分ける */
#ifdef PRODUCTION_BUILD
    #define DEBUG_CONSOLE_ENABLED   0
    #define LOG_LEVEL               LOG_ERROR
#else
    #define DEBUG_CONSOLE_ENABLED   1
    #define LOG_LEVEL               LOG_DEBUG
#endif

「デバッグ機能をコンパイル時に除去する」ことが重要である.

実行時のフラグで無効化するだけでは、 コードが残っているのでグリッチや脆弱性で有効化されうる。

量産ビルドには、そもそもコードを含めない。 リンカマップを見て、デバッグ用シンボルが残っていないか確認するとよい。

4. 経路 3: SWD / JTAG

最も直接的な経路である。 デバッガを繋げば、

保護の方法

方法内容
読み出し保護(RDP / CRP / FSEC)フラッシュ読み出しを禁止する(06 章)
デバッグポートの無効化ヒューズ/オプションバイトで完全に閉じる
認証付きデバッグ (Secure Debug)鍵を持つ者だけがデバッグを開ける
物理的な切断量産基板でパターンを切る、テストパッドを削除する

認証付きデバッグ

閉じるか開けるかの二択ではなく、「認証すれば開く」という第 3 の道である。

デバッグ認証 — 「閉じる」ではなく「鍵を持つ人だけ開ける」デバッガデバイスチャレンジ要求乱数チャレンジ毎回変える(リプレイ防止)秘密鍵で署名する署名 + 証明書OTP の公開鍵で検証OK → デバッグポートを開く(権限も証明書で指定)完全に閉じてしまうと自社も解析できない。認証つきで開けられるようにしておく
ライフサイクル状態で完全に閉じるか、認証つきで開けるか。故障解析の体制と併せて決める
標準・実装内容
Arm ADAC (Authenticated Debug Access Control)Arm が定めた認証デバッグの仕様
NXP Debug AuthenticationLPC55 / i.MX RT で提供
ST Debug AuthenticationSTM32H5 / U5 などで提供
Silicon Labs Secure Debug UnlockSecure Vault の機能
Nordic品種による

認証付きデバッグは、RMA(返品分析)の切り札である.

14 章で詳しく扱うが、 「量産品を完全にロックすると、故障解析ができない」という深刻な問題がある。

認証付きデバッグなら——

これがあるかどうかは、SoC 選定の重要な基準である。

5. 経路 4: 外付けフラッシュ

外付けフラッシュ — MCU がどれだけ堅牢でも別のチップである平文で置いた場合MCU堅牢SPI FlashW25QxxSCK/IOSOIC クリップその場で数分でダンプロジックアナライザバスを流れる中身が読めるXIP で実行していれば、実行中のコードがそのままバスに流れるオンザフライ復号を使うMCU鍵は内部SPI Flash暗号文のみ暗号文鍵は MCU 内から出ない読んでも暗号文「起動時だけ復号」では足りない。常時暗号化されたまま転送される必要がある最も確実なのは、本当に守りたいものを内部フラッシュに置くこと
外付けフラッシュは基板上で誰でも触れる。取り外さなくてもバスを盗聴すれば中身が流れるので、対策は「常時暗号化」しかない

MCU がどれだけ堅牢でも、外付けフラッシュは別のチップである。

  1. SPI フラッシュ(W25Qxx、MX25Lxx など)を基板上で特定する
  2. SOIC クリップ(基板に載ったままのチップへ上から挟んで配線を取り出す治具)を付けてその場で読む、またはホットエアで外してプログラマで読む
  3. 数分でフルダンプが取れる
対策効果
フラッシュ暗号化(06 章)内容が読めない。鍵は MCU 内にある
オンザフライ復号(OTFDEC / PRINCE / BEE / Flash Encryption)XIP でも暗号化できる
重要な部分を内部フラッシュに置く最も確実
BGA パッケージのフラッシュ若干難しくなるが、外せる

バスの盗聴も可能である.

フラッシュを外さなくても、SPI バスにロジックアナライザを繋げば 転送内容が読める。XIP で実行していれば、実行中のコードがそのまま流れる。

だから「起動時だけ復号する」のでは足りない。 常時暗号化されたまま転送される必要がある。 これがオンザフライ復号エンジンの役割である。

6. 経路 5: ISP / ブートローダモード

多くの MCU が、工場書き込み用の ROM ブートローダを持っている。 基板に実装したまま外部から書き込める仕組みなので ISP(In-System Programming)と呼ばれる。

経路例
UART ブートローダBOOT ピンを引いて起動すると、UART から書き込める
USB DFU(Device Firmware Upgrade)USB 経由でファームウェアを書き込める
SDP(Serial Download Protocol)NXP i.MX の ROM 機能

これらは「書き込み」だけでなく「読み出し」もできる場合がある。

対策内容
ROM ブートローダを無効化OTP / オプションバイトで無効にする
ブートソースを固定内部フラッシュからしか起動しないよう固定
BOOT ピンを固定基板でプルダウン/プルアップして固定する
読み出し保護と連動保護レベルが上がると ROM ローダの読み出しも禁止される(品種による)

必ずデータシートで「保護レベルと ROM ブートローダの関係」を確認すること.

「フラッシュ読み出し保護をかけたのに、 ROM ブートローダ経由では読めた」という事故が起こりうる。

特に、保護をかけても「消去」はできる設計になっていることが多い。 消去は攻撃者にとって直接の利益にならないが、 消去 → 保護解除 → 自分のコードを書き込んで、外付けフラッシュを読ませる という 2 段構えの攻撃が成立する場合がある。

7. RAM に残る秘密

RAM に残る秘密 — フラッシュを守っても実行中は平文であるRAM 上の鍵平文の鍵が存在する区間復号/導出使用zeroize() で消去電源断SRAM の内容はしばらく残る(冷却すると更に伸びる)この区間だけが攻撃対象デバッガで読む・コールドブート対策: 使ったら必ず消す/起動時に SRAM をクリアタンパー検出時の自動消去があれば更に良い
鍵が平文で存在する時間を最短にするのが基本。リセットでは SRAM がクリアされない MCU があるので、起動時のクリアも必要になる

フラッシュを守っても、実行中の RAM には平文の鍵が乗っている。

攻撃内容
デバッガで RAM を読む上記の SWD/JTAG 対策で防ぐ
コールドブート攻撃電源断直後の DRAM/SRAM には内容が残る。冷却すると保持時間が伸びる
リセット後の SRAM 読み出しリセットでは SRAM がクリアされない MCU がある

対策:

/* 使い終わった鍵は必ず消す([08 章](08_暗号エンジンと乱数.md#落とし穴-2-dma-と共有バス)) */
mbedtls_platform_zeroize(session_key, sizeof(session_key));

/* リセット時・起動時に SRAM をクリアする */
void SystemInit(void) {
    extern uint32_t _sram_start, _sram_end;
    for (uint32_t *p = &_sram_start; p < &_sram_end; p++) *p = 0;
}
ハードウェア対策内容
タンパー検出時の SRAM 消去筐体開放などを検出したら即座に消す
バックアップレジスタの自動消去ST の tamper 機能など
TrustRAM(Microchip SAM L11)スクランブル格納、サイレントアクセス、タンパ時消去
セキュア SRAMTrustZone で Secure 属性にした領域

8. ファームウェアの解析を難しくする

塞ぎきれない前提で、解析コストを上げるという考え方もある。

手法効果注意
シンボル・デバッグ情報の除去必須。関数名が消えるだけで解析コストが数倍になるstrip、-g を外す
文字列の暗号化strings で情報が出なくなる実行時に復号するコードが要る
コード難読化逆コンパイルを困難にする商用ツールが必要。デバッグが難しくなる
制御フロー平坦化静的解析を困難にする性能が落ちる

難読化は「セキュリティ」ではなく「時間稼ぎ」である.

Security through obscurity(隠すことによる安全)は原則として避けるべきである。 暗号鍵や認証の強度を難読化に依存してはいけない。

ただし、正しい対策の上に追加で載せる分には価値がある。 特にシンボルの除去は、コストゼロで効果が大きいので必ずやること。

# リリースビルドでは必ず
arm-none-eabi-strip --strip-all firmware.elf
# マップファイルを確認して、デバッグ用シンボルが残っていないか見る

9. 出荷前チェックリスト

この章の内容は、そのままチェックリストになる。

#確認項目
1SWD / JTAG が無効化されているか(または認証付きデバッグに設定されているか)
2読み出し保護が有効か。レベルは適切か
3ROM ブートローダ/ISP が無効化されているか
4UART コンソールが無効化されているか(コード自体が入っていないか)
5デバッグ用のコマンド・バックドアが除去されているか
6外付けフラッシュが暗号化されているか
7ファームウェアに秘密(鍵・パスワード・トークン)が埋まっていないか
8シンボル・デバッグ情報が除去されているか
9公開する更新ファイルから秘密が読めないか
10RAM の秘密が使用後に消去されているか
11テストパッド/ピンヘッダが量産基板から削除されているか
12保護設定がフォールト耐性を持つか(10 章)

7 番目の確認方法.

# 出荷イメージに対して、必ず実行する
strings firmware.bin | grep -i -E 'password|passwd|secret|api[_-]?key|token|BEGIN (RSA|EC|PRIVATE)'
binwalk -E firmware.bin      # エントロピーを見る(高エントロピー領域 = 鍵かもしれない)

CI に組み込んで、毎ビルドで自動チェックすること。 人間のレビューでは必ず見落とす。

より本格的には、シークレットスキャナ(gitleaks、trufflehog など)を ソースとビルド成果物の両方に対して回す。

10. この章のまとめ

ポイント内容
攻撃の起点ほぼすべての物理攻撃がファームウェア解析から始まる
最も安い経路公開ファームウェア、UART、SWD、外付けフラッシュ。設定で塞げる
根本対策ファームウェアに秘密を埋め込まない。イメージ暗号化は時間稼ぎ
UART量産ビルドからコードごと除去する。実行時フラグでは不十分
SWD / JTAG無効化するか、認証付きデバッグ(Arm ADAC など)を使う
認証付きデバッグRMA 対応の切り札。選定基準に入れるべき
外付けフラッシュ外せば数分で読める。オンザフライ復号が必要
ROM ブートローダ無効化する。「保護してもブートローダから読めた」事故に注意
RAM の秘密使用後に zeroize。起動時に SRAM クリア
難読化セキュリティではなく時間稼ぎ。ただしシンボル除去は必須
検証CI で strings とシークレットスキャンを自動化する

ここまでで第 III 部は終わりである。 次章から第 IV 部——機器の一生を通した鍵と状態の管理に入る。