Quiet
  • HOME
  • ARCHIVE
  • CATEGORIES
  • TAGS
  • LINKS
  • ABOUT

Ram

  • HOME
  • ARCHIVE
  • CATEGORIES
  • TAGS
  • LINKS
  • ABOUT
Quiet主题
  • 漏洞挖掘
  • LLM

FirmAgent

Ram
论文阅读

2026-04-21 13:03:38

《FirmAgent: Leveraging Fuzzing to Assist LLM Agents with IoT Firmware Vulnerability Discovery》

这篇论文《FirmAgent: Leveraging Fuzzing to Assist LLM Agents with IoT Firmware Vulnerability Discovery》的核心目标,是解决 IoT 固件漏洞挖掘里一个长期很难同时兼顾的问题:
静态分析覆盖广,但误报高;动态分析(尤其 fuzzing)能给出可触发样例,但漏报高。 作者提出的 FirmAgent,本质上是在这两者之间做了一个很“聪明”的分工:先让 fuzzing 负责“找到真实输入从哪里进来、程序运行时到底走了哪些调用关系”,再让 LLM 负责“沿着这些更可信的路径做语义级污点分析,并补全 PoC”。作者把它定位为第一个“用 fuzzing 来辅助 LLM agent 做 IoT 固件漏洞发现”的混合框架。


1. 论文到底在解决什么问题

IoT 固件漏洞挖掘里,尤其是跑 Linux 的路由器、摄像头这类设备,常见方法大致分三类:

第一类是静态分析。
比如 SaTC、EmTaint、HermeScan、OctopusTaint。这些方法不运行程序,只看二进制/反编译代码,优点是理论上能“看遍很多路径”,缺点是很容易把不是真正外部可控的输入点也当成 source(污点源),于是误报很多;而且它们通常只能报“可能有洞”,不给 PoC,后续还要人手工验证。

第二类是动态分析 / fuzzing。
比如 FirmAFL、Greenhouse、FirmFuzz。这类方法的优点是,只要真打到了漏洞,通常就能给出 crash、输入样例,甚至直接给 PoC;问题是 IoT 固件路径约束很重,很多分支依赖特定 URI、参数名、配置项甚至硬件状态,fuzzer 很难靠随机变异跨过去,于是大量 sink 根本到不了,造成漏报。

第三类是混合方法。
传统 hybrid fuzzing 的想法是边 fuzz 边做符号执行/约束求解/甚至让 LLM 帮忙生成能过检查的输入。但在 Linux-based IoT firmware 上,这样做的代价很大:
一方面运行在模拟环境里的约束收集不稳定;
另一方面 IoT 固件特别容易崩、模拟又不完整,把 LLM 放进 fuzzing 内环会让系统很重、很脆。

这篇论文的关键点在于:它不是把 LLM 放进 fuzzing 的在线决策环里,而是把 fuzzing 当成“动态事实收集器”,把最难、最容易错的那部分事实先收上来,然后交给 LLM 去做更精准的静态推理。 这点非常重要。


2. 作者的核心观察:为什么这条路线是成立的

论文最有价值的不是“用了 LLM”,而是它先做了一个非常关键的经验观察。

2.1 静态分析为什么误报高

image-20260421200832986

表 II 里统计了静态 source 识别的准确性。以 HermeScan 为代表的静态方法,虽然已经算当前比较准的,但它找到的候选 source function 里,平均只有 21.6% 真的是实际接收外部输入的 source。
进一步看,由这些候选 source 拼出来的候选调用链,只有 30.7% 是真实漏洞调用链。这就解释了为什么静态分析会报一堆“看上去能通,实际上不可控”的假漏洞。

2.2 fuzzing 为什么漏报高

表 III 更关键:

image-20260421200904750

作者发现 fuzzing 在这些固件上,平均能到达 89.7% 的 source 点,但只能到达 25.0% 的 sink 点。
这说明一个很有意思的事实:

  • 外部输入进入程序的位置通常比较浅,fuzzing 比较容易摸到;
  • 但从 source 再走到危险 sink,中间会经过很多复杂条件,比如 URI 匹配、配置项判断、字符串格式检查、状态依赖,导致 fuzzer 很难真正触发漏洞。

所以作者的洞察是:

让 fuzzing 干它擅长的事:确认“这里真有外部输入进来”;
让静态/LLM 分析干它擅长的事:从这些可信 source 往后把路径推到底。

这就是 FirmAgent 的理论基础。

2.3 两个具体例子特别能说明问题

例子一:静态分析会被间接调用卡住

图 1 展示了 Trendnet 路由器里的一个例子。

image-20260421200943894请求匹配到 NTPSyncWithHost.cgi 后,会通过函数指针跳到 sub_F934。在这个函数里,用户输入经过一些字符串处理,最后进入:

sprintf(v5, "date -s %s", url_remove);
system(v5);

这显然是潜在命令注入路径。
问题是:静态分析很难把“间接调用点”和真正被调到的目标函数”准确连起来,于是污点在函数指针处“断掉了”,导致漏报。

而 fuzzing 在运行时是能看到“这次函数指针实际跳到了哪儿”的,所以它能补上这条控制流边。

例子二:fuzzing 会被配置条件卡住

图 2 里 Netgear DC112A 的代码:

image-20260421201531486

这里 deviceName 是外部输入,但想走到 system,还得满足固件内部配置条件。
fuzzer 可以把污点送进 Name,但未必能猜中 nvram 条件,所以动态上触发不到漏洞。

而如果你已经知道 Name 是真实外部输入,那么静态/LLM 就可以在后半段继续推理:只要某个配置成立,这里就有命令注入风险。

这两个例子恰好说明:
静态分析最怕 source 不准、间接调用断链;动态分析最怕深路径条件。
FirmAgent 就是在这两个薄弱点之间做拼接。


3. FirmAgent 的总体结构

image-20260421201549293

阶段一:Fuzzing-Driven Information Collection

即“fuzzing 驱动的信息收集”。

目标不是立刻找到漏洞,而是先收三类对后续分析最关键的信息:

  1. 真实 source 点 / Csource:程序里哪些位置在运行时真的接收了外部输入;
  2. 更完整的调用图:尤其是通过运行时解析补全的间接调用;
  3. 可达测试样例:哪些请求模板至少能走到这些 source 点。

阶段二:Taint-to-PoC Agent

即“从污点到 PoC 的 agent 阶段”。

在拿到上面的动态事实以后,再做两件事:

  1. 污点传播 agent:沿着从 Csource 到 sink 的潜在路径,做语义级污点分析;
  2. PoC 生成 agent:把 fuzzing 收集到的“可达 testcase”与 LLM 推导出的“语义约束”结合,自动补出一个真正能触发漏洞的 PoC。

这两个阶段的组合,实质上是:

动态阶段负责“把问题缩小到真实、可信的范围”
LLM 阶段负责“在这个可信范围里做高层语义推理和样例补全”

这比“全靠静态猜 source”,或者“全靠 fuzzing 硬撞 sink”,都要稳得多。


4. 第一阶段:Fuzzing 驱动的信息收集,具体是怎么做的

image-20260421201611874

4.1 预分析(Pre-fuzzing Analysis)

这是正式 fuzz 之前的静态准备工作,主要做三件事。

4.1.1 Service Handler Detection:找服务处理函数

IoT 固件里的 web 服务通常有很多 handler,分别处理不同 URI、SOAP 操作、HANP 消息等。
问题是很多 handler 并不在前端页面里显式暴露,或者文档不完整。如果你不知道 URI,fuzzing 连入口都进不去。

作者的做法是:

  1. 从公开接口信息里抽取初始请求模式
    例如 web server 配置、SOAP 定义、API 文档;
  2. 利用字符串引用和控制流分析,找到这些请求对应的 handler 代码块;
  3. 再收集这些 handler 附近的上下文,交给 LLM 去学习“handler 长什么样”;
  4. 通过代码结构相似性,挖出未文档化的 handler。

这个设计的意义在于:
不是只 fuzz 前端表面暴露的接口,而是尽量把隐藏后端接口也纳入覆盖范围。

4.1.2 Keyword Dictionary Analysis:构建关键字字典

传统方法像 SaTC,很依赖前端-后端共享关键字匹配。但这样会漏掉“只有后端才知道”的参数名。
FirmAgent 想要更系统地提取参数关键字。

它的方法是:

  1. 先通过人工与重宿主后的固件交互,拿到一些初始网络流量 seed;
  2. 用这些 seed 去分析二进制,找哪些函数和这些关键字交互频繁;
  3. 过滤掉通用字符串函数,如 strcpy、strcmp;
  4. 选出最可能处理参数的候选函数;
  5. 对这些函数的实参做回溯,提取参数名。

这里回溯参数来源时,论文总结了几种典型模式。

image-20260421202526295

主要包括:

  • 直接硬编码字符串:例如 get_cgi("countdown_time")
  • 变量由字符串常量赋值而来
  • 变量来自 .data 段数组或全局结构
  • 变量通过 sprintf / strcat 等动态拼接生成

这一步产出的不是“漏洞”,而是一个用于 fuzzing 的参数字典。后面生成请求时,哪些字段值得替换、替换成什么,就靠它。

4.1.3 Sink Scope and Distance:找 sink 范围并计算距离

这一步是为了让 fuzzing 更有方向感。

作者先通过模式匹配,把固件里一类一类安全敏感 API 找出来,作为 sink。
比如命令执行、拷贝、格式化字符串之类,分别对应命令注入、缓冲区溢出等风险。

然后做两件事:

第一件:算出哪些基本块“可能通向 sink”

对每个 sink 做向后可达性分析,得到一片和 sink 有关的地址范围。
后面 QEMU 只在这个范围里重点做监控,这样能大幅减轻开销。

第二件:给基本块打“离 sink 远近”的分数

作者在第 7 页给了一个公式:
$$
score(n)=depth(n)+w\cdot dis(s)
$$
其中:

  • depth(n):基本块在 CFG 里的结构深度;
  • dis(s):到最近 sink 的最短距离;
  • w:权重。

这个分数后面会用来指导 seed 排序和参数变异。
你可以把它理解成:既考虑路径深入程度,也考虑和危险点的接近程度。

4.2 运行时阶段(Runtime Monitoring)

预分析做完后,真正开始在用户态重宿主环境里跑 fuzzing。这里也分两部分。

4.2.1 变异策略:不是乱变,而是“字典 + 距离引导”

作者强调,传统 bit flip、splicing 在固件 web 二进制上效果不够好,因为 source 和 sink 大多都在服务 handler 附近。
所以它们采用 dictionary-based + distance-guided 的灰盒 fuzzing:

  1. 用之前提取的 URI 和关键字字典构造请求模板;
  2. 系统化地替换参数值,注入可能恶意的 payload;
  3. 每个关键字还会带上定制 taint tag,这样后面更容易跟踪它是否经过消毒;
  4. 运行时记录执行过的基本块;
  5. 根据基本块对应的预计算分数,给 testcase 打分;
  6. 高分种子优先继续变异,低分样例则尝试替换成别的关键字。

它的目标不是“尽快撞出 crash”,而是尽可能覆盖更多 handler,找到更多真实输入点 Csource。

4.2.2 运行时信息收集:如何识别 Csource 和间接调用

这是这篇论文最关键的工程点之一。

作者在 QEMU 的 TCG 执行阶段做了选择性插桩,但不是全程序都插,而是只盯着前面算出来的 sink scope。
在这个范围里,每执行一条相关指令,就检查内存状态是否从untainted 变成 tainted。

如果某个内存位置在这里第一次出现这种变化,就把对应地址记为 Csource。

这个定义很重要。
FirmAgent 里的 Csource 不是“静态上猜测的 source function”,而是:

运行时真实观察到、受到外部输入影响、并且出现在安全敏感范围内的代码点。

所以它比传统静态 source 精确得多。

同时,系统还会记录间接调用的真实目标。
做法是给基本块加轻量回调,识别间接跳转/调用,记录 (caller, callee) 对。
这样就能把静态看不清的函数指针调用在运行时补全进调用图里。

最后,利用:

  • 当前得到的 Csource
  • 完整得多的 CallGraph
  • 预定义的 Sinks

就可以构造出一批 Potential Paths(潜在漏洞路径)。

4.3 算法 1 如果用白话说,流程就是

第 6 页算法 1 可以翻成下面这件事:

  1. 从固件里提取 handler、关键字、sink、静态调用图;
  2. 反向分析得到 sink 相关范围和距离图;
  3. 启动模拟器;
  4. 依次把请求模板中的 URI 替换成每个 handler;
  5. 再把关键字逐个注入到模板里;
  6. 根据距离信息引导变异;
  7. 执行变异后的请求;
  8. 如果在 sink scope 里观察到 taint,就记录该位置为 Csource,并保存 testcase;
  9. 同时收集所有运行时出现的间接调用目标;
  10. 用更新后的调用图,持续生成从 Csource 到 sink 的潜在路径。

所以,fuzzing 在这里不只是“找 crash”,而是在持续在线地产生静态分析更需要的先验事实。


5. 第二阶段:Taint-to-PoC Agent,怎么把“潜在路径”变成“真实漏洞”

到了这一阶段,FirmAgent 已经有了:

  • 哪些点是真 source(Csource)
  • 哪些路径从这些点能走到危险 sink
  • 哪些请求样例至少能到 source

接下来才轮到 LLM 上场。

5.1 先修反编译结果:LLM-Based Refinement

作者非常清楚地意识到:
如果直接把 IDA 的反编译结果喂给 LLM,LLM 也会被“垃圾输入”带偏。

因为 IDA 在固件二进制上常常会出现:

  • 漏参数
  • 漏返回值赋值
  • 控制流/数据流恢复不准

附录给了一个特别直观的例子。

image-20260421203445656

原始 IDA 结果里,get_cgi("date") 的返回值根本没被保留下来,这显然丢失了关键数据流。
而 LLM refinement 后,代码被恢复成更合理的形式:这样污点从 date 到 system(command) 的关系才真正可见。

所以这一层实际上是在做先把反编译代码变得更“可推理”,再做污点分析。

5.2 污点传播 Agent:LLM 具体怎么分析

image-20260421203521259

它会把以下信息交给 LLM:

  • 当前函数的反编译代码
  • 相关 source
  • 相关 sink

然后让它判断:
source 的数据能否传播到 sink,并构成漏洞。

如果中间遇到未知函数,LLM 会先停下来,要求系统补上这些函数的反编译代码,再继续分析。
这就形成了一种“交互式函数级分析”。

这个分析怎么跨函数?

论文说它是函数级做的。

  • 如果 source 和 sink 在同一函数里,就做函数内污点传播;
  • 如果不在同一函数里,就先在调用点找出“哪些参数已被 taint”,
  • 再把这些 tainted 参数当成被调函数里的新 source,
  • 一层一层递归下去,直到走到 sink。

这实际上就是LLM 驱动的跨过程污点传播。


5.3 作者还专门处理了 LLM 容易犯错的三类误报

他们发现,LLM 做固件污点分析时,最容易在三种地方出错。附录第 16 页 图 11 给了很好的例子。

第一类:没看懂 sanitizer

例如有个输入 Value,程序逐字符检查,只允许数字;一旦有非法字符就 exit(1)。
虽然最后确实有:

sprintf(v5, "'%s'.gif '%s'.txt", Value, Value);
system(v5);

但因为输入早已被严格限制成数字,这其实不构成可利用命令注入。
如果 LLM 只看见 system(v5),很容易误报。

第二类:把“只参与条件判断”的 taint 当成真正传播

例如:

if (!strcmp(taint, "2"))
    v4 = "factory_hm info fat 2";
else
    v4 = "factory_hm info fat 1";
system(v4);

这里 taint 只决定分支,不直接流入 sink 参数。
sink 真正执行的永远是常量字符串。
这不是可控命令注入。

第三类:把系统文件读出来的数据当成用户输入

例如从 /etc/passwd 读数据进 buf,再 system(buf)。
这虽然“数据进入了 sink”,但来源不是用户可控输入,因此不属于作者关心的 taint-style 漏洞。

为了解决这些误报,论文在 taint agent 之后又加了一个 alert verification module,用 few-shot prompt 去专门甄别这几类情况。
另外还做了 function-level caching,避免多个调用链重复分析同一个函数。


5.4 PoC Generation Agent:怎么把“能到 source 的 testcase”补成“能打中 sink 的 PoC”

这是这篇论文实用性非常强的一部分。

传统静态分析最麻烦的地方就在这里:
它只能说“这里可能有洞”,但不会告诉你输入到底要怎么构造。
验证人员只好自己去读代码、猜参数、写 PoC,成本很高。

image-20260421203729321

FirmAgent 的思路是:

  1. 在污点传播阶段,顺手提取语义约束
    比如:
    • 必须走哪个分支
    • 某些参数必须等于什么
    • 某些特殊字符会被过滤
    • 某字段必须满足某种格式
  2. fuzzing 阶段已经有了一个至少能走到 source 的 testcase
  3. 把二者一起交给 PoC 生成 agent
    prompt 里就包括:
    • Reachable test case
    • Input validation constraints
    • Decompiled code

然后让 LLM 去推断:
每个参数应该填什么值,才能既满足前置条件,又让 taint 真正传到 sink。

附录第 16 页 C 节说得更明确:
最终 PoC 是 HTTP 请求包。
比如 fuzzing 已经给了 URL、Header、Body 框架,LLM 负责补上关键字段值,例如:

  • NtpDstEnable = "1"
  • NtpDstOffset = "A"*300

这样就能把“部分有效的请求模板”补成“真正能触发缓冲区溢出或命令注入的 PoC”。

这一步是 FirmAgent 和很多静态工作的最大差异之一:
它不只是报漏洞,而是尽量把验证工作也自动化了。


6. 实现细节:这不是概念模型,作者确实做了完整原型

第 9 页的实现部分给了不少工程信息:

  • 总体实现量:4000+ 行 Python,1000 行 C
  • 用 binwalk 解包固件 rootfs,定位 web 二进制
  • 用 IDA Pro + 自定义 IDAPython 做预分析
  • 用 Greenhouse 做用户态单服务重宿主
  • 用 自定义 QEMU 插件 收集内存 taint 与间接调用
  • LLM 选的是 DeepSeek-R1,温度设为 0.7

而且它是做成了一个全自动框架:
一旦 fuzzing 开始,系统就持续识别 Csource,把对应地址送去 taint propagation agent,再进入 PoC 生成。

换句话说,这不是“先 fuzz 半天,再人工挑一些点交给 LLM”,而是作者想把整个流程串成自动化流水线。


7. 实验部分:论文最重要的数据结论


7.1 数据集与对比对象

作者选了 14 个可成功模拟的真实 IoT 固件,来自:

  • Netgear
  • D-Link
  • Tenda
  • Trendnet
  • Linksys
  • ASUS
  • TOTOLINK

对比工具包括:

  • EmTaint(静态)
  • HermeScan(静态)
  • Greenhouse(动态)
  • Hy-FirmFuzz(混合)

另外一些工具没纳入直接对比,原因也写得很清楚:

  • SaTC:已有工作表明比不过 HermeScan/EmTaint
  • LARA:不开源,无法复现
  • Mango:和 HermeScan 同属 reaching definitions 路线,效果接近
  • OctopusTaint:开源代码不完整,缺 source 识别等关键部件

实验环境也很豪华:
Xeon Platinum 8358,128 逻辑核,2TB 内存,Ubuntu 20.04,Docker 重复实验 4 次。


7.2 RQ1:FirmAgent 与 SOTA 相比到底强多少

image-20260421203920011

FirmAgent 的总体结果

  • 200 个 alerts
  • 其中确认出 182 个真实漏洞
  • Precision = 91%
  • 漏洞类型包括:
    • 45 个命令注入
    • 137 个缓冲区溢出
  • 其中 140 个此前未知漏洞
    • 27 个未知命令注入
    • 113 个未知缓冲区溢出
  • 17 个已经分配 CVE

对比基线

  • EmTaint:27 alerts,10 real vulns,37% precision
  • HermeScan:215 alerts,71 real vulns,33% precision
  • Greenhouse:20 crashes,8 real vulns,40% precision
  • Hy-FirmFuzz:13 crashes,13 real vulns,100% precision

也就是说:

  • 比 EmTaint 多发现 18.2 倍
  • 比 HermeScan 多发现 2.6 倍
  • 比 Greenhouse 多发现 22.8 倍
  • 比 Hy-FirmFuzz 多发现 14 倍

第 11 页 图 6 还画了一个漏洞包含关系图,非常直观:
FirmAgent 覆盖了其他工具发现的所有漏洞。

image-20260421204146621

这说明它不是“找到另一批不同漏洞”,而是整体发现能力明显更强。


7.3 为什么别的工具不如它

论文对每个基线都做了具体误报/漏报分析。

EmTaint

  • 误报来源:过度 aliasing,把不相关变量也 taint 了
  • 还不太会识别程序内部 sanitizer
  • 漏报来源:只支持预定义 source,很多固件自定义 source 没覆盖到;部分固件指令支持也有限

HermeScan

  • 误报:source 识别不准、sanitize 处理不好
  • 漏报:reaching definition 在复杂数据流下会丢 taint

Greenhouse

  • 误报:有些 crash 其实是内存限制或 QEMU 模拟不完整,不是真漏洞
  • 漏报:不知道隐藏 URI、参数字典,也过不去程序特定约束,很多 sink 根本测不到

Hy-FirmFuzz

  • 优点:只要报出来,基本都是真的,所以没有误报
  • 缺点:只测前端暴露的 URL 和参数,而固件里大量功能接口根本没暴露,漏报非常严重

FirmAgent 自己的误报来自哪里

作者也没有回避这个问题。
FirmAgent 的 18 个误报全部是缓冲区溢出,主要因为 LLM 有时推不准:

  • 输入真实长度
  • 目标 buffer 大小
  • 全局变量和当前函数变量之间的关系

换句话说,命令注入上它更稳,缓冲区尺寸推理上还不够完美。


7.4 时间效率

从时间看:

  • EmTaint 平均约 3 分钟
  • HermeScan 平均约 8 分钟
  • FirmAgent 每个固件设定 1 小时
  • Hy-FirmFuzz 约 78 分钟
  • Greenhouse 约 24 小时

所以 FirmAgent 确实比静态工具慢,但它换来了三样东西:

  1. 更高 precision
  2. 更低 false negative
  3. 自动 PoC 验证能力

而且作者强调,不同固件可以并行分析,所以总体吞吐还可以接受。


8. RQ2:用 fuzzing 找 source,真的可靠吗?

image-20260421203947251

作者统计了:

  • Csource:FirmAgent 运行时识别到的 source
  • Source:这些 Csource 中真实 source 的数量
  • All-Source:人工验证得到的所有外部输入点总数

结论非常漂亮:

  • Csource 的准确率是 100%
  • 平均覆盖率是 94.2%

为什么准确率能 100%?
因为它不是靠字符串匹配猜,而是只在运行时真的观察到 taint 传播的地方才记 source。
这就从根上消掉了传统静态方法的“候选 source 假阳性”。

那剩下 5.8% 为什么没看到?

作者说主要有两类:

  1. 死代码 / 旧代码 / 实际不可达路径
    这些本来就不会被执行,不看到反而有助于减少误报。
  2. 跨过程很深的路径
    某些 source 要满足早期复杂条件才会出现,fuzzing 没走到。

但论文还说,这并没有导致真正的漏洞漏掉,因为后续 LLM 在分析调用链时,会把这些 source function 补充当成 source 来继续推理。

这点很重要:
FirmAgent 用 fuzzing 确认 source,是为了尽可能降低误报;但它并没有把 LLM 死死限制在“只分析动态看到的那些点”。
这让它在 precision 和 recall 之间取得了比较好的平衡。


9. RQ3:消融实验说明各模块到底有多重要

image-20260421204013530

9.1 去掉定向 fuzzing(Firm-Directed)

结果变成:

  • 194 alerts
  • 176 true positives
  • 少了 6 个真实漏洞

说明定向 fuzzing 的价值在于:
它能把探索推向更深的 source 点,而不是只在浅层打转。

9.2 去掉间接调用解析(Firm-Indirect)

结果变成:

  • 187 alerts
  • 169 true positives
  • 少了 13 个真实漏洞

这直接证明:
运行时补全函数指针/间接调用的控制流边,是发现这类固件漏洞的关键。

9.3 去掉 LLM refinement 和 alert verification(Firm-Cut)

结果变成:

  • 232 alerts
  • 172 true positives
  • 60 false positives

也就是说:

  • 真漏洞少了 10 个
  • 假阳性多了 42 个

这说明前面那两层“看起来像辅助功能”的模块,其实非常重要:

  • refinement 负责修复反编译缺陷,减少污点丢失
  • verification 负责识别 sanitizer / 非传播 taint / 系统文件来源,减少误报

9.4 用传统 taint 引擎替代 LLM taint agent

  • Firm-Emt:34 alerts,15 TP,19 FP
  • Firm-Her:120 alerts,71 TP,49 FP

这说明,即便把 source 识别换成 FirmAgent 的动态 Csource,传统 taint 分析依然不够好。
所以提升不是只来自“source 找准了”,还来自 LLM 的语义级污点推理能力。


10. RQ4:自动生成的 PoC 到底有没有用

image-20260421204034701

作者把 PoC 分成三类:

  • E-PoC:不做任何人工修改,直接就能在真实设备上触发
  • H-PoC:稍微人工调整后能触发
  • F-PoC:根本触发不了,属于误报

结果是:

  • 总共 200 个 alerts
  • 18 个是误报,对应 F-PoC
  • 剩下 182 个真实漏洞里:
    • 167 个 PoC 直接有效
    • 15 个稍微人工改一下就有效

所以直接有效率是 91.8%。

为什么那 15 个不能一步到位?
作者说大多是命令注入,原因在于 payload 形式非常依赖上下文。
比如某些固件做了黑名单过滤,不让用 ;、|、&,但过滤又不完整,需要安全研究人员根据具体命令上下文设计绕过 payload。
这类事情 LLM 目前还不够稳定。

但即便如此,这个结果已经很强了。
因为传统静态工具通常0% 自动 PoC 能力,而 FirmAgent 已经把绝大部分验证工作省掉了。


11. 这篇论文真正有价值的地方,我认为有四点

第一,它提出了一个很清晰的“职责分离”思想

不是让 fuzzing 和 LLM 都做所有事,而是让每个组件只做自己最擅长的部分:

  • fuzzing:确认真实输入点、补全动态调用事实、提供可达输入骨架
  • LLM:做语义级污点传播、识别 sanitizer、推断参数约束、补全 PoC

这种分工比“全静态”或“全动态”都更现实。

第二,它重新定义了 fuzzing 在固件分析里的价值

这里 fuzzing 不再只是“撞漏洞的锤子”,而是变成了:

  • 真实 source 的判定器
  • 间接调用的运行时解析器
  • PoC 的模板生产器

这是一种很漂亮的角色转换。

第三,它把 LLM 用在了更适合它的位置

LLM 最强的不是算地址,而是理解语义、补全缺失上下文、推断“如果要触发这个条件,输入大概要长什么样”。
FirmAgent 让 LLM 去干的正好是这些事,而不是让它在 fuzzing 内环里频繁实时生成变异。

第四,它非常强调“能验证”

安全研究里,只报 alert 而不给 PoC,实际价值会打折。
FirmAgent 的 PoC 生成模块让这个工作更接近真实漏洞挖掘流程,而不是停留在“静态告警系统”层面。


12. 论文的局限,作者也讲得比较诚实

12.1 依赖重宿主能力

第 12-13 页讨论部分说得很明确:
FirmAgent 的能力高度依赖底层 rehosting 框架,尤其是 Greenhouse。
而 Greenhouse 目前的限制包括:

  • 新固件成功率还不高
  • 只能做单服务重宿主
  • 所以只能分析那个服务对应的单个 binary
  • 对跨 binary、多服务协同漏洞无能为力

这意味着:
FirmAgent 很强,但它的适用面,仍然受制于“固件能不能被稳定跑起来”。

12.2 缓冲区溢出判断仍然会有 LLM 误差

作者明确指出,目前的大部分误报都来自 buffer overflow。
因为 LLM 对:

  • 精确内存尺寸
  • 全局变量影响
  • 输入长度与目标 buffer 的真实关系

理解还不够稳定。
他们提出未来可以用:

  • 更精确的数据建模
  • RAG
  • 微调

来增强这部分能力。

12.3 从我的角度再补一条

论文虽然结果很好,但实验样本是 14 个固件。
对于 NDSS 论文来说,这个规模已经不算小了,尤其考虑到需要可模拟、可重宿主、可真实验证,但如果从“通用工业能力”角度看,仍然离大规模普适部署有距离。
也就是说,这篇论文更像是在证明:

这条技术路线是对的,而且非常有前景。

而不是说“今天起所有 IoT 固件都能自动挖得很好”。


13. 如果把整篇论文压缩成一句话

这篇论文最核心的思想可以概括成:

不要让 LLM 去猜哪个输入是真的用户可控,也不要让 fuzzing 去硬撞所有复杂条件;
先用 fuzzing 把“真实输入点”和“真实运行时控制流”找出来,再让 LLM 沿着这些更可信的路径做污点分析和 PoC 补全。

这就是它为什么能同时把:

  • 静态分析的误报
  • 动态分析的漏报
  • 手工验证的成本

一起压下去。

下一篇

自然语言处理基础

©2026 By Ram. 主题:Quiet
Quiet主题