Nuclei 模板编写笔记
快速编写模版流程
辅助插件
- nuclei:官方插件
- Nu_Te_Gen:社区插件
具体步骤
- 右键将数据包发送到 nuclei 插件,选择创建模板或者追加到模板
- 再使用 Nu_Te_Gen 插件生成合适的匹配器,或者查询内置函数文档
模板命名规范
- ID 使用小写字母、数字和连字符
- 名称要描述性强且简洁
- 标签要准确分类
调试命令
常用模板调试相关参数
# 详细输出
nuclei -t template.yaml -u target.com -v
# 调试模式
nuclei -t template.yaml -u target.com -debug
# 显示请求/响应
nuclei -t template.yaml -u target.com -debug-req -debug-resp
# 验证模板语法
nuclei -t template.yaml -validate
# 验证并显示详细信息
nuclei -t template.yaml -validate -v
在编写模板后,务必进行语法验证:
# 验证单个模板
nuclei -t my-template.yaml -validate
# 验证目录中的所有模板
nuclei -t templates/ -validate
# 验证并显示警告
nuclei -t template.yaml -validate -v
常见验证错误:
- YAML 语法错误
- 缺少必需字段
- 无效的匹配器类型
- 正则表达式语法错误
模板签名
为确保模板完整性,可以对模板进行数字签名。
生成密钥对
# 生成私钥
openssl genrsa -out private-key.pem 2048
# 生成公钥
openssl rsa -in private-key.pem -pubout -out public-key.pem
签名模板
nuclei -t template.yaml -sign -private-key private-key.pem
验证签名
nuclei -t template.yaml -verify -public-key public-key.pem
Burp-nuclei 快捷键备忘
快捷键
- 几乎每个动作都可以使用键盘快捷键触发:
- F1:打开核模板文档
- Ctrl + Enter : 执行当前模板
- Ctrl + Shift + E:跳转到模板编辑器
- Ctrl + L:跳转到 CLI 输入字段
- Ctrl + S:保存当前模板
- Ctrl + Plus/Minus:增加/减少字体大小
- Ctrl + Q:退出
- 如果模板保存到新位置,模板路径会自动更新
- 保存时推荐作为
template-id文件名
Nuclei Template
Nuclei Template 基本结构示例:
id: template-id # 唯一标识符,不能包含空格
info:
name: Template Name # 模板名称
author: author-name # 作者
severity: medium # 严重程度:info, low, medium, high, critical
description: Template description # 描述
reference: # 参考链接
- https://example.com
tags: tag1,tag2 # 标签,用于分类
metadata: # 元数据
shodan-query: 'vuln:CVE-2021-26855'
variables: # 模板级变量
var1: "value"
var2: "{{base64('hello')}}"
http: # 协议请求
- method: GET
path:
- "{{BaseURL}}/path"
headers:
User-Agent: Custom-Agent
matchers: # 匹配器
- type: word
words:
- "success"
extractors: # 提取器
- type: regex
regex:
- "token=([a-zA-Z0-9]+)"
内置变量
| 变量 | 描述 | 示例 |
|---|---|---|
{{BaseURL}} | 完整的基础 URL | https://example.com:443/foo/bar.php |
{{RootURL}} | 根 URL | https://example.com:443 |
{{Hostname}} | 主机名和端口 | example.com:443 |
{{Host}} | 主机名 | example.com |
{{Port}} | 端口 | 443 |
{{Path}} | 路径 | /foo |
{{File}} | 文件名 | bar.php |
{{Scheme}} | 协议 | https |
{{FQDN}} | 完全限定域名 | example.com |
特殊参数备忘
使用 stop-at-first-match 选项获得匹配响应也要继续执行。
stop-at-first-match: false
matchers:
- type: dsl
dsl:
- "len(body) > 109"
较新版本的 nuclei 中已经默认启用同一模板中多个会话中传递 cookie,使用 disable-cookie: true 可以禁用这一默认行为:
http:
- method: GET
path:
- "{{BaseURL}}/login"
# disable-cookie: true # 禁用 Cookie 会话管理
重定向控制
http:
- method: GET
path:
- "{{BaseURL}}/redirect"
redirects: true # 启用重定向跟踪
max-redirects: 5 # 最大重定向次数
参数备忘
攻击模式的总结如下:
| 模式 | 描述 |
|---|---|
Batteringram | 使用一个载荷列表,遍历载荷并将相同的载荷注入请求中定义的所有注入点。 |
Pitchfork | 为每个注入点使用一个单独的载荷列表,并并行遍历这些载荷列表。 |
Clusterbomb | 接收多个载荷列表,并将在每个注入点中迭代每个列表的载荷的所有排列组合。 |
多请求
http:
- method: GET
path:
- "{{BaseURL}}/login"
extractors:
- type: regex
name: csrf_token
part: body
internal: true
regex:
- 'name="csrf_token" value="([^"]+)"'
- method: POST
path:
- "{{BaseURL}}/login"
headers:
Content-Type: application/x-www-form-urlencoded
body: |
username=admin&password=admin&csrf_token={{csrf_token}}
matchers:
- type: word
words:
- "Welcome"
条件竞争
要在模板中启用竞态条件检查,请设置选项 race: true 并将 race_count 值设置为要发送的并发请求数量。
Flow 流程控制
Flow 是 Nuclei v3 引入的强大功能,提供条件执行和请求编排能力。
条件执行
id: wordpress-bruteforce
info:
name: WordPress Login Bruteforce
author: pdteam
severity: high
flow: http(1) && http(2) # 先执行第一个请求,成功后执行第二个
http:
- method: GET
path:
- "{{BaseURL}}/wp-login.php"
matchers:
- type: word
words:
- "WordPress"
- method: POST
path:
- "{{BaseURL}}/wp-login.php"
body: |
log={{username}}&pwd={{password}}&wp-submit=Log+In
attack: clusterbomb
payloads:
users: helpers/wordlists/wp-users.txt
passwords: helpers/wordlists/wp-passwords.txt
请求编排
使用 JavaScript (ECMAScript 5.1) 进行复杂的流程控制:
id: vhost-enum-flow
info:
name: vhost enum flow
author: tarunKoyalwar
severity: info
flow: |
ssl();
for (let vhost of iterate(template["ssl_domains"])) {
set("vhost", vhost);
http();
}
ssl:
- address: "{{Host}}:{{Port}}"
http:
- raw:
- |
GET / HTTP/1.1
Host: {{vhost}}
matchers:
- type: dsl
dsl:
- status_code != 400
- status_code != 502
Matchers 匹配器
匹配二进制与十六进制响应
matchers:
- type: binary
binary:
- "504B0304" # zip archive
- "526172211A070100" # RAR archive version 5.0
- "FD377A585A0000" # xz tar.xz archive
condition: or
part: body
匹配二进制与十六进制响应
matchers:
- type: word
encoding: hex
words:
- "50494e47"
part: body
Conditions 条件
单个匹配器中可以指定多个单词和正则表达式,并可以配置不同的条件,如 AND 和 OR。如果没有指定条件,则默认使用 OR。
Negative Matchers 负向匹配器
所有类型的匹配器也支持负向条件,这在你寻找具有排除条件的匹配时非常有用。这可以通过在匹配器块中添加 negative: true 来使用。
这里是一个使用 negative 条件的示例语法,这将返回所有在响应头中不包含 PHPSESSID 的 URL。
matchers:
- type: word
words:
- "PHPSESSID"
part: header
negative: true
Internal Matchers 内部匹配器
在多协议或 Flow 模板中,使用 internal: true 可以跳过中间结果的输出,只显示最终结果。
使用
internal: true跳过中间结果的输出:
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"
matchers:
- type: dsl
dsl:
- 'len(body) == 0'
- 'status_code == 200'
condition: and
在编写多协议或基于 flow 的模板时,可能存在需要先验证/匹配第一个请求,然后才继续下一个请求的情况,一个很好的例子就是 CVE-2023-6553
在这个模板中,我们首先使用 matchers 和 Backup Migration 插件检查目标是否真实,如果为真,则使用 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 # <- updated logic (this will skip printing this event/result)
- 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
Extractors 提取器
- kval - 从 Header/Cookie 中提取
key: value/key=value格式化的数据
一个 kval Extractor 示例,用于从 HTTP 响应中提取 content-type 头部。
请注意,
content-type已被替换为content_type,因为 kval Extractor 不接受连字符 (-) 作为输入,必须用下划线 (_) 替换。
extractors:
- type: kval # type of the extractor
kval:
- content_type # header/cookie value to extract from response
Dynamic Extractor 动态提取器
此功能仅在 RAW 请求格式中可用。
extractors:
- type: regex
name: api
part: body
internal: true # Required for using dynamic variables
regex:
- "(?m)[0-9]{3,10}\\.[0-9]+"
- 如果想将 extractor 用作动态变量,必须使用
internal: true来避免在终端中打印提取的值。
使用 Nuclei v3.1.4,您现在可以立即在后续的提取器中重用动态提取的值(例如:上述示例中的 csrf_token),并且默认在后续请求中可用
id: basic-raw-example
info:
name: Test RAW Template
author: pdteam
severity: info
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
name: title
group: 1
regex:
- '<title>(.*)<\/title>'
internal: true
- type: dsl
dsl:
- '"Title is " + title'
Flow
模板流程引擎在 Nuclei v3 中被引入,为 Nuclei 带来了两个重要改进:
- 条件执行请求的能力
- 请求执行的编排
在编写复杂模板时,我们经常需要在执行请求的某些部分之前添加一些额外的检查(或条件语句)。
flow 接受任何 JavaScript(ECMAScript 5.1)表达式/代码,因此你可以自由地构建任何你想要的条件执行逻辑。
这是一个理想的例子,比如当我们使用默认的用户名和密码暴力破解 WordPress 登录时,但如果我们仔细重新评估这个模板,我们可以看到这个模板在不检查 URL 是否实际存在或目标站点是否真的是 WordPress 站点的情况下发送了 276 个请求。
通过在 Nuclei v3 中添加流程,我们可以重写这个模板,首先检查目标是否是 WordPress 站点,如果是,则使用默认凭据暴力破解登录,这可以通过简单地添加一行内容即可实现,即 flow: http(1) && http(2) ,Nuclei 将处理所有其他事情。
id: wordpress-bruteforce
info:
name: WordPress Login Bruteforce
author: pdteam
severity: high
flow: http(1) && http(2)
http:
- method: GET
path:
- "{{BaseURL}}/wp-login.php"
matchers:
- type: word
words:
- "WordPress"
- method: POST
path:
- "{{BaseURL}}/wp-login.php"
body: |
log={{username}}&pwd={{password}}&wp-submit=Log+In
attack: clusterbomb
payloads:
users: helpers/wordlists/wp-users.txt
passwords: helpers/wordlists/wp-passwords.txt
matchers:
- type: dsl
dsl:
- status_code == 302
- contains_all(header, "/wp-admin","wordpress_logged_in")
condition: and
其他技巧
查找 XPath 表达式的一个快速技巧是使用浏览器开发工具来显示给定元素的节点层次结构。通过在浏览器中打开开发工具并使用检查器获取页面元素的信息,工具窗口应显示选中节点的路径。例如,在 Firefox 中,状态栏区域会显示选中元素的路由信息。
DAST Nuclei 模板
Nuclei 支持基于规则的 HTTP 请求模糊测试,可以创建通用 Web 应用程序漏洞模板(如 SQLi、SSRF、CMDi 等),无需了解目标的具体信息。
DAST 模板可以在主机上执行命令,并且默认扫描不包括这些模板。要使用这些模板,您可以通过提供
-dast标志来运行它们。
Fuzzing 模板基本结构
http:
- pre-condition: # 预条件,决定何时执行模糊测试
- type: dsl
dsl:
- 'method == "GET"'
- 'len(body) > 0'
condition: and
payloads:
reflection:
- "6842'\"><9967"
fuzzing:
- part: query # 模糊测试的部分
type: postfix # 替换类型
mode: single # 模式
fuzz:
- "{{reflection}}"
matchers:
- type: word
part: body
words:
- "{{reflection}}"
模糊测试部分 (Part)
query(默认) - 模糊测试 URL 查询参数path- 模糊测试路径参数header- 模糊测试请求头cookie- 模糊测试 Cookiebody- 模糊测试请求体request- 模糊测试整个请求(所有部分)
替换类型 (Type)
replace(默认) - 用载荷替换值prefix- 在值前添加载荷postfix- 在值后添加载荷infix- 在值中间插入载荷replace-regex- 使用正则表达式替换值
模式 (Mode)
multiple(默认) - 同时替换所有值single- 一次替换一个值
组件数据过滤
fuzzing:
- part: query
type: replace
mode: single
keys: # 精确匹配参数名
- "daemon"
- "cmd"
keys-regex: # 正则匹配参数名
- "redirect.*"
values: # 正则匹配参数值
- "https?://.*"
分析器 (Analyzer)
时间延迟分析器
用于验证时间盲注等漏洞:
analyzer:
name: time_delay
parameters:
sleep_duration: 10
requests_limit: 6
time_correlation_error_range: 0.30
time_slope_error_range: 0.40
fuzzing:
- part: request
type: postfix
mode: single
fuzz:
- " and sleep([SLEEPTIME]) -- "
matchers:
- type: word
part: analyzer
words:
- "true"
动态占位符:
[SLEEPTIME]- 睡眠时间(秒)[INFERENCE]- 推理条件
常见模糊测试模板示例
XSS 检测
id: fuzz-reflection-xss
info:
name: Basic Reflection Potential XSS Detection
author: pdteam
severity: low
http:
- pre-condition:
- type: dsl
dsl:
- 'method == "GET"'
payloads:
reflection:
- "6842'\"><9967"
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"
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}}"
matchers:
- type: word
part: body
words:
- "{{result}}"
盲注 SSRF 检测
http:
- payloads:
redirect:
- "{{interactsh-url}}"
fuzzing:
- part: query
type: replace
mode: single
keys:
- "dest"
- "redirect"
- "url"
fuzz:
- "https://{{redirect}}"
matchers:
- type: word
part: interactsh_protocol
words:
- "http"
在编写/执行模板时,可以使用
-v -svd标志在应用过滤器之前查看过滤器中所有可用的变量。
文件模式
使用命令示例:
nuclei -file -target /path/to/folder/containing/subject/files/ -t google-api-key.yaml
- 文件模式支持
extractors 提取器和matchers 匹配器- 文件模式仅支持
word和regex提取器类型。这些行为方式与其他模式中所述相同。
文件模式模板:
应向模板提供要处理的文件扩展名列表 (extensions)。
all扩展名基本上是一个通配符,匹配除可选拒绝列表中提供的那些扩展名之外的所有扩展名。
id: google-api-key
info:
name: Google API Key
author: pdteam
severity: info
file:
- extensions: # 文件扩展名
- all # 匹配所有扩展名(除默认黑名单外)
- txt # 或指定特定扩展名
- denylist: # 黑名单扩展名
- go
- py
- txt
max-size: 5242880 # 最大文件大小(字节),默认 5MB
no-recursive: false # 是否禁用递归遍历
extractors:
- type: regex
name: google-api-key
regex:
- "AIza[0-9A-Za-z\\-_]{35}"
默认情况下,nuclei 文件模块中会排除某些扩展名。这些扩展名的列表如下
3g2,3gp,7z,apk,arj,avi,axd,bmp,css,csv,deb,dll,doc,drv,eot,exe,flv,gif,gifv,gz,h264,ico,iso,jar,jpeg,jpg,lock,m4a,m4v,map,mkv,mov,mp3,mp4,mpeg,mpg,msi,ogg,ogm,ogv,otf,pdf,pkg,png,ppt,psd,rar,rm,rpm,svg,swf,sys,tar,tar.gz,tif,tiff,ttf,txt,vob,wav,webm,wmv,woff,woff2,xcf,xls,xlsx,zip
更多选项
- max-size 参数用于限制 nuclei 引擎读取的文件的最大大小(以字节为单位)。默认情况下,
max-size的值为 5 MB(5242880),大于max-size的文件将不会被处理。 - no-recursive 选项禁用 nuclei 文件模块在处理输入时对目录 / 通配符进行递归遍历。
Workflows 工作流
条件工作流的核心要点是:
- 运行模板以识别目标
- 根据第一个模板的结果,可能运行其他模板
条件工作流定义的基本组成部分是:
- 模板
- 匹配器(可选,用于定义比之前找到某个内容更详细的条件)
- 子模板(用于定义条件性运行的模板)
以下工作流不使用任何匹配器,只有当模板有任何发现时才会运行子模板:
workflows:
- template: technologies/jira-detect.yaml
subtemplates:
- tags: jira
- template: exploits/jira/
以下工作流程使用匹配器,并在运行各种 WordPress 模板之前,会检查 tech-detect 模板的输出是否包含字符串“wordpress”:
workflows:
- template: technologies/tech-detect.yaml
matchers:
- name: wordpress
subtemplates:
- template: cves/CVE-2019-6715.yaml
- template: cves/CVE-2019-9978.yaml
- template: files/wordpress-db-backup.yaml
- template: files/wordpress-debug-log.yaml
条件工作流可以串联多个条件,以执行复杂的模板序列。一个条件工作流模板的示例是:
workflows:
- template: technologies/tech-detect.yaml
matchers:
- name: foo-xyz
subtemplates:
- template: technologies/foo-xyz-version-3.yaml
subtemplates:
- template: cves/2022/CVE-2022-123456.yaml
subtemplates:
- template: cves/CVE-2022-123457.yaml
这个假设性示例仅在满足以下条件时才会运行 CVE-2022-123457 模板:
该 tech-detect 模板检测 foo-xyz,并且 foo-xyz 的版本是 3.x,同时它检测到 CVE-2022-123456。
因此,总的来说,工作流提供了定义更高效和更有针对性的扫描步骤以保存和共享的能力。
全局匹配器
global-matchers 自 Nuclei v3.3.5 起可用,可以参考文档了解更多关于其用法的信息。
- 仅基于 HTTP 协议:全局匹配器仅与基于 HTTP 协议的模板一起工作。如果你正在处理 DNS、TCP 或其他协议,此功能将不适用。
- 匹配器和提取器:您可以使用全局匹配器进行模式匹配以及从响应中提取数据。
- 显式启用:您必须使用
-enable-global-matchers或-egm标志(如果您使用 Nuclei SDK,可以通过nuclei.EnableGlobalMatchersTemplates以编程方式启用它们)来激活它们。否则,模板将不会运行。
使用命令示例:
必须使用
-enable-global-matchers/-egm参数才能启用全局匹配器
nuclei -enable-global-matchers \
-t http-template-with-global-matchers.yaml \
-t http-template-1.yaml \
-t http-template-2.yaml \
-silent -u http://scanme.sh
全局匹配器模版示例:
该模板设置了
global-matchers: true,这表示告知 Nuclei 在扫描过程中对所有 HTTP 响应应用这些匹配器。而matchers-condition: or意味着只要发现 任意 一个定义的模式匹配,就会标记该响应。
# 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
模板小抄
构造 Jwt
构造 jwt 的 python 伪代码
def generate_jwt_token():
"""Generate JWT token"""
# Get current timestamp
current_time = int(datetime.now().timestamp())
payload = {
"aud": "zplatUsers",
"exp": current_time + 3600, # Expires in 1 hour
"iat": current_time, # Issued at current time
"iss": "zplat",
"nbf": current_time, # Not before current time
"sub": "1",
"roles": [
"admin"
]
}
secret = "123"
token = jwt.encode(payload, secret, algorithm='HS512')
return token
伪代码对照的 nuclei 模板变量示例
variables:
json: |
{
"aud": "zplatUsers",
"iss": "zplat",
"sub": "1",
"roles": ["admin"]
}
secret: "123"
algorithm: "HS512"
# 总是设置为当前时间后24小时
maxAge: '{{unix_time() + 3600}}' # 3600秒 = 1小时
jwt: '{{generate_jwt(json, algorithm, secret, maxAge)}}'
关键点:
json参数必须是 JSON 字符串格式- 不需要手动设置
exp和iat-maxAge参数会自动处理 - 算法使用
HS512 - 密钥直接作为字符串传递
dsl 匹配器提取 json 字段
extractors:
- type: json
json:
- '.data | {bucket: .bucket, endpoint: .endpoint, access_key: .access_key, secret_key: .secret_key}'
name: storage_config
使用 flow 来控制多数据包执行流程
# 使用Flow来控制执行流程
flow: |
http(1);
for (let storage_id of iterate(template["storage_ids"])) {
set("storage_id", storage_id);
http(2);
}
http 爆破
http:
- raw:
- |-
POST /{{Path}} HTTP/1.1
Host: {{Hostname}}
Content-Type: application/json
{"username":{{username}},"password":{{password}}}
attack: clusterbomb # 可用类型: batteringram,pitchfork,clusterbomb
payloads:
username:
- 'admin'
password:
- 'admin'
Path:
- 'api/selectContentManagePage'
# header: helpers/wordlists/header.txt
dsl 匹配器
印象中,匹配 http header 时,需要将
-替换成_
matchers:
- type: dsl
dsl:
- "status_code == 200"
- "contains_all(body_1, 'pageSize', 'pageNum')"
- "contains(content_type, 'application/json')"
condition: and
从开源模板中学到的邪教写法,在 dsl 匹配器中内嵌正则
matchers:
- type: dsl
dsl:
- "contains(interactsh_protocol, 'http')"
- "contains(content_type, 'text/plain')"
- "regex('^{{string}}$', body)"
- "status_code == 200"
condition: and
windows 任意文件读取
matchers:
- type: dsl
dsl:
- "status_code == 200"
- "contains_all(body, 'bit app support', 'fonts', 'extensions')"
- "len(body_1) <= 1024"
condition: and
linux 任意文件读取
matchers-condition: and
matchers:
- type: regex
regex:
- "root:[x*]:0:0:"
part: body
-
- type: dsl
dsl:
- "status_code == 200"
- "len(body_1) <= 1024"
condition: and
二进制流匹配
matchers:
- type: binary
binary:
- "504B0304" # zip archive
- "526172211A070100" # RAR archive version 5.0
- "FD377A585A0000" # xz tar.xz archive
condition: or
part: body
正则匹配邮箱
extractors:
- type: regex
part: body
regex:
- "[a-zA-Z0-9-_.]{4,}@[A-Za-z0-9_-]+[.](com|org|net|io|gov|co|co.uk|com.mx|com.br|com.sv|co.cr|com.gt|com.hn|com.ni|com.au|com.cn|cn|gov.cn)"
URL 重定向
matchers:
- type: regex
part: header
regex:
- "(?m)^(?:Location\\s*:\\s*)(?:https?://|//|\\\\)?(?:[a-zA-Z0-9\\-_]*\\.)?interact\\.sh(?:\\s*)$"