Documentation Index
Fetch the complete documentation index at: https://projectdiscovery.sec-lab.cn/llms.txt
Use this file to discover all available pages before exploring further.
匹配器允许对协议响应进行不同类型的灵活比较。这是使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
Word和Regex匹配器可以根据用户的需求进行进一步配置。
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_length | Content-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) |
单个匹配器中可以指定多个单词和正则表达式,并且可以使用不同的条件如AND和OR进行配置。当未指定条件时,默认使用OR。
- AND - 使用AND条件允许匹配匹配器的单词列表中的所有单词。只有当所有单词都匹配时,请求才会被标记为成功。
- 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
在这种情况下,全局匹配器正在寻找非对称私钥和Slack webhook。如您在输出中所见,它在来自其他模板的请求中找到了匹配项,尽管匹配逻辑仅在全局匹配器模板中定义了一次。这使得在多个请求中检测模式非常高效,而无需在每个模板中复制代码。