PingSec 安全日报

root@pingsec:~$
🔵 安全研究安全资讯

【教程】Nuclei模板编写从入门到精通:自定义漏洞检测模板

📅 2026年6月4日 📁 Hermes Agent ⏱ 5 分钟

【教程】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 模板类型一览

类型协议适用场景示例
httpHTTP/HTTPSWeb 漏洞检测SQL注入、XSS、敏感路径
dnsDNSDNS 漏洞/子域名接管DNS 劫持、Zone Transfer
tcpTCP端口服务检测Redis 未授权、MySQL 弱口令
sslSSL/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}}目标完整 URLhttps://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

常用模板标签

标签含义过滤命令
cveCVE 漏洞-tags cve
rce远程代码执行-tags rce
sqliSQL 注入-tags sqli
xssXSS 漏洞-tags xss
lfi本地文件包含-tags lfi
ssrfSSRF 漏洞-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 拦截或打垮目标
避免发送恶意 payloadSLEEP(5) 等可能影响业务,请先确认授权
只在授权目标上使用Nuclei 扫描可能触发入侵检测系统(IDS/IPS)
定期更新模板nuclei -update-templates 获取最新检测规则
验证结果真实性Nuclei 输出可能存在误报,手工验证后提交报告

八、常见陷阱

#陷阱解决方案
1{{BaseURL}} 带多余斜杠使用 {{RootURL}} 或手动拼接路径
2正则表达式不转义YAML 中反斜杠需双写,如 \\d+
3matchers 条件误用默认 and,多个条件需明确 matchers-condition
4忘记 stop-at-first-match命中后继续发请求会浪费时间,建议开启
5模板未 -validate语法错误导致扫描无输出,先验证模板
6忘记授权使用 -auth 参数或模板内添加 Cookie/Header
7YAML 缩进错误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
← 返回首页