ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Nuclei模板化扫描器实战:从POC编写到批量检测全流程

Nuclei模板化扫描器实战:从POC编写到批量检测全流程

很多做安全测试的朋友应该都有过这种经历:甲方给了一个挺大的IP段,说“帮忙看看有没有暴露的老设备”,你总不能一台台手工登录去试。这时候有个趁手的批量检测工具就特别重要。Nuclei作为一款模板化的漏洞扫描器,正好能解决这个痛点。这篇文章我就拿“天融信TOPSEC命令执行漏洞”这个具体场景,完整走一遍从POC编写到批量检测的流程,包括里面容易踩的坑和排查思路,希望对刚接触Nuclei或者正在做类似工作的朋友有点帮助。

1. 项目背景与检测思路拆解

1.1 天融信TOPSEC设备为什么值得重点关注

天融信的TOPSEC系列防火墙在国内政企内网里存量非常大,不少单位用了很多年,固件版本常年不更新。这类设备一旦爆出远程命令执行漏洞,影响面通常很广,而且因为设备本身就是为了“隔离内外网”而存在的,被攻破后攻击者拿到的是内网的一个稳定跳板,风险等级相当高。

我平时做授权测试时,遇到TOPSEC设备会格外留意几个点:第一,设备的Web管理面板是否直接暴露在非信任网络;第二,固件版本是否老旧,是否已经出现在公开漏洞库中;第三,是否存在一些历史遗留的默认口令或调试接口。命令执行类漏洞是这里面最严重的一种,它能直接让测试人员从“能访问管理页”变成“能执行系统命令”,接下来无论是读取配置文件还是做内网跳板,都变得十分顺滑。

1.2 Nuclei这类模板化扫描器好在哪里

Nuclei是ProjectDiscovery团队开源的漏洞扫描器,核心设计思路是“用YAML模板描述漏洞检测逻辑”,扫描引擎负责并发发起请求、匹配响应、提取结果。社区维护着非常庞大的模板库,很多公开漏洞在PoC公布后几天内就会有对应的nuclei模板。

相比直接用Python脚本或Burp Suite的Intruder,Nuclei有几个明显优势:

  • 并发效率高:默认就能跑几十上百个并发,扫一个大网段不用等太久。
  • 模板可复用:一个写好的模板,之后遇到同类设备随时复用。
  • 结果结构化:输出JSON、Markdown等格式,方便后续对接工单或报告。
  • 内置多种协议支持:除了HTTP,还能写DNS、TCP等协议的检测逻辑。

这次要做的TOPSEC命令执行检测,本质上就是构造一个特殊的HTTP请求,看设备是否会在响应中回显命令执行的结果。Nuclei的HTTP请求模板能力足够覆盖这个场景,而且不需要额外写复杂的Python脚本。

1.3 漏洞检测的整体流程拆解

整个检测过程可以分成四步走:

  1. 确认目标设备确实是天融信TOPSEC,避免误报。
  2. 构造命令执行探测请求,通过响应特征判断漏洞是否存在。
  3. 用Nuclei模板批量跑目标IP段,收集存活且存在漏洞的设备。
  4. 对扫出来的结果做人工复核,确认不是误报。

这里我想强调一点:批量扫描工具只是辅助,最终确认漏洞可利用性还是得靠手工验证。Nuclei的职责是帮你把“可能有问题”的设备从成千上万个IP里筛出来,而不是替你下结论。

2. Nuclei与POC设计核心逻辑

2.1 YAML模板的基础结构

先看一个Nuclei模板最基础的结构长什么样,后面写POC都是在这个框架上扩展的:

id: tosec-rce-check info: name: TianRong TOPSEC RCE Detection author: your-name severity: critical description: Detects command execution vulnerability in TOPSEC devices tags: tosec, rce, firewall requests: - method: GET path: - "{{BaseURL}}/xxx" matchers: - type: word words: - "uid="

id字段是这个模板的唯一标识,info区块存漏洞元数据,requests区块定义具体的检测请求。模板写完后,把文件放到nuclei的templates目录下的某个子目录里,比如http/cves/,执行扫描时用-tags参数就能筛出来。

2.2 命令执行漏洞POC的常见设计思路

命令执行类漏洞的POC设计,核心是解决一个问题:怎么在不直接进行破坏性操作的前提下,可靠地判断命令确实被执行了。

最常用的思路是让设备执行一个无害且结果可回显的命令,比如id、whoami、cat /etc/passwd等。如果设备把命令输出直接拼在HTTP响应里,那恭喜你,这是一个教科书级的回显型命令执行。

以TOPSEC的某类接口为例,漏洞点常出现在一些调试用或维护用的功能参数上。比如某个参数会把用户输入直接拼进系统命令中执行,检测时就能构造类似这样的请求:

GET /tosec/cmd.action?cmd=id HTTP/1.1 Host: target

如果响应体里出现了uid=这样的字符串,基本可以确定命令执行漏洞存在。当然实际代码中的参数名和路径需要根据具体固件版本调整,我这里就不写具体设备的细节了,避免被恶意利用。思路是通用的,拿到一个命令执行漏洞,第一步就是找能在响应中回显命令结果的最小验证请求。

2.3 为什么选择Nuclei DSL而不是普通正则匹配

Nuclei的DSL(领域特定语言)提供了比单纯正则匹配更灵活的响应判断能力。比如你可以用contains(body, 'uid=')这样的表达式,还能组合多个条件做AND/OR判断。

写复杂检测逻辑时DSL的价值会体现得更明显。比如说,你检测一个漏洞,需要同时满足“响应状态码是200”和“响应体中包含特定字符串”,用纯正则写起来比较绕,但用Nuclei DSL就是:

matchers-condition: and matchers: - type: status status: - 200 - type: word words: - "uid="

这样逻辑一目了然,后续维护也方便。另外Nuclei的DSL还支持extractors,能从响应中提取动态的内容,比如提取命令执行的结果保存下来,方便人工复核。

3. 实操配置与POC编写详解

3.1 环境准备与工具安装

Nuclei的安装方式很简单,有Go环境的话一行命令:

go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

没有Go环境的话,直接去GitHub的Releases页面下载编译好的二进制文件,扔到/usr/local/bin下就行。Windows环境就用exe文件,命令用法一样。

装完之后更新一下模板库:

nuclei -update-templates

这个是必须做的,因为社区模板每天都在更新。当然我们这种自定义POC,属于私有模板,不会在社区模板库里,需要单独管理。

3.2 自定义POC模板的完整写法

下面我给一个实际可用的模板框架,假设检测路径是/tosec/cmd.action,参数是cmd,命令执行结果会直接回显到响应体中(实际场景需根据目标版本调整,但方法完全一致):

id: tosec-cmd-exec info: name: TianRong TOPSEC Command Execution author: security-researcher severity: critical description: Detects command execution vulnerability in TOPSEC devices by injecting id command tags: tosec,rce,firewall,cnvd requests: - method: GET path: - "{{BaseURL}}/tosec/cmd.action?cmd=id" headers: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 matchers-condition: and matchers: - type: word part: body words: - "uid=" - "gid=" condition: and - type: status status: - 200 extractors: - type: regex part: body regex: - "uid=\\d+\\([^)]+\\)"

这个模板做的事情很简单:发一个GET请求,往cmd参数里塞入id命令,然后匹配响应体里是否同时出现uid=和gid=。如果返回200同时包含这两个特征,就认为存在命令执行漏洞。

3.3 编写POC时容易忽略的细节

写这个模板时有几个细节值得特别注意:

  • 路径大小写:某类设备的Web服务对路径大小写敏感,最好在模板里明确写出实际测试过可用的路径。如果把/tosec/cmd.action写成/Tosec/Cmd.action,遇到区分大小写的服务就直接404了。
  • URL编码:如果命令里有空格或特殊字符,需要在请求里做URL编码。id命令本身不含空格,但如果后续想执行cat /etc/passwd,空格在URL里要么写成%20,要么写成+,不同设备对这两种编码的接受程度不一样,建议在手工验证时都试一遍。
  • 请求频率控制:Nuclei默认并发不算低,批量扫大量IP时,如果目标设备性能较差(很多老防火墙的CPU和内存都很感人),容易把设备扫挂。后面会讲到怎么控制速率。
  • 指纹确认:批量检测时,大量非TOPSEC设备也会出现在目标列表里,如果直接发送POC请求,一方面会产生大量无意义的告警日志,另一方面可能触发一些安全设备的封禁策略。建议先加一个指纹匹配步骤,确认是TOPSEC设备再发命令执行探测请求。

3.4 指纹预筛的设计方法

想加指纹预筛,最简单的方式是利用Nuclei的stop-at-first-match配合多级请求。或者更直接一点,先做一次指纹请求,用internal变量把结果传给后面的请求判断。Nuclei支持在同一个模板里写多个请求,后面的请求可以引用前面请求的响应内容(比如提取到的关键字符串)。

思路大概是这样的:

requests: - method: GET path: - "{{BaseURL}}/" matchers: - type: word name: tosec_fingerprint words: - "TOPSEC" - "天融信" condition: or internal: true

上面第一个请求先判断首页是否有TOPSEC相关指纹。如果匹配成功,再走第二个请求做漏洞探测。不过实际写起来有一个坑:Nuclei的internal变量和请求间数据传递在复杂模板中不太好维护,新手容易写出“第一个请求的matcher没生效,第二个请求照样发”的情况。这里我更推荐一个懒人做法:分两步跑。

第一步用指纹模板扫描目标列表,筛出TOPSEC设备:

id: tosec-detect info: name: TOPSEC Device Fingerprint severity: info requests: - method: GET path: - "{{BaseURL}}/" matchers: - type: word words: - "TOPSEC" - "天融信WebSec"

第二步把指纹命中的IP作为目标,用命令执行检测模板再扫一遍。这样逻辑清楚,排查问题也方便。

4. 批量检测执行流程实录

4.1 目标列表准备

批量检测的第一步是准备目标列表。实际工作中目标来源一般有三种:甲方给的一个网段、资产测绘平台导出的IP列表、或者子域解析出来的IP集合。

无论来源是哪种,建议先把列表做去重和存活探测。去重可以用sort -u,存活探测可以用httpx这样的工具:

cat targets_raw.txt | sort -u | httpx -silent -status-code -title -tech-detect -o alive_targets.txt

这个命令会探测每个IP的HTTP服务是否存活,并输出状态码、页面标题和识别到的技术栈。这里有个小技巧:别把所有IP都直接丢给nuclei扫,先筛一次能节省大量时间,也减少误报源。有些地址根本不开Web服务,扫了也是白扫。

4.2 指纹预筛的执行过程

假设现在有一个存活目标文件alive_targets.txt,内容是IP加端口,格式大概是https://192.0.2.10:8443这种。先跑指纹模板:

nuclei -l alive_targets.txt -t tosec-detect.yaml -o tosec_ips.txt -jsonl -silent

-jsonl参数会输出JSON格式的结果,方便后续脚本提取命中的IP。执行完之后,查看tosec_ips.txt,里面应该有所有指纹命中的目标。

这一步输出的是“疑似TOPSEC设备”,数量通常不会太多。如果一下子命中几百上千个,说明目标网段里这种设备确实多,后面命令执行检测会很热闹。

4.3 漏洞检测与结果输出

接下来用命令执行模板扫指纹命中的目标:

nuclei -l tosec_ips.txt -t tosec-cmd-exec.yaml -o rce_results.txt -jsonl -rate-limit 10 -c 5

这里两个参数要重点解释一下:

  • -rate-limit 10:限制每秒最多发10个请求。这样设置是为了照顾老设备的承受能力。
  • -c 5:限制并发模板数,也就是同时只有5个目标在处理。

有朋友可能会觉得这个速率是不是太慢了。我实际测过一批设备,很多是用了五年以上的老防火墙,Web服务模块用的是很老的架构,并发稍微一高就无响应了。与其扫崩了再重启再补扫,不如一开始就悠着点,慢工出细活。

执行完之后,屏幕上会高亮显示命中的目标,同时结果写入rce_results.txt。每一行是一个JSON对象,包含目标地址、模板ID、匹配到的详细信息等。

4.4 结果的人工复核与利用验证

这一步非常关键。Nuclei命中的结果不一定是真的漏洞,有可能是某种特殊的页面刚好包含uid=这样的字符串。所以需要拿命中的目标再做一次人工复核。

我的标准操作是:浏览器访问目标,手工构造POC请求,观察响应。如果条件允许,用一个无害命令验证一下,比如id或uname -a,确认命令确实执行了。如果能够回显命令结果,再截图留证。

这里要特别提醒:授权是硬前提。没有目标单位书面授权,做任何扫描都是不合规的。别拿这个流程去扫不在授权范围内的目标,这是底线问题。

5. 常见问题与排查技巧实录

5.1 模板不生效,所有目标都显示未命中

这种情况最常见的两个原因:一是路径或参数名不对,二是目标设备固件版本已经修复漏洞。

排查路径很简单,先手工发一个请求看看响应,如果手工请求都拿不到预期的特征,说明POC里的路径或者命令不对,需要换一个接口或参数。如果是固件修复了,那就是漏洞本身已不存在,模板更新也没用。

另外还有一种情况:设备把带命令参数的请求交给WAF模块拦截了,返回了一个拦截页面,当然匹配不到特征。这种要看看响应头或响应体里是否有WAF的标识,比如Powered by XXX之类的。

5.2 误报率过高,响应里到处都有uid=

如果命中的结果里有一堆明显不是TOPSEC的设备,可能是指纹模板写得太宽泛了。比如匹配词里只写了TOPSEC,结果有些第三方登录页也用这个词做了品牌展示。

解决方法是增加指纹的权重,比如同时匹配TOPSEC和页面标题中的特定关键字,或者匹配特定的JS文件名、Logo路径等。多条件AND匹配能筛掉大部分误报。

5.3 扫描过程中目标设备无响应

批量扫TOPSEC设备时,容易被扫挂的设备通常有这些特征:老版本固件、开启了很多不必要的服务、内存较小。

处理办法是先确认设备是彻底宕机还是只是Web服务无响应。如果只是Web服务重启,等几分钟再补测即可。如果是整机宕机,可能需要联系现场人员重启。所以前面强调的-rate-limit和-c参数,真的别不放在心上。

还有一个经验:尽量避免在业务高峰期扫描这类老设备。老防火墙除了做安全隔离,往往还承载着一些历史遗留的转发任务,你把它的Web服务扫挂了,整个办公网出口都可能受影响。

5.4 Nuclei命令执行模板无法提取命令结果

有些场景下,命令执行漏洞确实存在,但命令结果是异步返回的,比如设备把命令放到后台执行,结果写到某个临时文件里,需要另一个接口去读。这种时候Nuclei的单请求模板就不够用了,得用多请求模板。

思路是:第一个请求触发命令执行,把输出重定向到一个可访问的静态文件路径下,第二个请求去读取这个文件,匹配内容。这类漏洞检测模板写起来复杂度高一些,但也不是不能写。Nuclei支持同模板内定义多个requests,按顺序执行,前一个请求的输出可以作为后一个请求的输入。

5.5 批量扫描结果如何高效整理

扫出来的结果往往是纯文本或JSON,直接贴给甲方肯定不行。我一般用一个小脚本把JSON结果转成表格:

cat rce_results.txt | jq -r '[.host, .matched-at, .info.name] | @tsv'

然后贴到表格软件里,按漏洞等级、目标IP、URL、验证状态列成清单,再补充修复建议。这个流程看起来很笨,但确实是项目交付时最实用的做法。

6. 经验总结与进一步扩展思路

6.1 模板维护的小技巧

Nuclei模板写多了,建议按设备厂商或漏洞类型建好目录结构,比如templates/tosec/下面放这类设备的全部模板,templates/rce/放通用命令执行检测模板。每次扫描前用nuclei -update-templates更新社区库,同时检查一下自己的私有模板是否需要修正路径或匹配词。

我习惯给每个模板文件写清楚注释,包括漏洞编号、影响版本、检测命令、验证方法。Nuclei的YAML支持#注释,多写点说明,后续自己回来看也能快速想起来当时为什么这么写。

6.2 从单点检测到体系化复盘

这次批量检测做完后,我建议把整个流程沉淀下来:模板文件、命令、结果、人工复核记录都整理成一套文档。下次遇到同类设备,直接复用这套流程就行。

同时也别只盯着一个漏洞点,TOPSEC这种设备往往同时存在多个已知漏洞,比如未授权访问、信息泄露等。把多个检测模板组合起来跑,一次扫描就能对目标设备的安全状况有个比较全面的认识。

6.3 实际工作里我个人的几个心得

第一,工具永远是辅助,手工验证是必须项。再好的模板也有误报,也有抓不到的绕过姿势。批量检测帮你圈定范围,人工确认帮你下结论。

第二,速率控制是对目标最基本的尊重。有些设备承载着生产业务,你扫挂了它,影响的可能是一整片网络,这个责任谁也担不起。宁可多花点时间,也别图快。

第三,结果整理比扫描本身更花精力。真正靠谱的安全测试,核心交付物是一份结论清晰、证据完整的报告。一个IP一个结论加截图,比打印十页扫描原始输出有价值得多。

第四,POC不等于武器库。写命令执行检测模板的目的是帮助确认风险、推进修复,而不是拿去做一些不该做的事情。合规这条线,任何时候都不能松。

这篇文章里写的检测方法,在我自己处理过的不少授权测试项目中都验证过,流程是可复用的。整体思路也不只适用于TOPSEC,换一个设备型号,本质上就是换一组指纹、换一条漏洞路径、换一组匹配特征,方法骨架完全一致。希望这份从POC编写到批量落地的心得,能帮你少走一些弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进