【教程】Nuclei模板编写从入门到精通:自定义漏洞检测模板
适合人群:安全测试工程师、漏洞挖掘爱好者、想要自动化漏洞检测的渗透测试人员
前置知识:YAML基础语法、HTTP协议基本概念、正则表达式基础
实验环境:Linux + Nuclei v3+ + 浏览器
一、前置准备
1.1 安装 Nuclei
# 方式一:Go 安装(推荐)
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# 方式二:Release 二进制
wget https://github.com/projectdiscovery/nuclei/releases/latest/download/nuclei-linux-amd64.zip
unzip nuclei-linux-amd64.zip && mv nuclei /usr/local/bin/
# 方式三:Kali/APT
apt install nuclei
# 验证安装
nuclei -version
1.2 模板目录结构
# 默认模板目录
~/.nuclei/
├── nuclei-templates/ # 官方模板库(自动更新)
└── custom-templates/ # 自定义模板(自己创建)
# 推荐在项目目录下创建独立模板目录
mkdir -p my-templates
cd my-templates
1.3 更新官方模板库
nuclei -update-templates
# 或指定模板目录
nuclei -update-templates -directory ~/nuclei-templates
二、核心原理
2.1 Nuclei 是什么?
Nuclei 是 ProjectDiscovery 团队开发的一款基于模板的漏洞扫描器。它的核心理念是:
将漏洞检测逻辑写成 YAML 模板文件,Nuclei 引擎执行模板并输出结果
这意味着你无需写 Python/Go 代码,只要会写 YAML 就能自动化检测漏洞。
2.2 模板执行流程
输入目标(URL/IP)
↓
加载模板(YAML 文件)
↓
发送请求(HTTP/DNS/TCP/File 等协议)
↓
匹配响应(状态码/正文/Header/正则)
↓
输出结果(发现漏洞 / 未发现)
2.3 模板类型一览
| 类型 | 协议 | 适用场景 | 示例 |
|---|---|---|---|
| http | HTTP/HTTPS | Web 漏洞检测 | SQL注入、XSS、敏感路径 |
| dns | DNS | DNS 漏洞/子域名接管 | DNS 劫持、Zone Transfer |
| tcp | TCP | 端口服务检测 | Redis 未授权、MySQL 弱口令 |
| ssl | SSL/TLS | 证书安全检测 | 过期证书、弱加密套件 |
| file | 文件读取 | 本地文件检测 | 读取 /etc/passwd |
| headless | 浏览器 | 客户端漏洞 | DOM XSS、CSRF Token 提取 |
| network | 网络协议 | 自定义网络协议 | Modbus、MQTT 等 |
2.4 模板文件结构(核心字段)
id: example-vuln # 模板唯一 ID(必填)
info:
name: 漏洞名称 # 模板展示名
severity: high # high/medium/critical/low/info
description: "漏洞描述" # 详细描述
author: author_name # 作者
tags: web,example # 标签(用于分类和过滤)
reference: # 参考链接
- https://example.com/cve-123
requests: # HTTP 请求定义(核心)
- method: GET # 请求方法
path: # 请求路径
- "{{BaseURL}}/vuln-path"
matchers: # 匹配规则
- type: word
words:
- "vulnerable string"
三、实操步骤
🔴 模板一:检测敏感文件泄露(基础入门)
# 文件名: sensitive-file.yaml
id: sensitive-file-example
info:
name: Sensitive File Disclosure
author: pingsec
severity: medium
description: "检测常见的敏感文件泄露"
tags: exposure,file
requests:
- method: GET
path:
- "{{BaseURL}}/.env"
- "{{BaseURL}}/.git/config"
- "{{BaseURL}}/wp-config.php.bak"
- "{{BaseURL}}/config.json"
- "{{BaseURL}}/backup.sql"
matchers-condition: or
matchers:
- type: word
words:
- "DB_PASSWORD"
- "APP_KEY"
- "DB_HOST"
- "database_name"
condition: or
- type: word
words:
- "[core]"
- "repositoryformatversion"
condition: or
运行:
nuclei -t sensitive-file.yaml -u https://target.com
🔴 模板二:SQL 注入检测(带 Payload 和策略)
# 文件名: sql-injection-detect.yaml
id: sql-injection-basic
info:
name: Basic SQL Injection Detection
author: pingsec
severity: critical
description: "通过时间盲注和报错注入检测 SQL 注入漏洞"
tags: sql-injection, sqli
requests:
- method: GET
path:
- "{{BaseURL}}/search?q={{url_encode('\\' OR 1=1 --')}}"
- "{{BaseURL}}/product?id={{url_encode('1 AND SLEEP(5)')}}"
- "{{BaseURL}}/user?id={{url_encode('1\\' UNION SELECT 1,2,3,4--')}}"
stop-at-first-match: true
matchers-condition: or
matchers:
- type: word
words:
- "SQL syntax"
- "mysql_fetch"
- "You have an error in your SQL"
- "Unclosed quotation mark"
- "Warning: mysql"
condition: or
part: body
- type: status
status:
- 500
part: header
🔴 模板三:CVE-2026-XXXXX 示例(带 Extract 高级匹配)
id: cve-2026-example
info:
name: CVE-2026-XXXXX Example Vuln
author: pingsec
severity: high
description: "检测某个已知 CVE 漏洞"
reference:
- https://example.com/cve-2026-xxxxx
tags: cve,cve2026,rce
requests:
- method: GET
path:
- "{{BaseURL}}/api/debug?cmd=id"
- "{{BaseURL}}/console?action=whoami"
matchers-condition: and
matchers:
- type: word
words:
- "uid="
- "gid="
condition: or
part: body
- type: status
status:
- 200
extractors:
- type: regex
name: command_output
part: body
regex:
- "uid=\\d+\\(\\w+\\).*"
- "groups=\\d+.*"
group: 0
运行含提取结果:
nuclei -t cve-2026-example.yaml -u https://target.com -v
# 输出会显示提取的命令执行结果
🔴 模板四:POST 请求 + 多条件匹配
id: admin-panel-bruteforce
info:
name: Admin Panel Default Credential Check
author: pingsec
severity: high
description: "检测管理后台默认密码"
tags: admin,bruteforce
requests:
- method: POST
path:
- "{{BaseURL}}/admin/login.php"
- "{{BaseURL}}/login"
- "{{BaseURL}}/admin/"
headers:
Content-Type: application/x-www-form-urlencoded
body: 'username=admin&password=admin&submit=1'
matchers-condition: and
matchers:
- type: word
words:
- "dashboard"
- "admin"
- "welcome"
condition: or
part: body
- type: word
words:
- "Invalid"
- "Error"
- "Login failed"
condition: or
part: body
negative: true
🔴 模板五:多协议 — DNS 检测(子域名接管)
id: subdomain-takeover-check
info:
name: Subdomain Takeover Detection
author: pingsec
severity: high
description: "检测 DNS CNAME 指向未托管服务的子域名"
tags: takeover,dns
dns:
- name: "{{FQDN}}"
type: CNAME
matchers-condition: and
matchers:
- type: dns
dns:
- type: CNAME
value: ".*\\.amazonaws\\.com"
regex: true
- type: CNAME
value: ".*\\.azureedge\\.net"
regex: true
- type: CNAME
value: ".*\\.cloudfront\\.net"
regex: true
- type: CNAME
value: ".*github\\.io"
regex: true
condition: or
- type: dns
dns:
- type: NXDOMAIN
value: true
四、模板编写高级技巧
4.1 模板调试
# 验证模板语法
nuclei -validate -t my-template.yaml
# 详细输出模式
nuclei -t my-template.yaml -u https://target.com -debug
# 查看原始请求和响应
nuclei -t my-template.yaml -u https://target.com -debug-req -debug-resp
4.2 变量系统
| 变量 | 说明 | 示例 |
|---|---|---|
{{BaseURL}} | 目标完整 URL | https://target.com |
{{Hostname}} | 目标主机名 | target.com |
{{Port}} | 目标端口 | 443 |
{{url_encode:xxx}} | URL 编码 | %27%20OR%201%3D1 |
{{randstr}} | 随机字符串 | a3b8c9d2 |
{{rand_int}} | 随机整数 | 45321 |
{{hex_encode:xxx}} | 十六进制编码 | 61646d696e |
{{base64_encode:xxx}} | Base64 编码 | YWRtaW4= |
4.3 使用 Fuzzing(模糊测试)
requests:
- method: GET
path:
- "{{BaseURL}}/api/{{fuzz}}"
payloads:
fuzz:
- "users"
- "admin"
- "config"
- "debug"
- "backup"
- "api-docs"
stop-at-first-match: true
...
4.4 动态标签高级用法
requests:
- method: GET
path:
- "{{BaseURL}}/"
# 提取 CSRF Token 用于后续请求
extractors:
- type: regex
name: csrf_token
part: body
regex:
- 'name="csrf_token" value="([^"]+)"'
group: 1
- method: POST
path:
- "{{BaseURL}}/login"
body: 'username=test&password=test&csrf_token={{csrf_token}}'
五、Payload 速查表
HTTP 模板常用匹配模式
| 匹配类型 | 使用场景 | 关键词示例 |
|---|---|---|
word | 字符串匹配 | "root:x:", "PHP Version" |
regex | 正则匹配 | "uid=\\d+\\(\\w+\\)" |
binary | 二进制匹配 | "504B0304"(ZIP 魔数) |
status | 状态码匹配 | 200, 403, 500 |
dsl | 表达式匹配 | len(body)>1000 |
常用模板标签
| 标签 | 含义 | 过滤命令 |
|---|---|---|
cve | CVE 漏洞 | -tags cve |
rce | 远程代码执行 | -tags rce |
sqli | SQL 注入 | -tags sqli |
xss | XSS 漏洞 | -tags xss |
lfi | 本地文件包含 | -tags lfi |
ssrf | SSRF 漏洞 | -tags ssrf |
misconfig | 配置错误 | -tags misconfig |
六、实战案例复盘
场景:自动化检测 Spring Boot Actuator 泄露
有一次渗透测试中,客户要求对 200+ 子域名进行 Spring Boot Actuator 泄露检测。手动测试每个端点效率极低,于是编写了 Nuclei 模板:
id: spring-actuator-check
info:
name: Spring Boot Actuator Exposure
severity: high
description: "检测 Spring Boot Actuator 端点暴露"
tags: spring,exposure,misconfig
requests:
- method: GET
path:
- "{{BaseURL}}/actuator"
- "{{BaseURL}}/actuator/env"
- "{{BaseURL}}/actuator/health"
- "{{BaseURL}}/actuator/beans"
- "{{BaseURL}}/actuator/auditevents"
matchers:
- type: word
words:
- "_links"
- "spring.application"
- "spring.datasource"
- "activeProfiles"
- "JAVA_HOME"
condition: or
运行结果:针对 200+ 目标,单次扫描发现 18 个 存在 Actuator 泄露的站点,其中 3 个 暴露了数据库密码和 AWS 密钥。
七、防御建议
| 防护措施 | 说明 |
|---|---|
| 限制 Nuclei 扫描速率 | 使用 -rate-limit 50 避免被 WAF 拦截或打垮目标 |
| 避免发送恶意 payload | 如 SLEEP(5) 等可能影响业务,请先确认授权 |
| 只在授权目标上使用 | Nuclei 扫描可能触发入侵检测系统(IDS/IPS) |
| 定期更新模板 | nuclei -update-templates 获取最新检测规则 |
| 验证结果真实性 | Nuclei 输出可能存在误报,手工验证后提交报告 |
八、常见陷阱
| # | 陷阱 | 解决方案 |
|---|---|---|
| 1 | {{BaseURL}} 带多余斜杠 | 使用 {{RootURL}} 或手动拼接路径 |
| 2 | 正则表达式不转义 | YAML 中反斜杠需双写,如 \\d+ |
| 3 | matchers 条件误用 | 默认 and,多个条件需明确 matchers-condition |
| 4 | 忘记 stop-at-first-match | 命中后继续发请求会浪费时间,建议开启 |
| 5 | 模板未 -validate | 语法错误导致扫描无输出,先验证模板 |
| 6 | 忘记授权 | 使用 -auth 参数或模板内添加 Cookie/Header |
| 7 | YAML 缩进错误 | Nuclei 使用 2 空格缩进,Tab 会导致解析失败 |
九、总结
速查:编写一个 Nuclei 模板的 6 步流程
1. 确定漏洞类型和检测方法 → id + info 元信息
2. 设计请求路径和 Payload → requests.path
3. 编写匹配规则 → matchers 匹配响应特征
4. (可选)添加提取器 → extractors 获取关键数据
5. 本地验证 → nuclei -validate && nuclei -t xxx.yaml -u https://test.com -debug
6. 批量扫描 → nuclei -t xxx.yaml -l targets.txt -o results.txt
一句话记住:Nuclei = YAML 描述漏洞特征 → 引擎自动检测 → 结果导出。会写 YAML 就会写漏洞检测脚本!
更多资源:
- 官方模板仓库:https://github.com/projectdiscovery/nuclei-templates
- 模板编写文档:https://docs.projectdiscovery.io/templates/introduction
- 在线模板调试:https://play.nuclei.sh