Skip to main content
匹配器允许对协议响应进行不同类型的灵活比较。这是使nuclei如此强大的原因,检查非常简单易写,并且可以根据需要添加多个检查以进行非常有效的扫描。

类型

一个请求中可以指定多个匹配器。基本上有7种类型的匹配器:
匹配器类型匹配部分
status部分的整数比较
size部分的内容长度
word协议的部分
regex协议的部分
binary协议的部分
dsl协议的部分
xpath协议的部分
要匹配响应的状态码,可以使用以下语法。
matchers:
  # 匹配状态码
  - type: status
    # 我们想要匹配的一些状态码
    status:
      - 200
      - 302
要匹配十六进制响应的二进制数据,可以使用以下语法。
matchers:
  - type: binary
    binary:
      - "504B0304" # zip压缩文件
      - "526172211A070100" # RAR压缩文件 版本5.0
      - "FD377A585A0000" # xz tar.xz压缩文件
    condition: or
    part: body
匹配器还支持十六进制编码的数据,这些数据将被解码并匹配。
matchers:
  - type: word
    encoding: hex
    words:
      - "50494e47"
    part: body
WordRegex匹配器可以根据用户的需求进行进一步配置。 XPath匹配器使用XPath查询来匹配XML和HTML响应。如果XPath查询返回任何结果,则被视为匹配。
matchers:
  - type: xpath
    part: body
    xpath:
      - "/html/head/title[contains(text(), 'Example Domain')]"
dsl类型的复杂匹配器允许使用辅助函数构建更复杂的表达式。这些函数允许访问包含各种数据的协议响应,具体取决于每个协议。请参阅特定协议的文档了解不同的返回结果。
matchers:
  - type: dsl
    dsl:
      - "len(body)<1024 && status_code==200" # 正文长度小于1024且状态码为200
      - "contains(toupper(body), md5(cookie))" # 检查cookie的MD5值是否包含在大写的正文中
协议响应的每个部分都可以用DSL匹配器匹配。一些例子 -
响应部分描述示例
content_lengthContent-Length头content_length >= 1024
status_code响应状态码status_code==200
all_headers包含所有头的唯一字符串len(all_headers)
body正文字符串len(body)
header_name小写头名称,-转换为_len(user_agent)
raw头+响应len(raw)

条件

单个匹配器中可以指定多个单词和正则表达式,并且可以使用不同的条件如ANDOR进行配置。当未指定条件时,默认使用OR
  1. AND - 使用AND条件允许匹配匹配器的单词列表中的所有单词。只有当所有单词都匹配时,请求才会被标记为成功。
  2. OR - 使用OR条件允许匹配匹配器的列表中的单个单词。当匹配器的任何一个单词匹配时,请求将被标记为成功。

匹配部分

还可以为请求匹配响应的多个部分,如果未定义,默认匹配部分是body 使用AND条件的HTTP响应体匹配器示例:
matchers:
  # 匹配正文单词
  - type: word
   # 我们想要匹配的一些单词
   words:
     - "[core]"
     - "[config]"
   # 两个单词都必须在响应正文中找到
   condition: and
   # 我们要匹配请求正文(默认)
   part: body
类似地,可以编写匹配器来匹配您想在响应正文中找到的任何内容,允许无限的创造性和可扩展性。

否定匹配器

所有类型的匹配器也支持否定条件,当您需要排除某些匹配时非常有用。这可以通过在matchers块中添加negative: true来使用。 以下是使用negative条件的示例语法,这将返回响应头中没有PHPSESSID的所有URL。
matchers:
  - type: word
    words:
      - "PHPSESSID"
    part: header
    negative: true

多个匹配器

在单个模板中可以使用多个匹配器,通过单个请求对多个条件进行指纹识别。 以下是多个匹配器的语法示例。
matchers:
  - type: word
    name: php
    words:
      - "X-Powered-By: PHP"
      - "PHPSESSID"
    part: header
  - type: word
    name: node
    words:
      - "Server: NodeJS"
      - "X-Powered-By: nodejs"
    condition: or
    part: header
  - type: word
    name: python
    words:
      - "Python/2."
      - "Python/3."
    condition: or
    part: header

匹配器条件

在使用多个匹配器时,默认条件是在所有匹配器之间遵循OR操作,可以使用AND操作来确保只有当所有匹配器返回true时才返回结果。
    matchers-condition: and
    matchers:
      - type: word
        words:
          - "X-Powered-By: PHP"
          - "PHPSESSID"
        condition: or
        part: header

      - type: word
        words:
          - "PHP"
        part: body

内部匹配器

在编写多协议或基于flow的模板时,可能会有一种情况,我们需要验证/匹配第一个请求,然后再进行下一个请求,一个很好的例子是CVE-2023-6553 在此模板中,我们首先使用匹配器检查目标是否实际使用了Backup Migration插件,如果为true,则在flow的帮助下继续下一个请求 但这将打印两个结果,每个请求匹配一个,由于我们使用第一个请求匹配器作为继续下一个请求的先决条件,我们可以使用internal: true在匹配器块中将其标记为内部。
id: CVE-2023-6553

info:
  name: Worpress Backup Migration <= 1.3.7 - Unauthenticated Remote Code Execution
  author: FLX
  severity: critical

flow: http(1) && http(2)

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/backup-backup/readme.txt"

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "Backup Migration")'
        condition: and
        internal: true  # <- 更新逻辑(这将跳过打印此事件/结果)

  - method: POST
    path:
      - "{{BaseURL}}/wp-content/plugins/backup-backup/includes/backup-heart.php"
    headers:
      Content-Dir: "{{rand_text_alpha(10)}}"

    matchers:
      - type: dsl
        dsl:
          - 'len(body) == 0'
          - 'status_code == 200'
          - '!contains(body, "Incorrect parameters")'
        condition: and

全局匹配器

全局匹配器本质上是适用于运行其他模板时接收到的所有HTTP响应的matchers。这使它们对于被动检测、指纹识别、发现错误、WAF检测、识别异常行为,甚至捕获秘密和信息泄漏非常有用。通过将global-matchers设置为true,您可以启用模板自动匹配由其他模板触发的事件,而无需单独配置它们。
  • 全局匹配器仅适用于基于HTTP协议的模板。
  • 启用全局匹配器时,不会发送模板中定义的请求。
  • 此功能不仅限于matchers;您还可以在全局匹配器模板中定义extractors
让我们看一个快速示例,了解它的工作原理:
# http-template-with-global-matchers.yaml
http:
  - global-matchers: true
    matchers-condition: or
    matchers:
      - type: regex
        name: asymmetric_private_key
        regex:
          - '-----BEGIN ((EC|PGP|DSA|RSA|OPENSSH) )?PRIVATE KEY( BLOCK)?-----'
        part: body

      - type: regex
        name: slack_webhook
        regex:
          - >-
            https://hooks.slack.com/services/T[a-zA-Z0-9_]{8,10}/B[a-zA-Z0-9_]{8,12}/[a-zA-Z0-9_]{23,24}
        part: body
在此示例中,我们使用了一个将global-matchers设置为true的模板。它在所有HTTP请求中查找特定模式,如非对称私钥或Slack webhook。现在,当您运行此模板以及其他模板时,全局匹配器将自动检查所有HTTP响应中的这些模式。您不必在每个模板中单独设置匹配器即可使其工作。 要运行它,使用如下命令:
> nuclei -egm -u http://example.com -t http-template-with-global-matchers.yaml -t http-template-1.yaml -t http-template-2.yaml -silent
[http-template-with-global-matchers:asymmetric_private_key] http://example.com/request-from-http-template-1
[http-template-with-global-matchers:slack_webhook] http://example.com/request-from-http-template-2
全局匹配器默认不应用。您需要使用-enable-global-matchers/-egm标志或通过nuclei.EnableGlobalMatchersTemplates以编程方式显式启用它们(如果您正在使用Nuclei SDK)。
在这种情况下,全局匹配器正在寻找非对称私钥和Slack webhook。如您在输出中所见,它在来自其他模板的请求中找到了匹配项,尽管匹配逻辑仅在全局匹配器模板中定义了一次。这使得在多个请求中检测模式非常高效,而无需在每个模板中复制代码。