← Back to Blog

FirmVulnFlow:AI 驱动的 IoT 固件漏洞挖掘管线

0x00 背景

IoT 固件安全研究是一个高度重复的流程:下载固件、binwalk 解包、找到关键二进制、strings 看一眼、IDA 打开逆向、发现漏洞点、QEMU 模拟验证、写报告。每个步骤都有大量的命令行操作和人工判断。

这些步骤虽然流程化,但细节极多。FirmVulnFlow 的设计目标是:把整个固件漏洞研究流程封装成 MCP 工具,让 AI Agent 能自主完成从固件下载到 PoC 验证的全流程。

替代研究员做的那些重复性操作——解包、字符串提取、xref 分析、QEMU 配置、NVRAM 编译部署这些。研究员只需要在关键决策点介入:选择分析目标、确认 IDA 反编译结果、判断漏洞是否可利用。

0x01 架构总览

整个系统基于 MCP(Model Context Protocol) 构建。

项目结构:

FirmVulnFlow/
├── src/firmvulnflow/
│   ├── common/                 # 共享配置、数据库、日志
│   ├── firmware_manager/       # MCP Server: 固件下载与管理
│   ├── firmware_extractor/     # MCP Server: 固件解包与分析
│   ├── vuln_database/          # MCP Server: CVE/PoC 查询
│   ├── binary_diff/            # MCP Server: 二进制比对
│   └── firmware_emulator/      # MCP Server: QEMU 全系统模拟
├── .claude/commands/           # Skill 文件(工作流编排)
│   ├── vuln-discovery.md
│   ├── emulate-firmware.md
│   ├── cross-model-vuln-hunt.md
│   └── patch-bypass-analysis.md
├── data/
│   ├── firmwares/              # 下载的固件文件
│   └── extracted/              # 解包后的文件系统
└── tools/                      # 辅助工具、sysroot 缓存

核心设计:5 个 MCP Server 提供 34 个原子工具,4 个 Skill 文件编排完整工作流。

MCP Server 负责”怎么做”——每个工具做一件具体的事。Skill 文件负责定义完整的多步骤研究流程,指导 Agent 按什么顺序调用哪些工具、如何处理异常、何时请求人工介入。

0x02 五个 MCP Server

firmware-manager:固件生命周期管理

4 个工具。处理固件的下载、注册、搜索和版本比对。

# .mcp.json 配置
"firmware-manager": {
    "command": ".venv/bin/python",
    "args": ["-m", "firmvulnflow.firmware_manager.server"]
}
工具用途
download_firmware下载固件文件,注册到本地 SQLite manifest
list_local_firmwares列出所有已下载的固件
search_firmware按品牌/关键词搜索本地 manifest
diff_firmware_versions同型号不同版本的文件级 diff

数据模型很简单——一个 SQLite 表存 model、version、brand、firmware_path、extracted_path。所有路径遵循统一约定:

data/firmwares/{model}_{version}/          # 原始固件
data/extracted/{brand}/{model}_{version}/  # 解包产物
    ├── rootfs/                            # 文件系统根
    └── kernel/                            # 内核镜像

路径标准化看起来不起眼,但在整个流程中至关重要——Agent 不需要猜路径,每个工具都能通过 model+version 自动定位文件。

firmware-extractor:解包与静态分析

5 个工具。封装 binwalk 做递归解包,提供 ELF 分析能力。

工具用途
extract_firmware端到端解包:支持多层嵌套(zip→.web→.bin→squashfs),自动定位文件系统根并复制到标准路径
list_binaries列出所有 ELF 可执行文件,含架构信息
list_shared_libraries列出所有 .so 共享库
find_cgi_handlers定位 CGI 处理程序(cstecgi.cgi、apply.cgi 等)
extract_strings提取二进制中的可打印字符串

extract_firmware 是最复杂的一个。很多路由器固件的打包格式层层嵌套——外层 zip,里面一个 .web 容器,再里面才是 squashfs 镜像。binwalk 递归解包后产出的目录名也五花八门(squashfs-root、jffs2-root、cpio-root……)。这个工具自动处理这些差异,输出统一的 rootfs/ 目录。

vuln-database:漏洞情报

4 个工具。对接 NVD API 和 GitHub,提供 CVE 查询和 PoC 获取。

工具用途
search_cve通过 CPE 或关键词搜索 CVE,本地缓存
get_cve_detail获取 CVE 完整详情、CVSS 评分、分类引用
fetch_poc从 GitHub 仓库和 exploit-db 聚合 PoC 代码
list_known_vuln_patterns列出厂商的常见漏洞模式

fetch_poc 不只是返回链接——它会直接读取 GitHub 仓库的 README 和脚本内容、解析 exploit-db 页面的代码。Agent 拿到的是可以直接参考的完整 PoC 源码,而不是一个需要手动打开的 URL。

search_cve 支持两种模式(CPE 和关键词),NVD 的 CPE 条目经常不全或命名不一致,只用 CPE 搜索会漏掉大量已知 CVE。两种模式并行搜索、结果合并,才能接近完整覆盖。

binary-diff:二进制比对

4 个工具。基于 radare2 做函数级和指令级 diff。

工具用途
diff_binaries两个 ELF 的函数级对比(函数列表、大小差异)
diff_functions单个函数的指令级 diff
identify_patched_functions识别两个版本之间被修补的函数
find_vuln_handlers找到调用危险函数(system、popen)的所有 caller,附带引用字符串

find_vuln_handlers 是漏洞挖掘中最常用的工具。它做的事情很直接:用 radare2 的交叉引用找到所有调用 system()popen() 的函数,然后提取每个 caller 引用的字符串。

使用 radare2 只能做精度比较低的识别,后续的详细分析需要借助IDA Pro MCP。

firmware-emulator:QEMU 全系统模拟

17 个工具,是整个项目最复杂的部分。通过 SSH 在远程 Linux 服务器上管理 QEMU 全系统模拟。

"firmware-emulator": {
    "command": ".venv/bin/python",
    "args": ["-m", "firmvulnflow.firmware_emulator.server"],
    "env": {"SUSER": "", "SERVER": ""}
}

工具按功能分四组:

生命周期管理:

工具用途
init_workspace初始化远程服务器目录结构
start_emulation启动 QEMU,创建 tmux session
stop_emulation停止模拟
check_emulation_status检查 session 状态
list_emulation_sessions列出所有活跃 session
wait_for_boot轮询等待 guest 启动完成

Guest 交互:

工具用途
send_console_command向 QEMU 控制台发送命令
capture_console_output捕获控制台输出
clear_console清空 tmux 缓冲区
exec_in_chroot在固件 chroot 环境内执行命令

Rootfs 注入:

工具用途
transfer_rootfs打包 rootfs 为 tarball,启动临时 HTTP 服务
inject_firmware_rootfsGuest 内下载、解压、挂载 /dev /proc /sys 等

环境配置:

工具用途
analyze_init_scripts解析 rcS/inittab,确定 web 服务类型
check_nvram_dependencies扫描二进制的 NVRAM 符号依赖
detect_nvram_config检测架构、libc、NVRAM API 类型
setup_nvram_emulation全自动 NVRAM 模拟:检测→编译→部署→验证
auto_setup_web_env一键配置 web 运行环境

每个固件型号对应一个独立的 tmux session。用 user-mode 网络做端口转发(host:8080 → guest:80),-snapshot 模式保护磁盘镜像不被修改。

0x03 四个 Skill 工作流

MCP 工具是砖块,Skill 是蓝图。每个 Skill 是一个详细的多步骤工作流程文档(Markdown),通过 Claude 的 /command 机制加载,指导 Agent 完成一个完整的研究任务。

/vuln-discovery — 独立漏洞挖掘

从零开始对一个固件进行系统性漏洞挖掘。7 步:

解包固件 → 攻击面识别 → radare2 xref 初筛(候选列表)
→ IDA 反编译验证(确认/证伪) → CVE 去重 → QEMU 模拟验证 → 报告

四层递进验证

  1. radare2 自动扫描——产出候选列表
  2. IDA Pro 反编译——确认或证伪每个候选的数据流
  3. CVE 去重——确保是新漏洞
  4. QEMU 动态验证——运行时证据

/emulate-firmware — 全系统模拟

把一个固件跑起来,让 web 服务可访问。9 步:

初始化工作区 → 查询固件 → 解包 → 分析启动配置
→ 启动 QEMU → 等待启动登录 → 传输 rootfs
→ NVRAM 配置 + 启动服务 → 验证可访问性

这个 Skill 最难的部分是 Step 7(NVRAM 模拟),后面单独展开讲。

/cross-model-vuln-hunt — 跨型号漏洞传播

已知某型号有漏洞,检查同品牌其他型号是否也有。7 步:

漏洞情报收集 → 获取多型号固件 → 解包
→ 分析已知漏洞特征 → 跨型号比对 → 模拟验证 → 报告

同一厂家的不同产品可能用的同一套底层库,所以跨型号漏洞传播还挺常见的

/patch-bypass-analysis — 补丁绕过分析

分析厂商的漏洞修复是否可以绕过。8 步:

漏洞情报 → 获取新旧版本固件 → 解包 → radare2 diff 定位变化
→ IDA 逐函数对比新旧伪代码 → 绕过可行性评估 → QEMU 验证 → 报告

有些漏洞修复的比较敷衍,比如只加一部分黑名单、只修一个参数、只修一个入口。

0x04 模拟系统设计

总体架构

固件模拟的核心思路是用一个通用的 Debian MIPSEL/ARM 虚拟机当壳,把目标固件的文件系统塞进去,在 chroot 里跑固件的服务进程。

不是模拟整块路由器硬件,只模拟到能让 web 服务跑起来接收请求的程度。

┌─ macOS Host ─────────────────────────────────────────────┐
│                                                          │
│  Claude Code + MCP Servers                               │
│       │                                                  │
│       │ SSH                                              │
│       ▼                                                  │
│  ┌─ Linux Server ──────────────────────────────────────┐ │
│  │                                                     │ │
│  │  tmux session: "A950RG"                             │ │
│  │  ┌─ QEMU (qemu-system-mipsel) ───────────────────┐ │ │
│  │  │                                                │ │ │
│  │  │  Debian MIPSEL Guest (malta)                   │ │ │
│  │  │  ┌─ chroot /rootfs ─────────────────────────┐  │ │ │
│  │  │  │                                          │  │ │ │
│  │  │  │  固件文件系统                              │  │ │ │
│  │  │  │  ├─ /usr/sbin/httpd                      │  │ │ │
│  │  │  │  ├─ /usr/sbin/cstecgi.cgi                │  │ │ │
│  │  │  │  ├─ /lib/libapmib.so  ← NVRAM hook 替换  │  │ │ │
│  │  │  │  └─ /tmp/nvram/       ← 文件 KV 存储     │  │ │ │
│  │  │  │                                          │  │ │ │
│  │  │  │  mount: /dev /proc /sys /tmp             │  │ │ │
│  │  │  └──────────────────────────────────────────┘  │ │ │
│  │  │                                                │ │ │
│  │  │  user-mode network: host:8080 → guest:80       │ │ │
│  │  │  -snapshot: 磁盘镜像只读                         │ │ │
│  │  └────────────────────────────────────────────────┘ │ │
│  └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘

整个流程分几步:

  1. 启动 QEMU:在远程 Linux 服务器上创建 tmux session,用 Debian MIPSEL 内核 + 磁盘镜像启动一个完整的 Linux guest。-snapshot 模式保护磁盘镜像不被修改,每次重启都是干净状态。

  2. 注入 rootfs:把固件文件系统打包成 tarball,通过 QEMU user-mode 网络的 HTTP 传输到 guest 内部,解压到 /rootfs。然后 mount bind /dev/proc/sys,挂载 tmpfs 到 /tmp/var/run——构造一个最小可用的 chroot 环境。

  3. 处理硬件依赖:chroot 环境虽然有了文件系统,但固件二进制依赖的硬件接口全都不存在。最关键的是 NVRAM——几乎所有路由器服务启动时都会读取 NVRAM 配置。需要编译一个 hook 库来模拟 NVRAM 读写。

  4. 启动服务:在 chroot 内启动 web 服务,通过端口转发从外部访问。

同一个 Debian 镜像可以跑所有 MIPSEL 架构的固件,不需要为每个型号适配不同的虚拟机。代价是模拟精度不高,guest 内核是标准 Debian 而非厂商定制内核,硬件外设全部缺失。但对安全研究来说够用了,能验证漏洞。

接下来讲几个落地时最难处理的部分。

NVRAM Hook

IoT 固件模拟的最大障碍不是 QEMU 本身,而是固件对硬件的依赖。路由器固件几乎都依赖 NVRAM(非易失性 RAM)存储配置。没有 NVRAM 支持,web 服务启动就会 crash。

多种实现

不同厂商用不同的配置存储 API,部分例子:

API 类型厂商芯片平台特点
nvram_get/setBroadcom 系BCM47xx/53xx字符串 KV,最常见
apmib_get/setRealtek 系RTL8196E/8197D数字 MIB ID,值可以是整数或字符串
cfm_get/setBroadcom DSL 系本质是 nvram 的别名
cdb_get/setRealtek RTL9600 系本质是 nvram 的别名

detect_nvram_config 会自动检测固件用的是哪种 API,setup_nvram_emulation 生成对应的 hook 库。

拦截策略

根据固件的 libc 类型选择不同策略:

LD_PRELOAD 策略:

编译一个 .so,在启动服务时用 LD_PRELOAD 注入,拦截 nvram_get/nvram_set 等符号。优点是不修改原始文件系统。

LD_PRELOAD=/tmp/libnvram_hook.so /usr/sbin/httpd

Library Replacement 策略:

LD_PRELOAD 不可靠时,直接替换导出 NVRAM 符号的原始 .so。备份原库 → 编译替代库 → 覆盖原库位置 → 替代库内部用 dlopen 加载备份库转发非 NVRAM 符号。

// library_replacement 模板中的转发逻辑
static void *_orig_lib = NULL;
static void _load_orig(void) {
    if (!_orig_lib)
        _orig_lib = dlopen("/lib/libapmib.so.bak", RTLD_LAZY);
}
// 非 NVRAM 符号通过 dlsym 转发到原库
交叉编译的两个维度

编译 NVRAM hook 库需要同时匹配两个维度:

架构 (architecture)  ×  libc 实现 (C runtime)
   mipsel                  glibc
   mips                    uClibc
   arm                     musl
   aarch64                 ...

这两个维度相互独立。mipsel + glibc 的 .so 放到 mipsel + uClibc 的固件里,动态链接器会静默拒绝加载——不报错,服务直接 crash。

detect_nvram_config 同时检测这两个维度:通过 ELF header 确定架构,通过动态链接器字符串确定 libc 类型和版本。

构建级联

build_nvram_library 按优先级尝试编译:

Priority 1: tools/sysroots/{arch}-{libc}/ 缓存有匹配的 sysroot
            → 用系统交叉编译器 + --sysroot 编译 LD_PRELOAD 模板

Priority 2: glibc 固件
            → 系统交叉编译器直接编译(自带 sysroot)

Priority 3: 返回 need_libc_source
            → 附带说明:交叉编译器已有,缺 libc 的 sysroot
            → 三个选项:下载预编译 sysroot / 编译 libc 源码 / -nostdlib fallback

Priority 3 不会静默降级,Agent 会拿到 need_libc_source 状态,然后询问用户如何获取匹配的 libc源码。这是刻意的设计:让人来做这个需要判断的决策,而不是让程序猜。

Library Replacement 的测试与回滚

替换原库是个危险操作——如果替代库 ABI 不兼容,整个 chroot 环境就废了。所以部署时有完整的安全网:

# 部署流程
1. 备份原库:cp libapmib.so libapmib.so.bak
2. 替换:cp hook.so libapmib.so
3. 烟雾测试:chroot /rootfs sh -c "ls /tmp"
4. 测试失败 → 自动回滚:cp libapmib.so.bak libapmib.so

烟雾测试的逻辑很简单——跑一个依赖 libc 的命令(ls),如果 chroot 环境崩了(SEGV、ABRT、链接器报错),说明替代库有问题,立刻回滚。

数据符号

NVRAM 相关的共享库不只导出函数,还导出全局变量。比如 Realtek 的 libapmib.so 导出 pMib(指向 MIB 数据库的指针)、mib_table(MIB 配置表)、wlan_idx(无线网卡索引)等。

如果替代库没有导出这些数据符号,依赖它们的二进制在运行时会因为符号解析失败而 crash。

detect_nvram_configreadelf --dyn-syms 采集 OBJECT 类型的符号(不只是 nm -D 的函数符号),然后 _generate_data_stubs 自动生成 C 声明:

// 自动生成的数据符号桩
static char _pMib_buffer[262144];       // 256KB 静态缓冲区
void *pMib = _pMib_buffer;              // 指针指向缓冲区,避免 NULL 解引用

int wlan_idx = 0;                       // 整数符号,零初始化
int mib_table[4] = {0};                 // 数组符号,零初始化

指针类型分配足够大的静态缓冲区(pMib 这种通常指向几百 KB 的配置数据库),整数和数组零初始化。这些桩不提供真实功能,但足够让依赖这些符号的二进制正常启动——而对于安全研究来说,只要 web 服务能跑起来接收请求就够了。

零 libc 依赖的模板

TEMPLATE_LIBRARY_REPLACEMENT 是一个完全不依赖 libc 的 C 模板。文件 I/O 全部用内联汇编做 raw syscall:

// MIPSEL 架构的 raw syscall 内联汇编
static inline long _raw_syscall3(long n, long a, long b, long c) {
    register long r4 __asm__("$4") = a;
    register long r5 __asm__("$5") = b;
    register long r6 __asm__("$6") = c;
    register long r2 __asm__("$2") = n;
    __asm__ volatile("syscall" : "+r"(r2) : "r"(r4),"r"(r5),"r"(r6)
                     : "$7","$8","$9","$10","$11","$12","$13","$14","$15",
                       "$24","$25","memory");
    return r2;
}

为什么这么做?因为 library_replacement 策略是替换原库——如果替代库本身又依赖 libc,而原库也是 libc 链接的一部分,就会形成循环依赖。用 raw syscall 的字符串比较、文件读写完全绕开 libc。

NVRAM 值存储在 /tmp/nvram/<key> 文件中,每个 key 一个文件。nvram_get 先查内存缓存(64 slot 的 key-value 数组),miss 时读文件。nvram_set 写文件 + 更新缓存。

不同的 NVRAM API 类型有不同的处理:

// nvram_get/set — 字符串 KV
char *nvram_get(const char *key) {
    // 查缓存 → miss 则读 /tmp/nvram/{key}
}

// apmib_get/set — 数字 MIB ID,第三个参数是目标缓冲区
int apmib_get(int id, void *value, int len) {
    // 读 /tmp/apmib/{id},memcpy 到 value
}

/proc 下的特殊文件依赖绕过

NVRAM 不是唯一的硬件依赖。很多路由器固件的守护进程在启动时会读取 /proc 下的硬件特有文件——这些文件由厂商内核模块注册,QEMU 的通用 Debian 内核里根本不存在。

例如某路由器 的 sysconf 在执行 init gw wan(初始化 WAN 网关)时会访问:

  • /proc/rtl_dnstrap — Realtek DNS trap 控制
  • /proc/br_igmpProxy — IGMP 代理配置
  • /proc/fast_pppoe — PPPoE 快速路径

这三个都是 Realtek RTL8196E 内核模块注册的 procfs 接口。QEMU guest 里没有这些文件,sysconf 直接 SIGSEGV(RC=139)。

inject_firmware_rootfs 在 chroot 里挂载的是 QEMU guest 的真实 /proc

f"mount -t proc /proc /{rootfs_basename}/proc"

这个 /proc 来自 Debian MIPSEL 内核,只有标准 Linux proc 条目,没有任何 Realtek 专有的硬件接口。

AI Agent 发现某个二进制因为缺失 /proc 文件而崩溃时,会自行调用 IDA Pro MCP进行判断,并进行 patch 尝试。

NVRAM API 碎片化、/proc 下的文件每个厂商完全不同、libc 不兼容导致 .so 静默加载失败——这些问题没有通用的自动化方案,但 AI Agent 可以看到报错信息(SIGSEGV、dlopen 失败、符号找不到),结合 IDA 反编译理解缺了什么,然后决定是创建 fake 文件、patch 二进制、还是绕过这个组件走其他验证路径。传统的固件模拟框架碰到这类问题就直接失败。而 AI Agent 的优势在于它能阅读错误理解上下文并做出判断——这恰恰是硬件碎片化场景下最需要的能力。

0x05 工具之外的智能

在真实的固件模拟过程中,大量问题是没有标准答案的。把一个固件的 web 服务完整跑起来,中间会碰到各种意想不到的阻塞,每一个都需要判断:这个问题值不值得修?怎么修?还是绕过去?这些判断全部由 AI Agent完成。 模型的基础推理能力是整个系统能正确运行的关键前提,工具只是手脚,AI Agent 才是大脑。

理解完整的服务启动链

例如某路由器的 web 服务不是简单的 httpd + cstecgi.cgi,而是一个基于 MQTT 消息分发的 CSTE 框架:

lighttpd → cstecgi.cgi → mosquitto_pub(topic)

cs_broker (mosquitto 1.4.8) → 消息路由

cste_sub → dlopen("cste_modules/*.so") → handler 函数

sysconf → 实际执行配置变更

这个架构完全没有文档。模型需要通过 IDA 反编译一步步逆向出来:cstecgi.cgiweb_getData() 发布到什么 topic、cste_sub 订阅什么 topic、load_modules() 怎么加载 handler、get_action() 怎么从 topic 里提取函数名。

整个过程开了 8 个 IDA session,在多个二进制之间交叉分析才理清了这条链路,模型必须自己读懂反编译代码,理解组件间的依赖关系,然后决定启动顺序。

模拟中的取舍

模拟过程中碰到的障碍,不是每个都值得花时间解决。模型需要对每个阻塞点做成本收益判断:

值得修的例子——MQTT topic 不匹配:

cste_sub 默认只订阅 "cste" topic,但 cstecgi.cgi 发布到的是 "totolink/router/{topicurl}"。消息根本到不了 handler。

模型通过 IDA 分析 web_getData() 发现了正确的 topic 格式,fix 很简单——启动 cste_sub 时加 -t "totolink/router/#" 参数。成本低,收益高(不修就完全不通),必须修。

不值得修、直接用 MQTT 替代 HTTP 的例子——lighttpd + cstecgi.cgi 联调:

让 lighttpd 正确路由请求到 cstecgi.cgi,涉及配置文件调整、CGI 环境变量设置、模块加载等一系列问题。模型判断:漏洞验证不一定要走 HTTP。 CSTE 架构的核心是 MQTT 消息分发——直接用 mosquitto_pub 发消息到对应 topic,效果等价于通过 HTTP + cstecgi.cgi 的完整链路:

mosquitto_pub -h 127.0.0.1 -t "totolink/router/setting/setDiagnosisCfg" \
  -m '{"topicurl":"setting/setDiagnosisCfg",
       "ipDoamin":"127.0.0.1 -w 1\necho PWNED > /tmp/diag_rce\n#"}'

这个决策省了大量的 lighttpd 调试时间,而且 MQTT 层的验证同样可以证明漏洞存在。

工具与模型

MCP 工具提供的是可靠的原子操作:解包不会出错、radare2 xref 不会漏、NVRAM 编译部署流程是确定性的。

模型提供的是不确定环境中的判断力:理解未知架构、决定修什么绕什么、在多种验证方式中选择最高效的、从错误中修正。

两者缺一不可。只有工具没有模型,面对 非标准架构束手无策。只有模型没有工具,每次都要手动敲 binwalk、radare2、qemu 命令,效率极低。

Skill 文档的不是脚本,而是经验。 它不是告诉模型机械地执行 step 1→2→3,而是告诉模型:这类任务通常怎么做、常见的坑是什么、什么时候需要人工介入。模型在执行过程中有充分的自由度来调整策略——跳过某些步骤、切换验证方式、甚至推翻自己之前的结论。

0x06 数据流管线

一次完整的漏洞挖掘,数据流是这样的:

[firmware-manager] 下载固件

[firmware-extractor] binwalk 解包 → rootfs/

[firmware-extractor] find_cgi_handlers → 定位关键二进制
[firmware-extractor] extract_strings → 提取字符串特征

[binary-diff] find_vuln_handlers → 危险函数 xref 初筛
        ↓ 候选列表
[IDA Pro MCP] decompile/xrefs_to → 反编译验证每个候选
        ↓ 确认/证伪
[vuln-database] search_cve + fetch_poc → CVE 去重
        ↓ 新漏洞
[firmware-emulator] QEMU 模拟 → 动态验证

输出:结构化漏洞报告 + PoC

每个工具只做一件事,Skill 文件把它们串起来。工具之间通过标准化路径(data/extracted/{brand}/{model}_{version}/rootfs/)和数据库(SQLite manifest)共享状态。

0x07 IDA Pro MCP 集成

单纯依赖 radare2 做静态分析是不够的。IDA Pro 通过 MCP 集成,提供反编译和深度分析能力。

在 Skill 工作流中,IDA 的角色是验证者而不是发现者

  1. radare2 的 find_vuln_handlers 找到候选
  2. idalib_open 加载目标二进制(支持同时打开多个文件,用 idalib_switch 切换)
  3. decompile 获取伪代码,逐一回答 radare2 无法回答的问题
  4. 对每个候选给出 CONFIRMED / DISPROVED / WEAKENED / NEEDS_DYNAMIC 结论
  5. idalib_close 关闭 session

这个二级验证机制在实践中非常有效。某路由器的研究中,radare2 初筛出了 20+ 个 system() caller,IDA 验证后只有 5 个真正可利用——其他的要么实际走 execve(不经 shell,无法注入),要么输入经过 gethostbynameinet_ntoa 转换后已经不可控。

0x08 当前局限性

无法识别内存破坏漏洞

当前的分析能力集中在逻辑漏洞——命令注入、认证绕过、信息泄露这些。对于缓冲区溢出、堆溢出、格式化字符串漏洞等内存破坏类漏洞,目前的工具链力不从心。

原因很简单:

  1. radare2 xref 只能找到 strcpy/sprintf 的 caller,但判断是否存在溢出需要理解缓冲区大小和输入长度的关系——这需要更精细的数据流分析
  2. IDA 伪代码可以看到栈变量的大小,但自动化判断”这个 sprintf 是否能溢出这个 128 字节的缓冲区”仍然困难
  3. 最关键的是:即使静态分析认为可能溢出,没有运行时验证就不能确认——stack canary、ASLR、编译选项都会影响可利用性,需要用调试工具进行更详细的调试

find_vuln_handlers 目前对 sprintf/strcpy/strcat 的分析精度远低于对 system()/popen() 的分析。后者只需要确认”用户输入到达了 system 参数”,前者还需要额外计算缓冲区边界。

经验积累不足

目前实际完整跑通的固件样本太少。Skill 文档中的经验主要来自几个特定品牌的型号,覆盖的芯片平台只有 Broadcom 和 Realtek,架构只有 MIPSEL。这意味着模型在面对新厂商、新平台的固件时,缺乏足够的先验知识来指导 AI Agent 高效决策。直接后果是大量 token 消耗在重复试错上——每次模拟失败都要重新分析报错、调整编译参数、重新部署测试。比如碰到非标准的 web 服务架构(不是 httpd/lighttpd + CGI 的常见模式)时,模型需要花费大量上下文窗口通过 IDA 逆向来理解组件间的依赖关系,才能找到正确的启动方式。

0x09 后续计划:GDB Server 集成

下一步是集成 gdbserver 到 QEMU 模拟环境中,补上内存破坏漏洞的验证能力。

计划的架构:

[QEMU Guest]                    [Host]
┌──────────────────┐           ┌──────────────────┐
│ chroot /rootfs   │           │                  │
│   ├─ gdbserver   │←─ SSH ──→│  GDB MCP Server  │
│   │  :1234       │   tunnel  │   (新 MCP)       │
│   └─ target_bin  │           │                  │
└──────────────────┘           └──────────────────┘

有了 gdbserver 支持,验证流程可以扩展为:

radare2 初筛 sprintf/strcpy caller
    → IDA 确认缓冲区大小 vs 输入长度
    → GDB 设断点在 sprintf 处
    → 发送超长输入
    → GDB 检查是否覆盖了返回地址 / canary
    → 确认可利用性

另外还考虑加入 strace 的系统化集成——目前在 Skill 文档中只是作为辅助手段提及,后续可以作为 MCP 工具正式封装,用于二阶注入的数据流追踪。

0x0A 总结

FirmVulnFlow 的核心思路是:把 IoT 安全研究中的重复性操作封装成 MCP 工具,让 AI Agent 自主编排完成全流程,人只在关键决策点介入。

但工具只是一半。另一半是模型本身的推理能力——理解未知固件架构、判断执行阻塞的修复策略、在多种验证方式中选择最高效的路径、从自身的判断错误中修正。工具提供可靠的原子操作,模型提供不确定环境中的决策力,两者结合才是完整的能力。

5 个 MCP Server 覆盖从固件获取到动态验证的完整链路。4 个 Skill 工作流把 34 个原子工具组合成可执行的研究方案。NVRAM 模拟子系统解决了固件模拟中最棘手的硬件依赖问题。Skill 文档沉淀了实战经验,让模型在面对新固件时不需要从零摸索。

目前对逻辑漏洞(命令注入、认证绕过)的发现效率已经很高。下一步通过 gdbserver 集成补齐内存破坏漏洞的能力,让整个系统覆盖更完整的漏洞类型。