Nuclei 是目前渗透测试与安全评估领域最主流的基于模板的漏洞扫描引擎。编写一个高质量、低误报且易于维护的 PoC(Proof of Concept)模板,是安全工程师的核心能力之一。本文将从结构规范、语法要点、匹配逻辑及最佳实践等维度,系统阐述如何编写生产级的 Nuclei 模板。

一个标准的 Nuclei 模板由元数据(Info)和请求逻辑(Requests)两大部分组成。清晰的元数据是模板被正确分类、检索和执行的前提。
id**:** CVE-2024-XXXXX-poc
info**:**
name**:** "示例应用未授权访问漏洞"
author**:** "your_name"
severity**:** high
description**:** "示例应用 /api/admin 接口缺乏鉴权,导致未授权用户可获取敏感配置。"
reference**:**
- https://example.com/advisory
classification**:**
cvss-metrics**:** "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
cvss-score**:** 9.8
cve-id**:** CVE-2024-XXXXX
tags**:** "cve,cve2024,example,unauth"
关键点: - id: 必须全局唯一,建议遵循 CVE-年份-编号 或 厂商-产品-漏洞类型 的命名规范。 - severity: 严格依据 CVSS 评分填写,可选值为 info, low, medium, high, critical。 - tags: 使用逗号分隔,便于 nuclei -tags 进行筛选。
http**:**
- raw**:**
- |
GET /api/admin/config HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0
matchers-condition**:** and
matchers**:**
- type**:** status
status**:**
- 200
- type**:** word
words**:**
- "db_password"
- "internal_api_key"
condition**:** and
Nuclei 模板基于 YAML 格式,语法错误是导致模板加载失败的主要原因。
Nuclei 提供了强大的动态变量替换机制,避免硬编码:
|
变量 |
说明 |
示例 |
|---|---|---|
|
{{BaseURL}} |
目标基础 URL |
https://example.com |
|
{{Hostname}} |
仅主机名(含端口) |
example.com:8080 |
|
{{RootURL}} |
协议+主机+端口 |
https://example.com:8080 |
|
{{randstr}} |
随机字符串 |
用于探测反射型 XSS 或盲注 |
|
{{date}} |
当前日期 |
用于时间戳相关测试 |
缩进: 严格使用2个空格,禁止使用 Tab。
特殊字符: 包含:, {, }, | 的字符串必须使用双引号包裹。
多行文本: 使用| (保留换行) 或 > (折叠换行) 处理 Raw 请求体。
注释: 使用# 添加注释,解释复杂的正则或匹配逻辑,提高可读性。
这是 PoC 的灵魂,决定了检测的准确性。
原则:多维度交叉验证,拒绝单一指标。
Status Code: 仅作为辅助条件,不要单独使用。
Word: 匹配响应体中的特征字符串。务必设置part: body 或 part: header,避免全量搜索导致的性能损耗。
Regex: 用于匹配动态内容(如版本号、Token)。```yaml
type: regex regex:
‘version:?(..)’ part: body ```
DSL: 用于复杂的逻辑判断。```yaml
type: dsl dsl:
“status_code == 200 && contains(body, ‘success’) && !contains(body, ‘error’)” ```
用于从响应中提取关键数据(如 POC 验证所需的 Token、版本号),通常与 Matchers 配合使用。
extractors**:**
- type**:** regex
part**:** body
group**:** 1
regex**:**
- '"token":"([a-zA-Z0-9_-]+)"'
技巧: - 使用 group: 1 仅提取正则捕获组内容,而非整个匹配行。 - 设置 internal: true 可将提取结果作为变量供后续请求使用(多步 PoC 必备)。
只读优先: 默认使用GET 请求。若必须使用 POST/PUT,确保 Payload 不会修改、删除数据或触发业务逻辑(如发送邮件、创建订单)。
避免DoS: 禁止在 PoC 中使用递归请求、大文件下载或高并发 Payload。
随机化: 文件名、参数值使用{{randstr}},防止 WAF 拦截或日志污染。
减少请求数: 尽量在单次请求中完成验证。
Stop-at-first-match: 对于多Path 探测,设置 stop-at-first-match: true,命中即停。
精确匹配: 正则表达式避免使用.* 等贪婪匹配,使用 [^"]+ 等限定符。
自描述: name和 description 要清晰说明漏洞原理,而非仅写 “Check vulnerability”。
引用权威: reference必须包含官方公告、CVE 详情页或高质量技术分析文章。
版本兼容: 若漏洞仅影响特定版本,在description 或 tags 中注明,或使用 DSL 进行版本预检。
|
错误类型 |
典型表现 |
解决方案 |
|---|---|---|
|
高误报 |
仅匹配状态码 200 |
增加 Body 关键字或 Regex 校验,使用 matchers-condition: and |
|
YAML 解析失败 |
yaml: line X: mapping values are not allowed |
检查缩进,特殊字符加引号,使用在线 YAML Lint 工具验证 |
|
Payload 被拦截 |
403 Forbidden |
修改 User-Agent,对 Payload 进行 URL 编码或 Unicode 编码 |
|
逻辑漏洞 |
验证了错误页面 |
确认匹配特征在漏洞存在时才出现,而非错误页面或默认页面 |
|
路径硬编码 |
/admin/login 写死 |
使用 {{BaseURL}} 拼接,支持子目录部署场景 |
本地验证: 使用nuclei -t template.yaml -u target -debug 查看完整请求/响应。
单元测试: 使用nuclei -t template.yaml -u target -jsonl -o result.json 验证输出格式。
误报测试: 在已知安全的目标上运行,确认无误报。
社区规范: 提交前运行nuclei -t template.yaml -validate 确保符合官方规范。
编写优秀的 Nuclei PoC 不仅是技术的体现,更是对安全责任的践行。始终牢记:精准、安全、可复现是衡量一个 PoC 价值的唯一标准。