Skip to main content
Nuclei 支持基于 HTTP 请求中 fuzzing 部分定义的规则对 HTTP 请求进行 fuzzing。这允许创建针对通用 Web 应用程序漏洞(如 SQLi、SSRF、CMDi 等)的模板,而无需像传统 web fuzzer 那样获取目标的任何信息。我们将这一概念称为未知漏洞 Fuzzing

pre-condition(前置条件)

通常情况下,我们只希望在有意义的请求上尝试 fuzzing。例如:
  • 当存在 Body 时才对 Body 进行 Fuzz
  • 忽略 PreFlight 和 CONNECT 请求
等等。在 Nuclei v3.2.4 中,我们引入了新的 pre-condition 部分,其中包含了 fuzzing 模板应该执行的条件。 pre-condition 可以被视为 nuclei 中 matchers 的孪生兄弟。它们支持所有匹配器类型,包括 DSL,唯一的区别是它们服务于不同的目的。 例如,要仅在具有某些 body 的 POST 请求上执行模板,可以使用以下过滤器:
- pre-condition:
    - type: dsl
      dsl:
        - method == POST
        - len(body) > 0
      condition: and
目前,只有 header、host、input、method、path 等请求数据可用,但很快,一旦添加了加载响应和请求的支持,响应数据也将可用。
在编写/执行模板时,可以使用 -v -svd 标志查看应用过滤器之前可用的所有变量。

Part(部分)

Part 指定请求的哪一部分应该根据指定的规则进行 fuzzing。该参数的可用选项有: query默认)- 对 URL 的查询参数进行 fuzzing
fuzzing:
  - part: query # 对 URL 查询中的参数进行 fuzzing
path - 对请求的路径参数进行 fuzzing
fuzzing:
  - part: path # 对路径参数进行 fuzzing
header - 对请求的头部参数进行 fuzzing
fuzzing:
  - part: header # 对头部进行 fuzzing
cookie - 对请求的 cookie 参数进行 fuzzing
fuzzing:
  - part: cookie # 对 cookies 进行 fuzzing
body - 对请求的 body 参数进行 fuzzing
fuzzing:
  - part: body # 对 body 中的参数进行 fuzzing

特殊部分

request - 对整个请求进行 fuzzing(上面提到的所有部分)
fuzzing:
  - part: request # 对整个请求进行 fuzzing

多重选择部分

可以通过定义 parts 字段(即上述选项的复数形式)来选择多个部分进行 fuzzing。
fuzzing:
  - parts:
      - query
      - body
      - header

Type(类型)

Type 指定了要为 fuzzing 规则值执行的替换类型。该参数的可用选项有:
  1. replace默认)- 使用 payload 替换值
  2. prefix - 使用 payload 作为值的前缀
  3. postfix - 使用 payload 作为值的后缀
  4. infix - 使用 payload 作为值的中缀(放在中间)
  5. replace-regex - 使用正则表达式通过 payload 替换值
fuzzing:
  - part: query
    type: postfix # 对查询进行 fuzzing 并将 payload 作为参数的后缀

Key-Value 抽象

在 HTTP 请求中,有各种部分如 query、path、headers、cookies 和 body,每个部分在不同格式中有所不同。例如,query 部分是键值对,path 部分是值列表,body 部分可以是 JSON、XML 或 form-data。 为了有效地抽象这些部分并允许它们被 fuzzed,Nuclei 将这些值暴露为 keyvalue 对。这允许用户基于请求部分的键或值进行 fuzzing。 例如,下面的示例 HTTP 请求可以抽象为如下所示的键值对:
POST /reset-password?token=x0x0x0&source=app HTTP/1.1
Host: 127.0.0.1:8082
User-Agent: Go-http-client/1.1
Cookie: PHPSESSID=1234567890
Content-Length: 23
Content-Type: application/json
Accept-Encoding: gzip
Connection: close

{"password":"12345678"}
  • part: Query
keyvalue
tokenx0x0x0
sourceapp
  • part: Path
keyvalue
value/reset-password
  • part: Header
keyvalue
Host127.0.0.1:8082
User-AgentGo-http-client/1.1
Content-Length23
Content-Typeapplication/json
Accept-Encodinggzip
Connectionclose
  • part: Cookie
keyvalue
PHPSESSID1234567890
  • part: Body
keyvalue
password12345678
注意: XML、JSON、Form、Multipart-FormData 将采用 kv 格式,但如果 Body 是二进制或任何其他格式,整个 Body 将表示为单个键值对,键为 value,值为整个 Body。
keyvalue
value”\x08\x96\x01\x12\x07\x74”
这种抽象真正提升了效率,因为你只需要为 Body 编写一个规则,它就会应用于所有格式。例如,如果你检查 body 值中的 SQLi,单个规则将适用于所有格式,即 JSON、XML、Form、Multipart-FormData 等。

Mode(模式)

Mode 指定执行替换的模式。可用模式有:
  1. multiple默认)- 一次替换所有值
  2. single - 一次替换一个值
fuzzing:
  - part: query
    type: postfix
    mode: multiple # 对查询进行 fuzzing,同时将 payloads 作为所有参数的后缀
注意:当未定义其他选项时,将设置/使用默认值。

组件数据过滤

支持多种过滤器,以将 fuzzing 的范围限制为仅感兴趣的参数键和值。Nuclei HTTP Fuzzing 引擎将请求部分转换为键和值,然后可以通过相关选项进行过滤。 支持以下过滤字段:
  1. keys - 要进行 fuzzing 的参数名称列表(精确匹配)
  2. keys-regex - 要进行 fuzzing 的参数正则表达式列表
  3. values - 要进行 fuzzing 的值正则表达式列表
这些过滤器可以组合使用,基于参数输入运行高度针对性的 fuzzing。下面提供了一些此类过滤的示例:
# 基于参数名称值进行命令注入 fuzzing
fuzzing:
  - part: query
    type: replace
    mode: single
    keys:
      - "daemon"
      - "upload"
      - "dir"
      - "execute"
      - "download"
      - "log"
      - "ip"
      - "cli"
      - "cmd"
# 基于参数名称正则表达式进行开放重定向 fuzzing
fuzzing:
  - part: query
    type: replace
    mode: single
    keys-regex:
      - "redirect.*"
# 基于参数值正则表达式进行 SSRF fuzzing
fuzzing:
  - part: query
    type: replace
    mode: single
    values:
      - "https?://.*"

Fuzz

Fuzz 指定用于参数的 type 替换值。它支持 payloads、DSL 函数等,并允许用户充分利用现有的 nuclei 功能集进行 fuzzing。
# 使用 stop-at-first-match 进行 XSS fuzzing 的 fuzz 部分
payloads:
  reflection:
    - "6842'\"><9967"
stop-at-first-match: true
fuzzing:
  - part: query
    type: postfix
    mode: single
    fuzz:
      - "{{reflection}}"
# 使用 interactsh-url 占位符进行 oob 测试
payloads:
  redirect:
    - "{{interactsh-url}}"
fuzzing:
  - part: query
    type: replace
    mode: single
    keys:
      - "dest"
      - "redirect"
      - "uri"
    fuzz:
      - "https://{{redirect}}"
# 使用模板级变量进行 SSTI 测试
variables:
  first: "{{rand_int(10000, 99999)}}"
  second: "{{rand_int(10000, 99999)}}"
  result: "{{to_number(first)*to_number(second)}}"

http:
    ...
    payloads:
      reflection:
        - '{{concat("{{", "§first§*§second§", "}}")}}'
    fuzzing:
      - part: query
        type: postfix
        mode: multiple
        fuzz:
          - "{{reflection}}"

Analyzer(分析器)

Analyzers 是 nuclei fuzzing 中引入的一个新概念,它允许引擎基于特定逻辑进行额外的验证请求,以验证漏洞。

time_delay

time_delay 分析器验证请求的响应时间是否可由 fuzzed payload 控制。它使用从 ZAP 移植的线性回归算法,通过交替请求来确定服务器时间实际上是可控制的,而不仅仅是噪音。你可以像这样配置它:
# 创建一个新的时间延迟分析器
analyzer:
  name: time_delay
  # 可选地,你可以像下面这样定义分析器的参数。
  # 
  # 默认值对于大多数用例已足够好。
  parameters:
    sleep_duration: 10 # 睡眠 10 秒(默认值:5)
    requests_limit: 6 # 发出 6 个验证请求(默认值:4)
    time_correlation_error_range: 0.30 # 时间相关性的错误范围(默认值:0.15)
    time_slope_error_range: 0.40 # 时间斜率的错误范围(默认值:0.30)
以下动态占位符在带有 time_delay 分析器的 payloads 中可用:
  • [SLEEPTIME] - 时间延迟分析器的睡眠时间(以秒为单位)。
  • [INFERENCE] - 时间延迟分析器的推断条件 (%d=%d)。
这些值会在运行时用分析器的实际值替换。以下是一个通常的验证过程:
  1. 使用 payload 向目标发送请求,延迟 5 秒。
  2. 如果响应时间小于 5,不执行任何操作。
  3. 将请求发送到分析器,该分析器将其排队,延迟 5 秒。
  4. 接下来是 1 秒延迟
  5. 接下来是 5 秒延迟
  6. 最后,最后 1 秒延迟。
如果响应时间是可控的,分析器将报告漏洞。 分析器匹配的匹配也相当简单。与 interactsh 类似,你可以使用 part: analyzer 来匹配分析器响应。
matchers:
  - type: word
    part: analyzer
    words:
      - "true"
可选地,你还可以从分析器中提取 analyzer_details 进行匹配。

示例 Fuzzing 模板

下面提供了一个用于 fuzzing XSS 漏洞的示例模板:
id: fuzz-reflection-xss

info:
  name: Basic Reflection Potential XSS Detection
  author: pdteam
  severity: low

http:
  - pre-condition:
      - type: dsl
        dsl:
          - 'method == "GET"'       # 仅在方法为 GET 时运行
    payloads:
      reflection:
        - "6842'\"><9967"

    stop-at-first-match: true
    fuzzing:
      - part: query
        type: postfix
        mode: single
        fuzz:
          - "{{reflection}}"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "{{reflection}}"

      - type: word
        part: header
        words:
          - "text/html"
更完整的示例在这里提供