一、先交代问题设定
首篇推文(《FirmAudit2:从解包到 CNVD 交付,固件漏洞审计流水线》)讲的是固件审计那条线:上传一份路由器固件,平台替你走完解包、静态、仿真、验证,最后打包出一份能直接交 CNVD 的资料。
但有我在宿舍突发奇想,考虑另一个场景:如果手里不是一份固件,而是一整张系统盘/系统镜像——一个 .iso、一个 qcow2 虚拟机镜像、或者一组 bzImage + rootfs呢?
这种目标,光”解包看文件系统”远远不够,真正要审的是内核、基础网络栈、驱动和认证权限组件:syscall 接口的越界写入、ioctl 的 copy_from_user 边界、提权路径里的 setuid/capability 泄漏、PAM 默认凭据……这些都不是靠静态扫文件系统能碰到的,得真去 fuzz、去触发 crash、去读内核 oops。
所以 FirmAudit2 在 v1.1.47 把审计对象从”固件”扩到了”操作系统”,新增了操作系统漏洞审计(OS)。它和固件审计共用同一套沙箱、同一套 findings 协议、同一套 CNVD 打包管线,但流水线、攻击面口径和几条纪律是重新设计的。
数据同样统一从 log/database 抽取成文本展示,敏感信息不截图(依旧懒得打码)
二、系统总览
能力概览

工作流程图

攻击面台账是这条流水线和固件审计最大的分叉点。固件审计的收口门判的是”段落填没填完”,而 OS 审计多了一本必须逐行闭合的账。
三、OS 审计流水线:多了一个专门干 fuzz 的阶段
固件审计的五阶段是解包/结构/静态/动态/报告。OS 审计换成另一套口径,对应 defaults/prompts/os.md 的阶段上报协议:
1 | // internal/agent/os_prompt.go buildOSPromptFallback(节选) |
五个阶段里,fuzz 是 OS 审计专属的核心阶段,固件审计没有这一档:
- recon(环境侦察):识别镜像/内核类型(
file、binwalk、qemu-img info、fdisk -l)、版本号(uname -a、cat /etc/os-release、内核版本串)、架构、引导方式(GRUB/syslinux/U-Boot),并建立攻击面台账; - setup(环境搭建):在目标系统内装白名单内的辅助工具——编译(gcc/clang/make/cmake/musl-dev)、调试(gdb/strace/ltrace/valgrind/ASan)、二进制分析(objdump/readelf/radare2/rizin)、源码获取(git/wget/curl);
- fuzz(模糊测试):按攻击面选策略——syzkaller 对 syscall 做结构化 fuzz、AFL++ 对网络服务二进制做文件/网络 fuzz、libFuzzer 对有解析函数的库做 in-process fuzz、对 login/sudo/su/pam 做输入变异;
- analyze(分析):crash/oops 的 root cause 定位、提权路径分析、认证绕过验证;
- verify(验证):每个可确认漏洞写独立 PoC,
script命令录制终端转录作证据。
工具链在 provision.sh 里有专门的 OS 安装段:syzkaller(GitHub 源码编译,含 Go 工具链自动安装)、AFL++/rr/crash(apt)、angr(pip);装不上也只是降级成警告,不阻断部署。

四、攻击面台账:把”审没审完”变成平台能读的东西
为什么要造这本账
后台统计过同一份镜像、同一模型的多轮审计:攻击面条目数分别是 16 / 13 / 8 / 9,已证实分别是 5 / 3 / 0 / 2,而回合数和 token 消耗几乎恒定。
差别不在算力,在于模型有没有把”还没看过的入口”记在账上——它经常自报 done,但台账里还躺着 7 行没审。
首篇提过的收口门只管”漏洞段落填没填完”,管不到”攻击面有没有审全”。于是单独做了一条平台真正消费的协议:Agent 覆盖写
/workspace/.cpi/audit/attack_surface.json,每行是一个可控入口点及其审查结论;
监视器每轮读取,落四道门(代码在 internal/agent/attack_surface.go):
1 | // ledgerGateCategory:固件审计与操作系统审计都要求台账每行闭合; |
落下的四道门各管一摊。
G1 负责把进度亮出来——台账状态分布一变就发 audit.surface 事件,前端阶段区能直接看到覆盖进度,不用等黑盒跑完才知道审了多少。
G2 卡的是收口:Agent 自报 done 时台账里还躺着”未审/审查中”的行,平台直接拒收、发 audit.stage.blocked,并把待办清单回投给会话让它补判,而不是一刀切判停。
G3 逼着写理由——已排除或已放弃的行必须带 reason,否则照样算收口障碍,免得出现”我看过了但没写为什么排除”这种没法复核的结论。
G4 只在矛盾时存疑:Agent 自报的阶段和工作区客观产物对不上(比如自报 verify,却既没已证实条目也没转录证据),平台发 audit.stage.suspect 提醒操作员,但只提示不改判——万一是同回合里刚补上的,误判成卡住反而更糟。
还有个细节救过事故:台账用 cat > 覆盖写,文件会瞬间变成 0 字节或半截 JSON;收口门只读一次会把撕裂写当成”台账缺失”误判暂停,所以收口门专用读取会等 400ms 再读一次区分”真没写”和”正在写”。
漏洞数量波动的根因,就是这本账之前平台从不读。现在它既是 Agent 的待办清单,也是平台收口的硬依据。
五、反扫描器纪律:强制手工 fuzz,堵住”扫描器捷径”
OS 审计和固件审计有个本质区别:固件审计偏静态+仿真验证,OS 审计要真去跑 fuzz、触发内核 crash。最容易偷懒的做法是装个 Trivy / Semgrep 扫一遍、把扫描报告当发现——但那种输出没有运行时证据,交 CNVD 根本站不住。
所以 os.md 列了明确的黑名单,平台在提示词层就把它堵死:
1 | // defaults/prompts/os.md 安全边界与约束(节选) |
换句话说,OS 审计的”发现”必须来自 syzkaller/AFL++/libFuzzer 这类手工构建目标与用例的 fuzzing,或手工的静态分析+复现;扫描器能出的只是线索,不能当结论。
这条纪律和首篇讲的”仿真验证硬门只认运行时回显”是同一个底层原则——证据必须可复核,只是到了 OS 层面换成了”拒绝扫描器捷径”。

六、产品信息纪律:不替你猜厂商与型号
固件审计那边,平台能从文件名、版本文件里读出版本信息;OS 镜像这块我特意改了口径——平台取消厂商/型号的自动识别,上报表里的”厂商/产品/版本”只是操作员的可选填写值。报告里写什么,必须以 Agent 从镜像内容实测确证的结果为准:
1 | // defaults/prompts/os.md 产品信息纪律(节选) |
这条规定是为防一种常见幻觉:模型看一眼文件名 ubuntu-virt-3.24.1.iso 就把厂商写成 Ubuntu、版本写成 3.24.1,却从没真正 cat /etc/os-release 印证。
现在窗口里留的占位文本就是”未提供(操作员未填写;请从镜像内容确证,无法确证时在报告中如实注明「未能确认」,禁止臆测)”——把”我不知道”变成强制声明,而不是默默编一个。
七、网络门控与模型网关:流量只走宿主中转
OS 审计里 Agent 要装工具、拉源码、跑 fuzz,网络需求比固件审计重,所以隔离边界更要讲清楚。沙箱的网络不是”能连就能连”,而是 daemon 在任务命名空间内用 iptables 白名单实施的,提示词必须和内核实际行为一致,否则 Agent 会去试被丢弃的外联、白白浪费回合:
1 | // internal/agent/firmware_prompt.go sandboxNetworkNotice(OS 审计同用) |
这里有两件事得说清。模型流量统一走宿主网关中转(modelgateway),容器里禁止直连外网 API,上游密钥只在 daemon 侧持有,既不序列化给前端也不进容器;攻击载荷则只落在沙箱内部仿真目标与回环地址,绝不允许把 payload 打向任何真实第三方。
这和首篇的 overlay 临时根是同一套”运行时约束”思路:让 Agent 能干活,但写不坏宿主、连不到外面、密钥不出 daemon。
八、交付形态:复用同一套平铺总包
OS 审计的发现走的是和固件审计完全相同的收口路径:每段漏洞资料过首篇讲过的分段引导与四道质量门,过了门就平铺进 CNVD 交付包——镜像副本 + 报告 + PoC + 证据,全部平铺在包根,评审者不需要理解目录结构。v1.1.57 把攻击面台账收口门也并进了这条路径,所以 OS 任务不会在台账缺失/未闭合时被判”资料齐备”。

唯一 OS 专属的交付物是 审计总报告.md(v1.1.56 起三个审计类别都有了独立的报告页签 + Markdown 渲染):至少含镜像概览、实测版本信息、攻击面覆盖清单、漏洞汇总表与每漏洞的复现证据索引。
九、现有产出展示(貌似成果才是重点…)

十、购买入口(白帽集市)

FirmAudit2 · 固件 / 操作系统漏洞审计平台
- 【占位:价格】 ¥50(公测价)
- 【授权方式】 单设备永久授权
- 【库存余量】 11
- 【售后与更新】 版本更新:保持迭代推送;答疑渠道:微信群聊
- 【购买入口】 白帽集市搜索「FirmAudit2」,或直接扫描上方二维码
前置环境:Windows 11 x64、已启用 WSL2(wsl --install)、磁盘建议 ≥ 40GB 可用、首次部署工具链需联网。大模型 API 需自备,平台不内置任何模型额度。(OS 审计要装 syzkaller/AFL++ 这类重工具,建议用聪明一点的模型,并给沙箱留足磁盘与内存。)
结语
首篇解决了”怎么保证固件漏洞是真的、能拿出证据、能变成可交的格式”。本篇补的是另一半:
当目标从一份固件变成一整张系统镜像/内核,审计对象从文件系统挪到了内核态与系统组件,平台该怎么把”审没审全”也变成可校验的东西——攻击面台账、反扫描器纪律、产品信息实测确证,加上延续下来的网络门控,合起来就是 OS 审计线的底气。
说些什么吧!