Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into cloud-templates-targets-sync

This commit is contained in:
Ice3man 2022-12-08 20:31:23 +05:30
commit a3e3c1cf3d
86 changed files with 2187 additions and 1283 deletions

View File

@ -22,7 +22,7 @@ updates:
- package-ecosystem: "gomod"
directory: "v2/"
schedule:
interval: "daily"
interval: "weekly"
target-branch: "dev"
commit-message:
prefix: "chore"

View File

@ -1,25 +1,36 @@
name: 🔨 Build Test
on:
push:
pull_request:
paths:
- '**.go'
- 'v2/'
workflow_dispatch:
jobs:
build:
name: Test Builds
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
go-version: [1.18.x, 1.19.x]
os: [ubuntu-latest, windows-latest, macOS-12]
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
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/
- name: Build
run: go build .
working-directory: v2/cmd/nuclei/
@ -41,5 +52,5 @@ jobs:
- name: Race Condition Tests
if: ${{ matrix.os != 'windows-latest' }} # known issue: https://github.com/golang/go/issues/46099
run: go run -race . -u scanme.sh
run: go run -race . -l ../functional-test/targets.txt -id tech-detect,tls-version
working-directory: v2/cmd/nuclei/

View File

@ -1,11 +1,8 @@
name: 🚨 CodeQL Analysis
on:
push:
pull_request:
workflow_dispatch:
branches:
- dev
jobs:
analyze:

View File

@ -17,7 +17,7 @@ jobs:
- name: Get Github tag
id: meta
run: |
echo "::set-output name=tag::$(curl --silent "https://api.github.com/repos/projectdiscovery/nuclei/releases/latest" | jq -r .tag_name)"
curl --silent "https://api.github.com/repos/projectdiscovery/nuclei/releases/latest" | jq -r .tag_name | xargs -I {} echo TAG={} >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
@ -37,4 +37,4 @@ jobs:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: projectdiscovery/nuclei:latest,projectdiscovery/nuclei:${{ steps.meta.outputs.tag }}
tags: projectdiscovery/nuclei:latest,projectdiscovery/nuclei:${{ steps.meta.outputs.TAG }}

View File

@ -1,7 +1,9 @@
name: 🧪 Functional Test
on:
push:
pull_request:
paths:
- '**.go'
workflow_dispatch:

View File

@ -1,7 +1,6 @@
name: 🙏🏻 Lint Test
on:
push:
pull_request:
workflow_dispatch:
@ -17,7 +16,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v3
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3.3.0
uses: golangci/golangci-lint-action@v3.3.1
with:
version: latest
args: --timeout 5m

View File

@ -1,9 +1,9 @@
name: ⏰ Publish Docs
on:
push:
branches:
- dev
pull_request:
paths:
- '**.go'
workflow_dispatch:
jobs:
@ -13,7 +13,7 @@ jobs:
- name: Check out code
uses: actions/checkout@v3
with:
persist-credentials: false
ref: ${{ github.head_ref }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
@ -32,11 +32,11 @@ jobs:
go generate pkg/templates/templates.go
go build -o "cmd/docgen/docgen" cmd/docgen/docgen.go
./cmd/docgen/docgen ../SYNTAX-REFERENCE.md ../nuclei-jsonschema.json
echo "::set-output name=changes::$(git status -s | wc -l)"
git status -s | wc -l | xargs -I {} echo CHANGES={} >> $GITHUB_OUTPUT
working-directory: v2
- name: Commit files
if: steps.generate-docs.outputs.changes > 0
if: steps.generate-docs.outputs.CHANGES > 0
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
@ -44,7 +44,7 @@ jobs:
git commit -m "Auto Generate Syntax Docs + JSONSchema [$(date)] :robot:" -a
- name: Push changes
if: steps.generate-docs.outputs.changes > 0
if: steps.generate-docs.outputs.CHANGES > 0
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,4 +1,5 @@
name: 🎉 Release Binary
on:
push:
tags:

View File

@ -1,11 +1,9 @@
name: 👮🏼‍♂️ Sonarcloud
on:
push:
branches:
- master
- dev
pull_request:
types: [opened, synchronize, reopened]
paths:
- '**.go'
workflow_dispatch:
jobs:

View File

@ -1,6 +1,10 @@
name: 🛠 Template Validate
on: [ push, pull_request ]
on:
pull_request:
paths:
- '**.go'
workflow_dispatch:
jobs:
build:
@ -11,18 +15,9 @@ jobs:
with:
go-version: 1.18
- name: Cache Go
id: cache-go
uses: actions/cache@v3
with:
path: /home/runner/go
key: ${{ runner.os }}-go
- name: Installing Nuclei
# if: steps.cache-go.outputs.cache-hit != 'true'
run: |
go install github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
- name: Template Validation
run: |
nuclei -validate
nuclei -validate -w ./workflows
go run . -ut
go run . -validate
go run . -validate -w workflows
working-directory: v2/cmd/nuclei/

View File

@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="DSLFunctionsIT" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="nuclei" />
<working_directory value="$PROJECT_DIR$/integration_tests" />
<envs>
<env name="DEBUG" value="true" />
<env name="TESTS" value="http/dsl-functions.yaml" />
</envs>
<kind value="PACKAGE" />
<package value="github.com/projectdiscovery/nuclei/v2/cmd/integration-test" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/v2/cmd/integration-test/integration-test.go" />
<method v="2" />
</configuration>
</component>

102
DESIGN.md
View File

@ -261,108 +261,6 @@ engine.SetExecuterOptions(executerOpts)
results := engine.ExecuteWithOpts(finalTemplates, r.hmapInputProvider, true)
```
### Using Nuclei From Go Code
An example of using Nuclei From Go Code to run templates on targets is provided below.
```go
package main
import (
"context"
"fmt"
"log"
"os"
"path"
"time"
"github.com/logrusorgru/aurora"
"github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v2/pkg/core"
"github.com/projectdiscovery/nuclei/v2/pkg/core/inputs"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/ratelimit"
)
func main() {
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount)
defer cache.Close()
mockProgress := &testutils.MockProgressClient{}
reportingClient, _ := reporting.New(&reporting.Options{}, "")
defer reportingClient.Close()
outputWriter := testutils.NewMockOutputWriter()
outputWriter.WriteCallback = func(event *output.ResultEvent) {
fmt.Printf("Got Result: %v\n", event)
}
defaultOpts := types.DefaultOptions()
protocolstate.Init(defaultOpts)
protocolinit.Init(defaultOpts)
defaultOpts.Templates = goflags.StringSlice{"dns/cname-service.yaml"}
defaultOpts.ExcludeTags = config.ReadIgnoreFile().Tags
interactOpts := interactsh.NewDefaultOptions(outputWriter, reportingClient, mockProgress)
interactClient, err := interactsh.New(interactOpts)
if err != nil {
log.Fatalf("Could not create interact client: %s\n", err)
}
defer interactClient.Close()
home, _ := os.UserHomeDir()
catalog := disk.NewCatalog(path.Join(home, "nuclei-templates"))
executerOpts := protocols.ExecuterOptions{
Output: outputWriter,
Options: defaultOpts,
Progress: mockProgress,
Catalog: catalog,
IssuesClient: reportingClient,
RateLimiter: ratelimit.New(context.Background(), 150, time.Second),
Interactsh: interactClient,
HostErrorsCache: cache,
Colorizer: aurora.NewAurora(true),
ResumeCfg: types.NewResumeCfg(),
}
engine := core.New(defaultOpts)
engine.SetExecuterOptions(executerOpts)
workflowLoader, err := parsers.NewLoader(&executerOpts)
if err != nil {
log.Fatalf("Could not create workflow loader: %s\n", err)
}
executerOpts.WorkflowLoader = workflowLoader
configObject, err := config.ReadConfiguration()
if err != nil {
log.Fatalf("Could not read config: %s\n", err)
}
store, err := loader.New(loader.NewConfig(defaultOpts, configObject, catalog, executerOpts))
if err != nil {
log.Fatalf("Could not create loader client: %s\n", err)
}
store.Load()
input := &inputs.SimpleInputProvider{Inputs: []string{"docs.hackerone.com"}}
_ = engine.Execute(store.Templates(), input)
engine.WorkPool().Wait() // Wait for the scan to finish
}
```
### Adding a New Protocol
Protocols form the core of Nuclei Engine. All the request types like `http`, `dns`, etc. are implemented in form of protocol requests.

View File

@ -2,7 +2,7 @@ FROM golang:1.19.3-alpine as build-env
RUN apk add build-base
RUN go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
FROM alpine:3.16.2
FROM alpine:3.17.0
RUN apk add --no-cache bind-tools ca-certificates chromium
COPY --from=build-env /go/bin/nuclei /usr/local/bin/nuclei
ENTRYPOINT ["nuclei"]

151
README.md
View File

@ -31,7 +31,8 @@
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README.md">English</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_CN.md">中文</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_KR.md">Korean</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_KR.md">Korean</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_ID.md">Indonesia</a>
</p>
---
@ -90,13 +91,15 @@ Nuclei is a fast, template based vulnerability scanner focusing
on extensive configurability, massive extensibility and ease of use.
Usage:
nuclei [flags]
./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)
-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 IPs 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
@ -107,7 +110,8 @@ TEMPLATES:
-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
-nss, -no-strict-syntax disable strict syntax check on templates
-td, -template-display displays the templates content
-tl list all available templates
FILTERING:
@ -122,8 +126,8 @@ FILTERING:
-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
-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:
@ -135,7 +139,7 @@ OUTPUT:
-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
-nts, -no-timestamp disable printing timestamp in cli output
-ts, -timestamp enable 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
@ -153,6 +157,7 @@ CONFIGURATIONS:
-r, -resolvers string file containing resolver list for nuclei
-sr, -system-resolvers use system DNS resolving as error fallback
-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
@ -160,12 +165,13 @@ CONFIGURATIONS:
-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)
-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)
-rss, -response-size-save int max response size to save in bytes (default 10485760)
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)
@ -176,6 +182,14 @@ INTERACTSH:
-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) (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
@ -187,20 +201,21 @@ RATE-LIMIT:
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
-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)
-project use a project folder to avoid sending same request multiple times
-project-path string set a specific project path
-spm, -stop-at-first-path stop processing HTTP requests after the first match (may break template/workflow logic)
-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
-irt, -input-read-timeout duration timeout on input read (default 3m0s)
-no-stdin Disable Stdin processing
-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)
-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
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
-lha, -list-headless-action list available headless actions
DEBUG:
@ -217,6 +232,7 @@ DEBUG:
-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
@ -332,6 +348,109 @@ We have [a discussion thread around this](https://github.com/projectdiscovery/nu
<a href="https://github.com/projectdiscovery/nuclei-action"><img src="static/learn-more-button.png" width="170px" alt="Learn More"></a>
</h1>
### Using Nuclei From Go Code
An example of using Nuclei From Go Code to run templates on targets is provided below.
```go
package main
import (
"context"
"fmt"
"log"
"os"
"path"
"time"
"github.com/logrusorgru/aurora"
"github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v2/pkg/core"
"github.com/projectdiscovery/nuclei/v2/pkg/core/inputs"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/ratelimit"
)
func main() {
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount)
defer cache.Close()
mockProgress := &testutils.MockProgressClient{}
reportingClient, _ := reporting.New(&reporting.Options{}, "")
defer reportingClient.Close()
outputWriter := testutils.NewMockOutputWriter()
outputWriter.WriteCallback = func(event *output.ResultEvent) {
fmt.Printf("Got Result: %v\n", event)
}
defaultOpts := types.DefaultOptions()
protocolstate.Init(defaultOpts)
protocolinit.Init(defaultOpts)
defaultOpts.Templates = goflags.StringSlice{"dns/cname-service.yaml"}
defaultOpts.ExcludeTags = config.ReadIgnoreFile().Tags
interactOpts := interactsh.NewDefaultOptions(outputWriter, reportingClient, mockProgress)
interactClient, err := interactsh.New(interactOpts)
if err != nil {
log.Fatalf("Could not create interact client: %s\n", err)
}
defer interactClient.Close()
home, _ := os.UserHomeDir()
catalog := disk.NewCatalog(path.Join(home, "nuclei-templates"))
executerOpts := protocols.ExecuterOptions{
Output: outputWriter,
Options: defaultOpts,
Progress: mockProgress,
Catalog: catalog,
IssuesClient: reportingClient,
RateLimiter: ratelimit.New(context.Background(), 150, time.Second),
Interactsh: interactClient,
HostErrorsCache: cache,
Colorizer: aurora.NewAurora(true),
ResumeCfg: types.NewResumeCfg(),
}
engine := core.New(defaultOpts)
engine.SetExecuterOptions(executerOpts)
workflowLoader, err := parsers.NewLoader(&executerOpts)
if err != nil {
log.Fatalf("Could not create workflow loader: %s\n", err)
}
executerOpts.WorkflowLoader = workflowLoader
configObject, err := config.ReadConfiguration()
if err != nil {
log.Fatalf("Could not read config: %s\n", err)
}
store, err := loader.New(loader.NewConfig(defaultOpts, configObject, catalog, executerOpts))
if err != nil {
log.Fatalf("Could not create loader client: %s\n", err)
}
store.Load()
input := &inputs.SimpleInputProvider{Inputs: []string{"docs.hackerone.com"}}
_ = engine.Execute(store.Templates(), input)
engine.WorkPool().Wait() // Wait for the scan to finish
}
```
### Resources
- [Finding bugs with Nuclei with PinkDraconian (Robbe Van Roey)](https://www.youtube.com/watch?v=ewP0xVPW-Pk) by **[@PinkDraconian](https://twitter.com/PinkDraconian)**

View File

@ -7,12 +7,14 @@
<p align="center">
<a href="https://goreportcard.com/report/github.com/projectdiscovery/nuclei"><img src="https://goreportcard.com/badge/github.com/projectdiscovery/nuclei"></a>
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"></a>
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei"></a>
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei?filename=v2%2Fgo.mod">
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/downloads/projectdiscovery/nuclei/total">
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors"><img src="https://img.shields.io/github/contributors-anon/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/releases/"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/github/issues-raw/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/discussions"><img src="https://img.shields.io/github/discussions/projectdiscovery/nuclei">
<a href="https://discord.gg/projectdiscovery"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
<a href="https://github.com/projectdiscovery/nuclei/actions/workflows/build-test.yml"><img src="https://github.com/projectdiscovery/nuclei/actions/workflows/build-test.yml/badge.svg?branch=master"></a>
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
</p>
<p align="center">
@ -28,14 +30,15 @@
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README.md">English</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_CN.md">中文</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_CN.md">中文</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_KR.md">Korean</a>
</p>
---
Nuclei使用零误报的定制模板向目标发送请求同时可以对大量主机进行快速扫描。Nuclei提供TCP、DNS、HTTP、FILE等各类协议的扫描通过强大且灵活的模板可以使用Nuclei模拟各种安全检查。
Nuclei使用零误报的定制模板向目标发送请求同时可以对主机进行批量快速扫描。Nuclei提供TCP、DNS、HTTP、FILE等各类协议的扫描通过强大且灵活的模板可以使用Nuclei模拟各种安全检查。
我们的[模板仓库](https://github.com/projectdiscovery/nuclei-templates)包含**超过200**安全研究员和工程师提供的模板。
我们的[模板仓库](https://github.com/projectdiscovery/nuclei-templates)包含**超过300**安全研究员和工程师提供的模板。
@ -65,7 +68,7 @@ go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
自从[v2.5.2]((https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2))起Nuclei就内置了自动下载和更新模板的功能。[**Nuclei模板**](https://github.com/projectdiscovery/nuclei-templates)仓库随时更新社区中可用的模板列表。
您仍然可以随时使用`update-templates`命令更新模板,您可以根据[模板指南](https://nuclei.projectdiscovery.io/templating-guide/)编写您自己的模板。
您仍然可以随时使用`update-templates`命令更新模板,您可以根据[模板指南](https://nuclei.projectdiscovery.io/templating-guide/)为您的个人工作流和需求编写模板。
YAML的语法规范在[这里](SYNTAX-REFERENCE.md)。
@ -79,10 +82,10 @@ YAML的语法规范在[这里](SYNTAX-REFERENCE.md)。
nuclei -h
```
这将显示Nuclei的帮助以下是所有支持的命令
这将显示Nuclei的帮助以下是所有支持的命令
```yaml
```console
Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板的快速漏洞扫描器。
用法:
@ -90,104 +93,146 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
命令:
目标:
-u, -target string[] 指定扫描的URL/主机
-l, -list string 指定需要扫描的URL/主机文件(一行一个)
-u, -target string[] 指定扫描的URL/主机
-l, -list string 指定需要扫描的URL/主机文件(一行一个)
-resume string 断点续扫(将禁用集群)
模板:
-t, -templates string[] 指定需要扫描的模板或者模板的路径
-nt, -new-templates 只扫描最新版本中添加的模板
-ntv -new-templates-version 运行在特定版本中添加的新模板
-w, -workflows string[] 指定扫描中的工作流或者工作流目录
-validate 验证通过的模板
-tl 列出所有可用的模板
-nt, -new-templates 只扫描最新版本中添加的模板
-ntv, -new-templates-version string[] 运行在特定版本中添加的新模板
-as, -automatic-scan 在自动web扫描中使用wappalyzer技术检测的指纹
-t, -templates string[] 指定需要扫描的模板或者模板的路径(逗号分隔,文件)
-tu, -template-url string[] 从URL加载模板逗号分隔文件
-w, -workflows string[] 指定扫描中的工作流或者工作流目录(逗号分隔,文件)
-wu, -workflow-url string[] 从URL加载工作流逗号分隔文件
-validate 验证通过的模板
-nss, -no-strict-syntax 禁用模板的严格检查
-tl 列出所有可用的模板
过滤:
-tags string[] 执行有标记的模板子集
-etags, -exclude-tags string[] 执行标记为排除的模板
-itags, -include-tags string[] 不执行具有攻击性的模板
-et, -exclude-templates string[] 要排除的模板或者模板目录
-it, -include-templates string[] 执行默认或配置中排除的模板
-s, -severity value[] 根据严重程度运行模板可候选的值有info,low,medium,high,critical
-es, -exclude-severity value[] 根据严重程度排除模板可候选的值有info,low,medium,high,critical
-a, -author string[] 执行指定作者的模板
-a, -author string[] 执行指定作者的模板(逗号分隔,文件)
-tags string[] 执行有标记的模板子集(逗号分隔,文件)
-etags, -exclude-tags string[] 执行标记为排除的模板(逗号分隔,文件)
-itags, -include-tags string[] 执行默认或者配置排除的标记模板
-id, -template-id string[] 执行指定ID的模板逗号分隔文件
-eid, -exclude-id string[] 执行排除指定ID的模板逗号分隔文件
-it, -include-templates string[] 执行默认或配置中排除的模板
-et, -exclude-templates string[] 要排除的模板或者模板目录(逗号分隔,文件)
-em, -exclude-matchers string[] 在结果中排除指定模板
-s, -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
-ept, -exclude-type value[] 根据协议排除模板可候选的值有dns, file, http, headless, network, workflow, ssl, websocket, whois
-tc, -template-condition string[] 根据表达式运行模板
输出:
-o, -output string 输出发现的问题到文件
-silent 只显示结果
-nc, -no-color 禁用输出内容着色ANSI转义码
-json 输出为jsonLines
-irr, -include-rr 在JSONL中输出对应的请求和相应仅结果
-nm, -no-meta 不显示匹配的元数据
-nts, -no-timestamp 不在输出中显示时间戳
-rdb, -report-db string 本地的Nuclei结果数据库始终使用该数据库保存结果
-me, -markdown-export string 以markdown导出结果
-se, -sarif-export string 以SARIF导出结果
-o, -output string 输出发现的问题到文件
-sresp, -store-resp 将nuclei的所有请求和响应输出到目录
-srd, -store-resp-dir string 将nuclei的所有请求和响应输出到指定目录默认output
-silent 只显示结果
-nc, -no-color 禁用输出内容着色ANSI转义码
-json 输出为jsonLines
-irr, -include-rr 在JSONL中输出对应的请求和相应仅结果
-nm, -no-meta 不显示匹配的元数据
-nts, -no-timestamp 不在输出中显示时间戳
-rdb, -report-db string 本地的Nuclei结果数据库始终使用该数据库保存结果
-ms, -matcher-status 显示匹配失败状态
-me, -markdown-export string 以markdown导出结果
-se, -sarif-export string 以SARIF导出结果
配置:
-config string 指定Nuclei的配置文件
-rc, -report-config string 指定Nuclei报告模板文件
-H, -header string[] 指定报告中的标题value格式
-V, -var value 通过var=value指定var值
-r, -resolvers string 指定Nuclei的解析文件
-sr, -system-resolvers 当DNS错误时使用系统DNS
-passive 启用被动扫描处理HTTP响应
-ev, env-vars 在模板中使用环境变量
-config string 指定Nuclei的配置文件
-fr, -follow-redirects 为HTTP模板启用重定向
-fhr, -follow-host-redirects 在同一主机上重定向
-mr, -max-redirects int HTTP模板最大重定向次数默认10
-dr, -disable-redirects 为HTTP模板禁用重定向
-rc, -report-config string 指定Nuclei报告模板文件
-H, -header string[] 指定header、cookie以header:value的方式cli文件
-V, -var value 通过key=value指定var值
-r, -resolvers string 指定Nuclei的解析文件
-sr, -system-resolvers 当DNS错误时使用系统DNS
-passive 启用被动扫描处理HTTP响应
-ev, env-vars 在模板中使用环境变量
-cc, -client-cert string 用于对扫描的主机进行身份验证的客户端证书文件PEM 编码)
-ck, -client-key string 用于对扫描的主机进行身份验证的客户端密钥文件PEM 编码)
-ca, -client-ca string 用于对扫描的主机进行身份验证的客户端证书颁发机构文件PEM 编码)
-sml, -show-match-line 显示文件模板的匹配值,只适用于提取器
-ztls 对ztls自动退回到tls13
-sni string 指定tls sni的主机名默认为输入的域名
-i, -interface string 指定网卡
-sip, -source-ip string 指定源IP
-config-directory string 重写默认配置路径($home/.config
-rsr, -response-size-read int 最大读取响应大小默认10485760字节
-rss, -response-size-save int 最大储存响应大小默认10485760字节
交互:
-inserver, -ineractsh-server string 使用interactsh反连检测平台默认为"https://interact.sh"
-itoken, -interactsh-token string 指定反连检测平台的身份凭证
-interactions-cache-size int 指定保存在交互缓存中的请求数默认5000
-interactions-eviction int 从缓存中删除请求前等待的时间默认为60秒
-interactions-poll-duration int 每个轮询前等待时间默认为5秒
-interactions-cooldown-period int 退出轮询前的等待时间默认为5秒
-ni, -no-interactsh 禁用反连检测平台,同时排除基于反连检测的模板
-inserver, -ineractsh-server string 使用interactsh反连检测平台默认为oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me
-itoken, -interactsh-token string 指定反连检测平台的身份凭证
-interactions-cache-size int 指定保存在交互缓存中的请求数默认5000
-interactions-eviction int 从缓存中删除请求前等待的时间默认为60秒
-interactions-poll-duration int 每个轮询前等待时间默认为5秒
-interactions-cooldown-period int 退出轮询前的等待时间默认为5秒
-ni, -no-interactsh 禁用反连检测平台,同时排除基于反连检测的模板
限速:
-rl, -rate-limit int 每秒最大请求量默认150
-rlm, -rate-limit-minute int 每分钟最大请求量
-bs, -bulk-size int 每个模板最大并行检测数默认25
-c, -concurrency int 并行执行的最大模板数量默认25
-rl, -rate-limit int 每秒最大请求量默认150
-rlm, -rate-limit-minute int 每分钟最大请求量
-bs, -bulk-size int 每个模板最大并行检测数默认25
-c, -concurrency int 并行执行的最大模板数量默认25
-hbs, -headless-bulk-size int 每个模板并行运行的无头主机最大数量默认10
-headc, -headless-concurrency int 并行指定无头主机最大数量默认10
优化:
-timeout int 超时时间默认为5秒
-retries int 重试次数默认1
-mhe, -max-host-error int 某主机扫描失败次数跳过该主机默认30
-project 使用项目文件夹避免多次发送同一请求
-project-path string 设置特定的项目文件夹
-spm, -stop-at-first-path 得到一个结果后停止(或许会中断模板和工作流的逻辑)
-stream 流模式 - 在不整理输入的情况下详细描述
-timeout int 超时时间默认为10秒
-retries int 重试次数默认1
-ldp, -leave-default-ports 指定HTTP/HTTPS默认端口例如host:80host:443
-mhe, -max-host-error int 某主机扫描失败次数跳过该主机默认30
-project 使用项目文件夹避免多次发送同一请求
-project-path string 设置特定的项目文件夹
-spm, -stop-at-first-path 得到一个结果后停止(或许会中断模板和工作流的逻辑)
-stream 流模式 - 在不整理输入的情况下详细描述
-irt, -input-read-timeout duration 输入读取超时时间默认3分钟
-no-stdin 禁用标准输入
无界面浏览器:
-headless 启用需要无界面浏览器的模板
-page-timeout int 在无界面下超时秒数默认20
-sb, -show-brower 在无界面浏览器运行模板时,显示浏览器
-sc, -system-chrome 不使用Nuclei自带的浏览器使用本地浏览器
-headless 启用需要无界面浏览器的模板
-page-timeout int 在无界面下超时秒数默认20
-sb, -show-brower 在无界面浏览器运行模板时,显示浏览器
-sc, -system-chrome 不使用Nuclei自带的浏览器使用本地浏览器
-lha, -list-headless-action 列出可用的无界面操作
调试:
-debug 显示所有请求和响应
-debug-req 显示所有请求
-debug-resp 显示所有响应
-proxy, -proxy-url string 使用HTTP代理
-proxy-socks-url string 使用SOCK5代理
-tlog, -trace-log string 写入请求日志到文件
-version 显示版本信息
-v, -verbose 显示详细信息
-vv 显示额外的详细信息
-tv, -templates-version 显示已安装的模板版本
-debug 显示所有请求和响应
-dreq, -debug-req 显示所有请求
-dresp, -debug-resp 显示所有响应
-p, -proxy string[] 使用http/socks5代理逗号分隔文件
-pi, -proxy-internal 代理所有请求
-ldf, -list-dsl-function 列出所有支持的DSL函数签名
-tlog, -trace-log string 写入跟踪日志到文件
-elog, -error-log string 写入错误日志到文件
-version 显示版本信息
-hm, -hang-monitor 启用Nuclei的监控
-v, -verbose 显示详细信息
-profile-mem string 将Nuclei的内存转储成文件
-vv 显示额外的详细信息
-ep, -enable-pprof 启用pprof调试服务器
-tv, -templates-version 显示已安装的模板版本
-hc, -health-check 运行诊断检查
升级:
-update 更新Nuclei到最新版本
-ut, -update-templates 更新Nuclei模板到最新版
-ud, -update-directory string 覆盖安装模板
-duc, -disable-update-check 禁用更新
-update 更新Nuclei到最新版本
-ut, -update-templates 更新Nuclei模板到最新版
-ud, -update-directory string 覆盖安装模板
-duc, -disable-update-check 禁用更新
统计:
-stats 显示正在扫描的统计信息
-sj, -stats-json 将统计信息以JSONL格式输出到文件
-si, -stats-inerval int 显示统计信息更新的间隔秒数默认5
-m, -metrics 显示Nuclei端口信息
-mp, -metrics-port int 更改Nuclei默认端口默认9092
-stats 显示正在扫描的统计信息
-sj, -stats-json 将统计信息以JSONL格式输出到文件
-si, -stats-inerval int 显示统计信息更新的间隔秒数默认5
-m, -metrics 显示Nuclei端口信息
-mp, -metrics-port int 更改Nuclei默认端口默认9092
```
### 运行Nuclei
@ -233,7 +278,7 @@ Nuclei提供了大量有助于安全工程师在工作流定制相关的功能
**对于赏金猎人:**
Nuclei允许您定制自己的测试方法可以轻松的运行您的程序。此外Nuclei可以更容易的集成到您的漏扫设备中。
Nuclei允许您定制自己的测试方法可以轻松的运行您的程序。此外Nuclei可以更容易的集成到您的漏洞扫描工作流中。
- 可以集成到其他工作流中
- 可以在几分钟处理上千台主机
@ -267,7 +312,7 @@ Nuclei通过增加手动、自动的过程极大地改变了安全评估的
Nuclei构建很简单通过数百名安全研究员的社区模板Nuclei可以随时扫描来了解安全威胁。Nuclei通常用来用于复测以确定漏洞是否被修复。
- **CI/CD**工程师已经支持了CI/CD可以使用Nuclei来监控生产环境
- **CI/CD**工程师已经支持了CI/CD可以通过Nuclei使用定制模板来监控模拟环境和生产环境
- **周期性扫描:**使用Nuclei创建新发现的漏洞模板通过Nuclei可以周期性扫描消除漏洞
我们有个[讨论组](https://github.com/projectdiscovery/nuclei-templates/discussions/693),黑客提交自己的模板后可以获得赏金,这可以减少资产的漏洞,并且减少重复。如果你想实行该计划,可以[联系我](mailto:contact@projectdiscovery.io)。我们非常乐意提供帮助,或者在[讨论组](https://github.com/projectdiscovery/nuclei-templates/discussions/693)中发布相关信息。
@ -281,6 +326,11 @@ Nuclei构建很简单通过数百名安全研究员的社区模板Nuclei
</h1>
### 资源
- [使用PinkDraconian发现Nuclei的BUG (Robbe Van Roey)](https://www.youtube.com/watch?v=ewP0xVPW-Pk) 作者:[@PinkDraconian](https://twitter.com/PinkDraconian)
- [Nuclei: 强而有力的扫描器](https://bishopfox.com/blog/nuclei-vulnerability-scan) 作者Bishopfox
- [WAF有效性检查](https://www.fastly.com/blog/the-waf-efficacy-framework-measuring-the-effectiveness-of-your-waf) 作者Fastly
- [在CI/CD中使用Nuclei实时扫描网页应用](https://blog.escape.tech/devsecops-part-iii-scanning-live-web-applications/) 作者:[@TristanKalos](https://twitter.com/TristanKalos)
- [使用Nuclei扫描](https://blog.projectdiscovery.io/community-powered-scanning-with-nuclei/)
- [Nuclei Unleashed - 快速编写复杂漏洞](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/)
- [Nuclei - FUZZ一切](https://blog.projectdiscovery.io/nuclei-fuzz-all-the-things/)

354
README_ID.md Normal file
View File

@ -0,0 +1,354 @@
<h1 align="center">
<br>
<a href="https://nuclei.projectdiscovery.io"><img src="static/nuclei-logo.png" width="200px" alt="Nuclei"></a>
</h1>
<h4 align="center">Pemindai kerentanan yang cepat dan dapat disesuaikan berdasarkan DSL berbasis YAML sederhana.</h4>
<p align="center">
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei?filename=v2%2Fgo.mod">
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/downloads/projectdiscovery/nuclei/total">
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors"><img src="https://img.shields.io/github/contributors-anon/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/releases/"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/github/issues-raw/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/discussions"><img src="https://img.shields.io/github/discussions/projectdiscovery/nuclei">
<a href="https://discord.gg/projectdiscovery"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
</p>
<p align="center">
<a href="#cara-kerja">Cara Kerja</a>
<a href="#instalasi-nuclei">Instalasi</a>
<a href="#untuk-insinyur-keamanan">Untuk Teknisi Keamanan</a>
<a href="#untuk-pengembang-dan-organisasi">Untuk Pengembang</a>
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/">Dokumentasi</a>
<a href="#kredit">Kredit</a>
<a href="https://nuclei.projectdiscovery.io/faq/nuclei/">Tanya Jawab</a>
<a href="https://discord.gg/projectdiscovery">Gabung Discord</a>
</p>
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README.md">English</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_CN.md">中文</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_KR.md">Korean</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_ID.md">Indonesia</a>
</p>
---
Nuclei digunakan untuk mengirim permintaan lintas target berdasarkan templat, yang menghasilkan nol positif palsu dan menyediakan pemindaian yang cepat pada banyak host. Nuclei menawarkan pemindaian untuk berbagai protokol, termasuk TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless, dll. Dengan templating yang kuat dan fleksibel, Nuclei dapat digunakan untuk memodelkan semua jenis pemeriksaan keamanan.
Kami memiliki [repositori khusus](https://github.com/projectdiscovery/nuclei-templates) yang menampung berbagai jenis templat kerentanan yang disumbangkan oleh **lebih dari 300** peneliti dan teknisi keamanan.
## Cara Kerja
<h3 align="center">
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
</h3>
# Instalasi Nuclei
Nuclei membutuhkan **go1.18** agar dapat diinstall. Jalankan perintah berikut untuk menginstal versi terbaru -
```sh
go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
```
**Metode [instalasi lain dapat ditemukan di sini](https://nuclei.projectdiscovery.io/nuclei/get-started/).**
<table>
<tr>
<td>
### Nuclei Templates
Nuclei memiliki dukungan untuk unduhan/pembaruan templat otomatis sebagai bawaan sejak versi [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2). Proyek [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) menyediakan daftar template siap pakai yang dibuat oleh komunitas yang terus diperbarui.
Anda dapat menggunakan flag `-update-templates` untuk memperbarui templat inti kapan saja; Anda juga dapat menulis pemeriksaan Anda sendiri untuk alur kerja individu dan untuk kebutuhan Anda sendiri dengan mengikuti [panduan pembuatan templat Nuclei](https://nuclei.projectdiscovery.io/templating-guide/).
Untuk referensi penulisan sintaks DSL berbasis YAML tersedia [di sini](SYNTAX-REFERENCE.md).
</td>
</tr>
</table>
### Cara Pakai
```sh
nuclei -h
```
Ini akan menampilkan bantuan untuk alat tersebut. Berikut adalah semua flag yang didukungnya.
```console
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)
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
-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
-nts, -no-timestamp disable 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
-passive enable passive HTTP response processing mode
-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)
-i, -interface string network interface to use for network scan
-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 save in bytes (default 10485760)
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
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)
-project use a project folder to avoid sending same request multiple times
-project-path string set a specific project path
-spm, -stop-at-first-path stop processing HTTP requests after the first match (may break template/workflow logic)
-stream stream mode - start elaborating without sorting the input
-irt, -input-read-timeout duration timeout on input read (default 3m0s)
-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
-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:
-update update nuclei engine to the latest released version
-ut, -update-templates update nuclei-templates to latest released version
-ud, -update-directory string overwrite the default directory to install 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)
```
### Menjalankan Nuclei
Memindai domain target dengan templat Nuclei yang [dikurasi oleh komunitas](https://github.com/projectdiscovery/nuclei-templates).
```sh
nuclei -u https://example.com
```
Memindai URL target dengan templat Nuclei yang [dikurasi oleh komunitas](https://github.com/projectdiscovery/nuclei-templates).
```sh
nuclei -list urls.txt
```
Contoh dari berkas `urls.txt`:
```yaml
http://example.com
http://app.example.com
http://test.example.com
http://uat.example.com
```
**Contoh lebih detil tentang menjalankan Nuclei dapat ditemukan [di sini](https://nuclei.projectdiscovery.io/nuclei/get-started/#running-nuclei).**
# Untuk Teknisi Keamanan
Nuclei menawarkan sejumlah besar fitur yang berguna bagi teknisi keamanan untuk menyesuaikan alur kerja di organisasi mereka. Dengan berbagai kemampuan pemindaian (seperti misalnya DNS, HTTP, TCP), teknisi keamanan dapat dengan mudah membuat rangkaian pemeriksaan khusus mereka dengan Nuclei.
- Berbagai protokol yang didukung: TCP, DNS, HTTP, File, dll
- Mencapai langkah-langkah kerentanan yang kompleks dengan alur kerja dan [permintaan dinamis](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/).
- Mudah diintegrasikan ke dalam CI/CD, dirancang agar mudah diintegrasikan ke dalam siklus regresi untuk secara aktif memeriksa perbaikan dan kemunculan kerentanan kembali.
<h1 align="left">
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/"><img src="static/learn-more-button.png" width="170px" alt="Pelajari Selengkapnya"></a>
</h1>
<table>
<tr>
<td>
**Untuk Pemburu Celah Berhadiah:**
Nuclei memungkinkan Anda untuk menyesuaikan pendekatan pengujian Anda dengan rangkaian pemeriksaan Anda sendiri dan dengan mudah menjalankan program celah berhadiah Anda. Selain itu, Nuclei dapat dengan mudah diintegrasikan ke dalam alur kerja pemindaian berkelanjutan.
- Dirancang agar mudah diintegrasikan ke dalam alur kerja alat lainnya.
- Dapat memproses ribuan host hanya dalam beberapa menit.
- Mudah mengotomatiskan pendekatan pengujian khusus Anda dengan sintaks DSL berbasis YAML sederhana kami.
Silakan periksa proyek sumber terbuka kami yang lain yang mungkin cocok dengan alur kerja celah berhadiah Anda: [github.com/projectdiscovery](http://github.com/projectdiscovery), kami juga menyediakan [penyegaran data DNS di Chaos setiap hari](http://chaos.projectdiscovery.io).
</td>
</tr>
</table>
<table>
<tr>
<td>
**Untuk Penguji Penetrasi:**
Nuclei sangat meningkatkan cara Anda mendekati penilaian keamanan dengan menambah proses manual yang berulang. Para konsultan sudah mengonversi langkah penilaian manual mereka dengan Nuclei, ini memungkinkan mereka untuk menjalankan serangkaian pendekatan penilaian khusus mereka di ribuan host secara otomatis.
Para penguji penetrasi mendapatkan kekuatan penuh dari templat publik dan kemampuan penyesuaian kami untuk mempercepat proses penilaian mereka, dan khususnya dengan siklus regresi di mana Anda dapat dengan mudah memverifikasi perbaikannya.
- Mudah untuk membuat daftar pemeriksa kepatuhan Anda, sederet standar (mis., OWASP 10 Teratas).
- Dengan kemampuan seperti [fuzz](https://nuclei.projectdiscovery.io/templating-guide/#advance-fuzzing) dan [alur kerja](https://nuclei.projectdiscovery.io/templating-guide/#workflows), langkah manual yang rumit dan penilaian berulang dapat dengan mudah diotomatisasi dengan Nuclei.
- Mudah untuk menguji ulang perbaikan kerentanan hanya dengan menjalankan ulang template.
</td>
</tr>
</table>
# Untuk Pengembang dan Organisasi
Nuclei dibangun dengan kesederhanaan dalam pemikiran, dengan templat yang didukung komunitas oleh ratusan peneliti keamanan, memungkinkan Anda untuk tidak tertinggal dengan ancaman keamanan terbaru menggunakan pemindaian Nuclei terus menerus pada host. Ini dirancang agar mudah diintegrasikan ke dalam siklus pengujian regresi, untuk memverifikasi perbaikan dan menghilangkan kerentanan agar tidak terjadi di masa mendatang.
- **CI/CD:** Pengembang sudah memanfaatkan Nuclei dalam aliran CI/CD mereka, ini memungkinkan mereka untuk terus memantau lingkungan pementasan dan produksi mereka dengan templat yang disesuaikan.
- **Siklus Regresi Berkelanjutan:** Dengan Nuclei, Anda dapat membuat templat khusus pada setiap kerentanan baru yang teridentifikasi dan dimasukkan ke dalam mesin Nuclei untuk dihilangkan dalam siklus regresi berkelanjutan.
Kami memiliki [utas diskusi tentang ini](https://github.com/projectdiscovery/nuclei-templates/discussions/693), sudah ada beberapa program celah berhadiah yang memberikan insentif kepada peretas untuk menulis templat inti dengan setiap pengiriman, yang membantu mereka untuk menghilangkan kerentanan di semua aset mereka, serta untuk menghilangkan risiko masa depan yang muncul kembali pada lingkungan produksi. Jika Anda tertarik untuk menerapkannya di organisasi Anda, jangan ragu untuk [menghubungi kami](mailto:contact@projectdiscovery.io). Kami akan dengan senang hati membantu Anda dalam proses memulai, atau Anda juga dapat memposting ke [utas diskusi](https://github.com/projectdiscovery/nuclei-templates/discussions/693) untuk bantuan apapun.
<h3 align="center">
<img src="static/regression-with-nuclei.jpg" alt="Siklus Regresi Berkelanjutan dengan Nuclei" width="1100px"></a>
</h3>
<h1 align="left">
<a href="https://github.com/projectdiscovery/nuclei-action"><img src="static/learn-more-button.png" width="170px" alt="Pelajari Selengkapnya"></a>
</h1>
### Sumber Daya
- [Menemukan bug dengan menggunakan Nuclei dengan PinkDraconian (Robbe Van Roey)](https://www.youtube.com/watch?v=ewP0xVPW-Pk) oleh **[@PinkDraconian](https://twitter.com/PinkDraconian)**
- [Nuclei: Mengemas Pukulan dengan Pemindaian Kerentanan](https://bishopfox.com/blog/nuclei-vulnerability-scan) oleh **Bishopfox**
- [Kerangka kemanjuran WAF](https://www.fastly.com/blog/the-waf-efficacy-framework-measuring-the-effectiveness-of-your-waf) oleh **Fastly**
- [Memindai Aplikasi Web Langsung dengan Nuclei di Aliran CI/CD](https://blog.escape.tech/devsecops-part-iii-scanning-live-web-applications/) oleh **[@TristanKalos](https://twitter.com/TristanKalos)**
- [Pemindaian Bertenaga Komunitas dengan Nuclei](https://blog.projectdiscovery.io/community-powered-scanning-with-nuclei/)
- [Nuclei Unleashed - Menulis eksploitasi kompleks dengan cepat](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/)
- [Nuclei - Fuzz semua hal](https://blog.projectdiscovery.io/nuclei-fuzz-all-the-things/)
- [Integrasi Nuclei + Interactsh untuk Mengotomatiskan Pengujian OOB](https://blog.projectdiscovery.io/nuclei-interactsh-integration/)
- [Mempersenjatai Alur Kerja Nuclei untuk Menghancurkan Semua Hal](https://medium.com/@dwisiswant0/weaponizes-nuclei-workflows-to-pwn-all-the-things-cd01223feb77) oleh **[@dwisiswant0](https://github.com/dwisiswant0)**
- [Bagaimana Memindai Terus-menerus dengan Nuclei?](https://medium.com/@dwisiswant0/how-to-scan-continuously-with-nuclei-fcb7e9d8b8b9) oleh **[@dwisiswant0](https://github.com/dwisiswant0)**
- [Retas dengan Otomatisasi !!!](https://dhiyaneshgeek.github.io/web/security/2021/07/19/hack-with-automation/) oleh **[@DhiyaneshGeek](https://github.com/DhiyaneshGeek)**
### Kredit
Terima kasih kepada semua komunitas yang luar biasa yang [berkontribusi untuk mengirimkan PR](https://github.com/projectdiscovery/nuclei/graphs/contributors). Lihat juga proyek sumber-terbuka serupa di bawah ini yang mungkin sesuai dengan alur kerja Anda:
[FFuF](https://github.com/ffuf/ffuf), [Qsfuzz](https://github.com/ameenmaali/qsfuzz), [Inception](https://github.com/proabiral/inception), [Snallygaster](https://github.com/hannob/snallygaster), [Gofingerprint](https://github.com/Static-Flow/gofingerprint), [Sn1per](https://github.com/1N3/Sn1per/tree/master/templates), [Google tsunami](https://github.com/google/tsunami-security-scanner), [Jaeles](https://github.com/jaeles-project/jaeles), [ChopChop](https://github.com/michelin/ChopChop)
### Lisensi
Nuclei didistribusikan di bawah [Lisensi MIT](https://github.com/projectdiscovery/nuclei/blob/master/LICENSE.md)
<h1 align="left">
<a href="https://discord.gg/projectdiscovery"><img src="static/Join-Discord.png" width="380" alt="Join Discord"></a> <a href="https://nuclei.projectdiscovery.io"><img src="static/check-nuclei-documentation.png" width="380" alt="Cek Dokumentasi Nuclei"></a>
</h1>

View File

@ -106,6 +106,7 @@ TEMPLATES:
-wu, -workflow-url string[] 실행할 워크플로 URL 목록(쉼표로 구분된 파일)
-validate nuclei로 전달된 템플릿 검증
-tl 사용 가능한 모든 템플릿 목록
-td 템플릿 내용 표시
FILTERING:
-a, -author string[] 작성자를 기준으로 실행할 템플릿(쉼표로 구분된 파일)
@ -179,7 +180,7 @@ OPTIMIZATIONS:
-mhe, -max-host-error int 스캔을 건너뛰기 전에 호스트에 대한 최대 오류 수 (기본 30)
-project 프로젝트 폴더를 사용하여 동일한 요청을 여러 번 보내지 않음
-project-path string 특정 프로젝트 경로 설정
-spm, -stop-at-first-path 첫 번째 일치 후 HTTP 요청 처리 중지 (template/workflow 로직이 중단될 수 있음)
-spm, -stop-at-first-match 첫 번째 일치 후 HTTP 요청 처리 중지 (template/workflow 로직이 중단될 수 있음)
-stream stream 모드 - 입력을 정렬하지 않고 elaborating 시작
HEADLESS:

View File

@ -3924,6 +3924,28 @@ Client Cipher Suites - auto if not specified.
<hr />
<div class="dd">
<code>scan_mode</code> <i>string</i>
</div>
<div class="dt">
Tls Scan Mode - auto if not specified
Valid values:
- <code>ctls</code>
- <code>ztls</code>
- <code>auto</code>
</div>
<hr />

View File

@ -7,6 +7,7 @@ info:
requests:
- raw:
# Note for the integration test: dsl expression should not contain commas
- |
GET / HTTP/1.1
Host: {{Hostname}}
@ -90,9 +91,11 @@ requests:
78: {{line_starts_with("Hi\nHello", "He")}}
79: {{line_ends_with("Hello\nHi", "lo")}}
80: {{sort("a1b2c3d4e5")}}
81: {{join(" ", sort("b", "a", "2", "c", "3", "1", "d", "4"))}}
82: {{uniq("abcabdaabbccd")}}
81: {{uniq("abcabdaabbccd")}}
82: {{join(" ", sort("b", "a", "2", "c", "3", "1", "d", "4"))}}
83: {{join(" ", uniq("ab", "cd", "12", "34", "12", "cd"))}}
84: {{split("ab,cd,efg", ",")}}
85: {{split("ab,cd,efg", ",", 2)}}
extractors:
- type: regex

View File

@ -1121,7 +1121,7 @@
"tls13"
],
"type": "string",
"title": "TLS version",
"title": "Min. TLS version",
"description": "Minimum tls version - automatic if not specified."
},
"max_version": {
@ -1133,7 +1133,7 @@
"tls13"
],
"type": "string",
"title": "TLS version",
"title": "Max. TLS version",
"description": "Max tls version - automatic if not specified."
},
"cipher_suites": {
@ -1141,6 +1141,16 @@
"type": "string"
},
"type": "array"
},
"scan_mode": {
"enum": [
"ctls",
"ztls",
"auto"
],
"type": "string",
"title": "Scan Mode",
"description": "Scan Mode - auto if not specified."
}
},
"additionalProperties": false,

View File

@ -25,8 +25,8 @@ docs:
test:
$(GOTEST) $(GOFLAGS) ./...
integration:
bash ../integration_tests/run.sh
cd ../integration_tests; bash run.sh
functional:
bash cmd/functional-tests/run.sh
cd cmd/functional-test; bash run.sh
tidy:
$(GOMOD) tidy
$(GOMOD) tidy

View File

@ -0,0 +1,4 @@
scanme.sh
scanme.sh?a=1
scanme.sh?a=2
scanme.sh?a=3

View File

@ -29,6 +29,12 @@ func main() {
if err != nil || d.IsDir() {
return nil
}
pathIndex := path[strings.Index(path, "nuclei-templates/")+17:]
pathIndex = strings.TrimPrefix(pathIndex, "nuclei-templates/")
// Ignore items starting with dots
if strings.HasPrefix(pathIndex, ".") {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
@ -37,7 +43,7 @@ func main() {
_, _ = io.Copy(h, bytes.NewReader(data))
hash := hex.EncodeToString(h.Sum(nil))
_, _ = file.WriteString(path[strings.Index(path, "nuclei-templates/")+17:])
_, _ = file.WriteString(pathIndex)
_, _ = file.WriteString(":")
_, _ = file.WriteString(hash)
_, _ = file.WriteString("\n")

View File

@ -8,7 +8,6 @@ import (
"net/http"
"net/http/httptest"
"net/http/httputil"
"regexp"
"strconv"
"strings"
"time"
@ -16,6 +15,7 @@ import (
"github.com/julienschmidt/httprouter"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
stringsutil "github.com/projectdiscovery/utils/strings"
)
var httpTestcases = map[string]testutils.TestCase{
@ -284,19 +284,22 @@ func (h *httpDSLFunctions) Execute(filePath string) error {
return err
}
resultPattern := regexp.MustCompile(`\[[^]]+] \[[^]]+] \[[^]]+] [^]]+ \[([^]]+)]`)
submatch := resultPattern.FindStringSubmatch(results[0])
if len(submatch) != 2 {
return errors.New("could not parse the result")
// get result part
resultPart, err := stringsutil.After(results[0], ts.URL)
if err != nil {
return err
}
totalExtracted := strings.Split(submatch[1], ",")
numberOfDslFunctions := 83
if len(totalExtracted) != numberOfDslFunctions {
// remove additional characters till the first valid result and ignore last ] which doesn't alter the total count
resultPart = stringsutil.TrimPrefixAny(resultPart, "/", " ", "[")
extracted := strings.Split(resultPart, ",")
numberOfDslFunctions := 85
if len(extracted) != numberOfDslFunctions {
return errors.New("incorrect number of results")
}
for _, header := range totalExtracted {
for _, header := range extracted {
parts := strings.Split(header, ": ")
index, err := strconv.Atoi(parts[0])
if err != nil {

View File

@ -18,6 +18,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/uncover"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
@ -124,9 +125,9 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.CreateGroup("input", "Target",
flagSet.StringSliceVarP(&options.Targets, "target", "u", []string{}, "target URLs/hosts to scan", goflags.StringSliceOptions),
flagSet.StringVarP(&options.TargetsFilePath, "list", "l", "", "path to file containing a list of target URLs/hosts to scan (one per line)"),
flagSet.StringVar(&options.Resume, "resume", "", "Resume scan using resume.cfg (clustering will be disabled)"),
flagSet.BoolVarP(&options.ScanAllIPs, "scan-all-ips", "sa", false, "Scan all the ip's associated with dns record"),
flagSet.StringSliceVarP(&options.IPVersion, "ip-version", "iv", []string{"4"}, "IP version to scan of hostname (4,6) - (default 4)", goflags.CommaSeparatedStringSliceOptions),
flagSet.StringVar(&options.Resume, "resume", "", "resume scan using resume.cfg (clustering will be disabled)"),
flagSet.BoolVarP(&options.ScanAllIPs, "scan-all-ips", "sa", false, "scan all the IP's associated with dns record"),
flagSet.StringSliceVarP(&options.IPVersion, "ip-version", "iv", []string{""}, "IP version to scan of hostname (4,6) - (default 4)", goflags.CommaSeparatedStringSliceOptions),
)
flagSet.CreateGroup("templates", "Templates",
@ -138,7 +139,8 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.Workflows, "workflows", "w", []string{}, "list of workflow or workflow directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.WorkflowURLs, "workflow-url", "wu", []string{}, "list of workflow urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
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.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"),
)
@ -169,7 +171,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVar(&options.JSON, "json", false, "write output in JSONL(ines) format"),
flagSet.BoolVarP(&options.JSONRequests, "include-rr", "irr", false, "include request/response pairs in the JSONL output (for findings only)"),
flagSet.BoolVarP(&options.NoMeta, "no-meta", "nm", false, "disable printing result metadata in cli output"),
flagSet.BoolVarP(&options.NoTimestamp, "no-timestamp", "nts", false, "disable printing timestamp in cli output"),
flagSet.BoolVarP(&options.Timestamp, "timestamp", "ts", false, "enables printing timestamp in cli output"),
flagSet.StringVarP(&options.ReportingDB, "report-db", "rdb", "", "nuclei reporting database (always use this to persist report data)"),
flagSet.BoolVarP(&options.MatcherStatus, "matcher-status", "ms", false, "display match failure status"),
flagSet.StringVarP(&options.MarkdownExportDirectory, "markdown-export", "me", "", "directory to export results in markdown format"),
@ -188,6 +190,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.ResolversFile, "resolvers", "r", "", "file containing resolver list for nuclei"),
flagSet.BoolVarP(&options.SystemResolvers, "system-resolvers", "sr", false, "use system DNS resolving as error fallback"),
flagSet.BoolVar(&options.OfflineHTTP, "passive", false, "enable passive HTTP response processing mode"),
flagSet.BoolVarP(&options.ForceAttemptHTTP2, "force-http2", "fh2", false, "force http2 connection on requests"),
flagSet.BoolVarP(&options.EnvironmentVariables, "env-vars", "ev", false, "enable environment variables to be used in template"),
flagSet.StringVarP(&options.ClientCertFile, "client-cert", "cc", "", "client certificate file (PEM-encoded) used for authenticating against scanned hosts"),
flagSet.StringVarP(&options.ClientKeyFile, "client-key", "ck", "", "client key file (PEM-encoded) used for authenticating against scanned hosts"),
@ -195,10 +198,11 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.ShowMatchLine, "show-match-line", "sml", false, "show match lines for file templates, works with extractors only"),
flagSet.BoolVar(&options.ZTLS, "ztls", false, "use ztls library with autofallback to standard one for tls13"),
flagSet.StringVar(&options.SNI, "sni", "", "tls sni hostname to use (default: input domain name)"),
flagSet.BoolVar(&options.Sandbox, "sandbox", false, "sandbox nuclei for safe templates execution"),
flagSet.StringVarP(&options.Interface, "interface", "i", "", "network interface to use for network scan"),
flagSet.StringVarP(&options.AttackType, "attack-type", "at", "", "type of payload combinations to perform (batteringram,pitchfork,clusterbomb)"),
flagSet.StringVarP(&options.SourceIP, "source-ip", "sip", "", "source ip address to use for network scan"),
flagSet.StringVar(&options.CustomConfigDir, "config-directory", "", "Override the default config path ($home/.config)"),
flagSet.StringVar(&options.CustomConfigDir, "config-directory", "", "override the default config path ($home/.config)"),
flagSet.IntVarP(&options.ResponseReadSize, "response-size-read", "rsr", 10*1024*1024, "max response size to read in bytes"),
flagSet.IntVarP(&options.ResponseSaveSize, "response-size-save", "rss", 1*1024*1024, "max response size to read in bytes"),
)
@ -213,6 +217,15 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.NoInteractsh, "no-interactsh", "ni", false, "disable interactsh server for OAST testing, exclude OAST based templates"),
)
flagSet.CreateGroup("uncover", "Uncover",
flagSet.BoolVarP(&options.Uncover, "uncover", "uc", false, "enable uncover engine"),
flagSet.StringSliceVarP(&options.UncoverQuery, "uncover-query", "uq", []string{}, "uncover search query", goflags.FileStringSliceOptions),
flagSet.StringSliceVarP(&options.UncoverEngine, "uncover-engine", "ue", []string{}, fmt.Sprintf("uncover search engine (%s) (default shodan)", uncover.GetUncoverSupportedAgents()), goflags.FileStringSliceOptions),
flagSet.StringVarP(&options.UncoverField, "uncover-field", "uf", "ip:port", "uncover fields to return (ip,port,host)"),
flagSet.IntVarP(&options.UncoverLimit, "uncover-limit", "ul", 100, "uncover results to return"),
flagSet.IntVarP(&options.UncoverDelay, "uncover-delay", "ucd", 1, "delay between uncover query requests in seconds (0 to disable)"),
)
flagSet.CreateGroup("rate-limit", "Rate-Limit",
flagSet.IntVarP(&options.RateLimit, "rate-limit", "rl", 150, "maximum number of requests to send per second"),
flagSet.IntVarP(&options.RateLimitMinute, "rate-limit-minute", "rlm", 0, "maximum number of requests to send per minute"),
@ -225,11 +238,11 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.CreateGroup("optimization", "Optimizations",
flagSet.IntVar(&options.Timeout, "timeout", 10, "time to wait in seconds before timeout"),
flagSet.IntVar(&options.Retries, "retries", 1, "number of times to retry a failed request"),
flagSet.BoolVarP(&options.LeaveDefaultPorts, "leave-default-ports", "ldp", false, "leave default HTTP/HTTPS ports (eg. host:80,host:443"),
flagSet.BoolVarP(&options.LeaveDefaultPorts, "leave-default-ports", "ldp", false, "leave default HTTP/HTTPS ports (eg. host:80,host:443)"),
flagSet.IntVarP(&options.MaxHostError, "max-host-error", "mhe", 30, "max errors for a host before skipping from scan"),
flagSet.BoolVar(&options.Project, "project", false, "use a project folder to avoid sending same request multiple times"),
flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"),
flagSet.BoolVarP(&options.StopAtFirstMatch, "stop-at-first-path", "spm", false, "stop processing HTTP requests after the first match (may break template/workflow logic)"),
flagSet.BoolVarP(&options.StopAtFirstMatch, "stop-at-first-match", "spm", false, "stop processing HTTP requests after the first match (may break template/workflow logic)"),
flagSet.BoolVar(&options.Stream, "stream", false, "stream mode - start elaborating without sorting the input"),
flagSet.DurationVarP(&options.InputReadTimeout, "input-read-timeout", "irt", time.Duration(3*time.Minute), "timeout on input read"),
flagSet.BoolVarP(&options.DisableHTTPProbe, "no-httpx", "nh", false, "disable httpx probing for non-url input"),
@ -237,10 +250,10 @@ on extensive configurability, massive extensibility and ease of use.`)
)
flagSet.CreateGroup("headless", "Headless",
flagSet.BoolVar(&options.Headless, "headless", false, "enable templates that require headless browser support (root user on linux will disable sandbox)"),
flagSet.BoolVar(&options.Headless, "headless", false, "enable templates that require headless browser support (root user on Linux will disable sandbox)"),
flagSet.IntVar(&options.PageTimeout, "page-timeout", 20, "seconds to wait for each page in headless mode"),
flagSet.BoolVarP(&options.ShowBrowser, "show-browser", "sb", false, "show the browser on the screen when running templates with headless mode"),
flagSet.BoolVarP(&options.UseInstalledChrome, "system-chrome", "sc", false, "Use local installed chrome browser instead of nuclei installed"),
flagSet.BoolVarP(&options.UseInstalledChrome, "system-chrome", "sc", false, "use local installed Chrome browser instead of nuclei installed"),
flagSet.BoolVarP(&options.ShowActions, "list-headless-action", "lha", false, "list available headless actions"),
)
@ -258,7 +271,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.Verbose, "verbose", "v", false, "show verbose output"),
flagSet.StringVar(&memProfile, "profile-mem", "", "optional nuclei memory profile dump file"),
flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"),
flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "sdp", false, "show variables dump for debugging"),
flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "svd", false, "show variables dump for debugging"),
flagSet.BoolVarP(&options.EnablePprof, "enable-pprof", "ep", false, "enable pprof debugging server"),
flagSet.BoolVarP(&options.TemplatesVersion, "templates-version", "tv", false, "shows the version of the installed nuclei-templates"),
flagSet.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"),
@ -268,8 +281,6 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.UpdateNuclei, "update", "un", false, "update nuclei engine to the latest released version"),
flagSet.BoolVarP(&options.UpdateTemplates, "update-templates", "ut", false, "update nuclei-templates to latest released version"),
flagSet.StringVarP(&options.TemplatesDirectory, "update-template-dir", "ud", "", "custom directory to install / update nuclei-templates"),
flagSet.StringVarEnv(&options.GithubToken, "github-token", "gt", "", "GITHUB_TOKEN", "github token to download public/private templates (GITHUB_TOKEN)"),
flagSet.StringSliceVarP(&options.GithubTemplateRepo, "github-template-repo", "gtr", []string{}, "github template repository to download / update (GITHUB_TEMPLATE_REPO)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.BoolVarP(&options.NoUpdateTemplates, "disable-update-check", "duc", false, "disable automatic nuclei/templates update check"),
flagSet.StringVarEnv(&options.AwsAccessKey, "aws-access-key", "aak", "", "AWS_ACCESS_KEY", "aws access key to download template from bucket (AWS_ACCESS_KEY)"),
flagSet.StringVarEnv(&options.AwsSecretKey, "aws-secret-key", "ask", "", "AWS_SECRET_KEY", "aws secret key to download template from bucket (AWS_SECRET_KEY)"),
@ -309,13 +320,6 @@ on extensive configurability, massive extensibility and ease of use.`)
if options.LeaveDefaultPorts {
http.LeaveDefaultPorts = true
}
if os.Getenv("GITHUB_TEMPLATE_REPO") != "" {
// there is no flag Env function for slice variable type yet.
err := options.GithubTemplateRepo.Set(os.Getenv("GITHUB_TEMPLATE_REPO"))
if err != nil {
gologger.Fatal().Msgf("Could not read GITHUB_TEMPLATE_REPO env variable: %s\n", err)
}
}
if options.CustomConfigDir != "" {
originalIgnorePath := config.GetIgnoreFilePath()
config.SetCustomConfigDirectory(options.CustomConfigDir)

132
v2/go.mod
View File

@ -12,64 +12,59 @@ require (
github.com/bluele/gcache v0.0.2
github.com/corpix/uarand v0.2.0
github.com/go-playground/validator/v10 v10.11.1
github.com/go-rod/rod v0.112.0
github.com/go-rod/rod v0.112.2
github.com/gobwas/ws v1.1.0
github.com/google/go-github v17.0.0+incompatible
github.com/itchyny/gojq v0.12.9
github.com/itchyny/gojq v0.12.10
github.com/json-iterator/go v1.1.12
github.com/julienschmidt/httprouter v1.3.0
github.com/karlseguin/ccache v2.0.3+incompatible
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/miekg/dns v1.1.50
github.com/olekukonko/tablewriter v0.0.5
github.com/owenrumney/go-sarif/v2 v2.1.2
github.com/pkg/errors v0.9.1
github.com/projectdiscovery/clistats v0.0.8
github.com/projectdiscovery/fastdialer v0.0.18-0.20221102102120-8e9343e8b0e0
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08
github.com/projectdiscovery/gologger v1.1.4
github.com/projectdiscovery/clistats v0.0.9
github.com/projectdiscovery/fastdialer v0.0.19
github.com/projectdiscovery/gologger v1.1.5
github.com/projectdiscovery/hmap v0.0.2
github.com/projectdiscovery/interactsh v1.0.6-0.20220827132222-460cc6270053
github.com/projectdiscovery/nuclei-updatecheck-api v0.0.0-20211006155443-c0a8d610a4df
github.com/projectdiscovery/rawhttp v0.1.2
github.com/projectdiscovery/rawhttp v0.1.4
github.com/projectdiscovery/retryabledns v1.0.17
github.com/projectdiscovery/retryablehttp-go v1.0.5-0.20221203124408-1d25b06b0572
github.com/projectdiscovery/stringsutil v0.0.2 // indirect
github.com/projectdiscovery/retryablehttp-go v1.0.6-0.20221206071935-7924d7d34953
github.com/projectdiscovery/stringsutil v0.0.2
github.com/projectdiscovery/yamldoc-go v1.0.3-0.20211126104922-00d2c6bb43b6
github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.4.0
github.com/segmentio/ksuid v1.0.4
github.com/shirou/gopsutil/v3 v3.22.10
github.com/shirou/gopsutil/v3 v3.22.11
github.com/spaolacci/murmur3 v1.1.0
github.com/spf13/cast v1.5.0
github.com/syndtr/goleveldb v1.0.0
github.com/tj/go-update v2.2.5-0.20200519121640-62b4b798fd68+incompatible
github.com/valyala/fasttemplate v1.2.2
github.com/weppos/publicsuffix-go v0.15.1-0.20220724114530-e087fba66a37
github.com/xanzy/go-gitlab v0.74.0
github.com/xanzy/go-gitlab v0.76.0
go.uber.org/atomic v1.10.0
go.uber.org/multierr v1.8.0
golang.org/x/net v0.2.0
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
golang.org/x/text v0.4.0
golang.org/x/text v0.5.0
gopkg.in/yaml.v2 v2.4.0
moul.io/http2curl v1.0.0
)
require github.com/aws/aws-sdk-go v1.44.134
require (
github.com/DataDog/gostackparse v0.6.0
github.com/antchfx/xmlquery v1.3.12
github.com/antchfx/xmlquery v1.3.13
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/aws/aws-sdk-go-v2 v1.17.1
github.com/aws/aws-sdk-go-v2/config v1.17.10
github.com/aws/aws-sdk-go-v2/credentials v1.12.23
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1
github.com/aws/aws-sdk-go-v2 v1.17.2
github.com/aws/aws-sdk-go-v2/config v1.18.4
github.com/aws/aws-sdk-go-v2/credentials v1.13.4
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5
github.com/docker/go-units v0.5.0
github.com/fatih/structs v1.1.0
github.com/go-git/go-git/v5 v5.4.2
github.com/go-git/go-git/v5 v5.5.0
github.com/h2non/filetype v1.1.3
github.com/hashicorp/go-version v1.6.0
github.com/klauspost/compress v1.15.12
@ -77,19 +72,40 @@ require (
github.com/mholt/archiver v3.1.1+incompatible
github.com/mitchellh/go-homedir v1.1.0
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/goflags v0.1.3
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08
github.com/projectdiscovery/goflags v0.1.5
github.com/projectdiscovery/nvd v1.0.9
github.com/projectdiscovery/ratelimit v0.0.0-20221004232058-7b82379157fa
github.com/projectdiscovery/ratelimit v0.0.2
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
github.com/projectdiscovery/tlsx v0.0.7
github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.0.0
github.com/projectdiscovery/uncover v1.0.1
github.com/projectdiscovery/utils v0.0.4-0.20221201124851-f8524345b6d3
github.com/projectdiscovery/wappalyzergo v0.0.67
github.com/projectdiscovery/wappalyzergo v0.0.71
github.com/stretchr/testify v1.8.1
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.1
)
require github.com/projectdiscovery/asnmap v0.0.1 // indirect
require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/bits-and-blooms/bloom/v3 v3.0.1 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/karlseguin/expect v1.0.8 // indirect
github.com/pjbgf/sha1cd v0.2.0 // indirect
github.com/projectdiscovery/asnmap v0.0.1 // indirect
github.com/projectdiscovery/sliceutil v0.0.1 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
)
require (
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a // indirect
@ -104,8 +120,6 @@ require (
github.com/andybalholm/cascadia v1.1.0 // indirect
github.com/antchfx/xpath v1.2.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/bits-and-blooms/bloom/v3 v3.0.1 // indirect
github.com/c4milo/unpackit v0.1.0 // indirect
github.com/caddyserver/certmagic v0.16.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
@ -142,18 +156,17 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hdm/jarm-go v0.0.7 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/itchyny/timefmt-go v0.1.4 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mholt/acmez v1.0.4 // indirect
github.com/microcosm-cc/bluemonday v1.0.21 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@ -164,21 +177,21 @@ require (
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/projectdiscovery/blackrock v0.0.0-20220628111055-35616c71b2dc // indirect
github.com/projectdiscovery/mapcidr v1.0.3
github.com/projectdiscovery/networkpolicy v0.0.2-0.20220525172507-b844eafc878d // indirect
github.com/projectdiscovery/networkpolicy v0.0.3
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/trivago/tgo v1.0.7 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/yl2chen/cidranger v1.0.2 // indirect
github.com/ysmood/goob v0.4.0 // indirect
github.com/ysmood/gson v0.7.1 // indirect
github.com/ysmood/gson v0.7.3 // indirect
github.com/ysmood/leakless v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521 // indirect
@ -186,7 +199,7 @@ require (
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/zap v1.23.0 // indirect
goftp.io/server/v2 v2.0.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/exp v0.0.0-20221019170559-20944726eadf
golang.org/x/mod v0.6.0 // indirect
golang.org/x/sys v0.2.0 // indirect
@ -199,41 +212,36 @@ require (
)
require (
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 // indirect
github.com/aws/smithy-go v1.13.4 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/alecthomas/chroma v0.10.0
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/nwaples/rardecode v1.1.2 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/projectdiscovery/cryptoutil v0.0.0-20210805184155-b5d2512f9345 // indirect; indirectdev
github.com/projectdiscovery/fileutil v0.0.3
github.com/projectdiscovery/iputil v0.0.2 // indirect
github.com/projectdiscovery/sliceutil v0.0.1 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/src-d/gcfg v1.4.0 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xanzy/ssh-agent v0.3.2 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

617
v2/go.sum

File diff suppressed because it is too large Load Diff

View File

@ -12,14 +12,11 @@ var banner = fmt.Sprintf(`
____ __ _______/ /__ (_)
/ __ \/ / / / ___/ / _ \/ /
/ / / / /_/ / /__/ / __/ /
/_/ /_/\__,_/\___/_/\___/_/ %s
/_/ /_/\__,_/\___/_/\___/_/ v%s
`, config.Version)
// showBanner is used to show the banner to the user
func showBanner() {
gologger.Print().Msgf("%s\n", banner)
gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
gologger.Print().Label("WRN").Msgf("Use with caution. You are responsible for your actions.\n")
gologger.Print().Label("WRN").Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n")
}

View File

@ -3,9 +3,11 @@ package runner
import (
"fmt"
"io"
"net/http"
"strings"
"sync/atomic"
"github.com/corpix/uarand"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/hmap/store/hybrid"
@ -29,7 +31,7 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
if err != nil {
return nil, errors.Wrap(err, "could not get http client")
}
gologger.Info().Msgf("Running httpx on input to execute http based template")
gologger.Info().Msgf("Running httpx on input host")
var bulkSize = probeBulkSize
if r.options.BulkSize > probeBulkSize {
@ -56,7 +58,7 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
})
swg.Wait()
gologger.Info().Msgf("Discovered %d URL from input", atomic.LoadInt32(&count))
gologger.Info().Msgf("Found %d URL from httpx", atomic.LoadInt32(&count))
return hm, nil
}
@ -71,7 +73,13 @@ var (
func probeURL(input string, httpclient *retryablehttp.Client) string {
for _, scheme := range httpSchemes {
formedURL := fmt.Sprintf("%s://%s", scheme, input)
resp, err := httpclient.Get(formedURL)
req, err := retryablehttp.NewRequest(http.MethodGet, formedURL, nil)
if err != nil {
continue
}
req.Header.Set("User-Agent", uarand.GetRandom())
resp, err := httpclient.Do(req)
if resp != nil {
_, _ = io.CopyN(io.Discard, resp.Body, drainReqSize)
resp.Body.Close()

View File

@ -30,7 +30,11 @@ func ReadCatalogChecksum() map[string]string {
if len(text) < 2 {
continue
}
checksums[text[0]] = text[1]
path := strings.TrimPrefix(text[0], "nuclei-templates/")
if strings.HasPrefix(path, ".") {
continue
}
checksums[path] = text[1]
}
return checksums
}

View File

@ -22,6 +22,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/headless/engine"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/stringsutil"
fileutil "github.com/projectdiscovery/utils/file"
)
@ -40,6 +41,9 @@ func ParseOptions(options *types.Options) {
// Check if stdin pipe was given
options.Stdin = !options.DisableStdin && fileutil.HasStdin()
// Read the inputs from env variables that not passed by flag.
readEnvInputVars(options)
// Read the inputs and configure the logging
configureOutput(options)
// Show the user the banner
@ -61,7 +65,13 @@ func ParseOptions(options *types.Options) {
if err != nil {
gologger.Fatal().Msgf("Could not read template configuration: %s\n", err)
}
gologger.Info().Msgf("Current nuclei-templates version: %s (%s)\n", configuration.TemplateVersion, configuration.TemplatesDirectory)
gologger.Info().Msgf("Public nuclei-templates version: %s (%s)\n", configuration.TemplateVersion, configuration.TemplatesDirectory)
if configuration.CustomS3TemplatesDirectory != "" {
gologger.Info().Msgf("Custom S3 templates location: %s\n", configuration.CustomS3TemplatesDirectory)
}
if configuration.CustomGithubTemplatesDirectory != "" {
gologger.Info().Msgf("Custom Github templates location: %s ", configuration.CustomGithubTemplatesDirectory)
}
os.Exit(0)
}
if options.ShowActions {
@ -101,6 +111,13 @@ func ParseOptions(options *types.Options) {
if options.GithubToken != "" && os.Getenv("GITHUB_TOKEN") != options.GithubToken {
os.Setenv("GITHUB_TOKEN", options.GithubToken)
}
if options.UncoverQuery != nil {
options.Uncover = true
if len(options.UncoverEngine) == 0 {
options.UncoverEngine = append(options.UncoverEngine, "shodan")
}
}
}
// validateOptions validates the configuration options passed
@ -141,13 +158,28 @@ func validateOptions(options *types.Options) error {
}
validateCertificatePaths([]string{options.ClientCertFile, options.ClientKeyFile, options.ClientCAFile})
}
// Verify aws secrets are passed if s3 tempalte bucket passed
if options.AwsBucketName != "" && (options.AwsAccessKey == "" || options.AwsSecretKey == "" || options.AwsRegion == "") {
fmt.Printf("b: %s k: %s s: %s r: %s", options.AwsBucketName, options.AwsAccessKey, options.AwsSecretKey, options.AwsRegion)
return errors.New("aws s3 bucket details are missing. Please provide region, access and secret key")
// Verify aws secrets are passed if s3 template bucket passed
if options.AwsBucketName != "" && options.UpdateTemplates {
var missing []string
if options.AwsAccessKey == "" {
missing = append(missing, "AWS_ACCESS_KEY")
}
if options.AwsSecretKey == "" {
missing = append(missing, "AWS_SECRET_KEY")
}
if options.AwsRegion == "" {
missing = append(missing, "AWS_REGION")
}
if missing != nil {
return fmt.Errorf("aws s3 bucket details are missing. Please provide %s", strings.Join(missing, ","))
}
}
// verify that a valid ip version type was selected (4, 6)
if len(options.IPVersion) == 0 {
// add ipv4 as default
options.IPVersion = append(options.IPVersion, "4")
}
var useIPV4, useIPV6 bool
for _, ipv := range options.IPVersion {
switch ipv {
@ -240,3 +272,16 @@ func validateCertificatePaths(certificatePaths []string) {
}
}
}
// Read the input from env and set options
func readEnvInputVars(options *types.Options) {
options.GithubToken = os.Getenv("GITHUB_TOKEN")
repolist := os.Getenv("GITHUB_TEMPLATE_REPO")
if repolist != "" {
options.GithubTemplateRepo = append(options.GithubTemplateRepo, stringsutil.SplitAny(repolist, ",")...)
}
options.AwsAccessKey = os.Getenv("AWS_ACCESS_KEY")
options.AwsSecretKey = os.Getenv("AWS_SECRET_KEY")
options.AwsBucketName = os.Getenv("AWS_TEMPLATE_BUCKET")
options.AwsRegion = os.Getenv("AWS_REGION")
}

View File

@ -42,6 +42,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/uncover"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/excludematchers"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/headless/engine"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool"
@ -74,7 +75,7 @@ type Runner struct {
hostErrors hosterrorscache.CacheInterface
resumeCfg *types.ResumeCfg
pprofServer *http.Server
customTemplates *[]customtemplates.CustomTemplateProvider
customTemplates []customtemplates.Provider
cloudClient *nucleicloud.Client
}
@ -185,7 +186,7 @@ func New(options *types.Options) (*Runner, error) {
runner.hmapInputProvider = hmapInput
// Create the output file if asked
outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.NoTimestamp, options.JSON, options.JSONRequests, options.MatcherStatus, options.StoreResponse, options.Output, options.TraceLogFile, options.ErrorLogFile, options.StoreResponseDir)
outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.Timestamp, options.JSON, options.JSONRequests, options.MatcherStatus, options.StoreResponse, options.Output, options.TraceLogFile, options.ErrorLogFile, options.StoreResponseDir)
if err != nil {
return nil, errors.Wrap(err, "could not create output file")
}
@ -256,9 +257,9 @@ func New(options *types.Options) (*Runner, error) {
}
if options.RateLimitMinute > 0 {
runner.ratelimiter = ratelimit.New(context.Background(), options.RateLimitMinute, time.Minute)
runner.ratelimiter = ratelimit.New(context.Background(), uint(options.RateLimitMinute), time.Minute)
} else if options.RateLimit > 0 {
runner.ratelimiter = ratelimit.New(context.Background(), options.RateLimit, time.Second)
runner.ratelimiter = ratelimit.New(context.Background(), uint(options.RateLimit), time.Second)
} else {
runner.ratelimiter = ratelimit.NewUnlimited(context.Background())
}
@ -443,8 +444,15 @@ func (r *Runner) RunEnumeration() error {
}
store.Load()
// add the hosts from the metadata queries of loaded templates into input provider
if r.options.Uncover && len(r.options.UncoverQuery) == 0 {
ret := uncover.GetUncoverTargetsFromMetadata(store.Templates(), r.options.UncoverDelay, r.options.UncoverLimit, r.options.UncoverField)
for host := range ret {
r.hmapInputProvider.Set(host)
}
}
// list all templates
if r.options.TemplateList {
if r.options.TemplateList || r.options.TemplateDisplay {
r.listAvailableStoreTemplates(store)
os.Exit(0)
}

View File

@ -1,10 +1,15 @@
package runner
import (
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"bytes"
"io/ioutil"
"path/filepath"
"strings"
"github.com/alecthomas/chroma/quick"
"github.com/logrusorgru/aurora"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
@ -17,36 +22,73 @@ func (r *Runner) logAvailableTemplate(tplPath string) {
if err != nil {
gologger.Error().Msgf("Could not parse file '%s': %s\n", tplPath, err)
} else {
gologger.Print().Msgf("%s\n", templates.TemplateLogMessage(t.ID,
types.ToString(t.Info.Name),
t.Info.Authors.ToSlice(),
t.Info.SeverityHolder.Severity))
r.verboseTemplate(t)
}
}
// log available templates for verbose (-vv)
func (r *Runner) verboseTemplate(tpl *templates.Template) {
gologger.Print().Msgf("%s\n", templates.TemplateLogMessage(tpl.ID,
types.ToString(tpl.Info.Name),
tpl.Info.Authors.ToSlice(),
tpl.Info.SeverityHolder.Severity))
}
func (r *Runner) listAvailableStoreTemplates(store *loader.Store) {
gologger.Print().Msgf(
"\nListing available v.%s nuclei templates for %s",
r.templatesConfig.TemplateVersion,
r.templatesConfig.TemplatesDirectory,
)
extraFlags := r.options.Templates != nil || r.options.Authors != nil ||
r.options.Tags != nil || len(r.options.ExcludeTags) > 3 ||
r.options.IncludeTags != nil || r.options.IncludeIds != nil ||
r.options.ExcludeIds != nil || r.options.IncludeTemplates != nil ||
r.options.ExcludedTemplates != nil || r.options.ExcludeMatchers != nil ||
r.options.Severities != nil || r.options.ExcludeSeverities != nil ||
r.options.Protocols != nil || r.options.ExcludeProtocols != nil ||
r.options.IncludeConditions != nil || r.options.TemplateList
for _, tl := range store.Templates() {
if extraFlags {
path := strings.TrimPrefix(tl.Path, r.templatesConfig.TemplatesDirectory+string(filepath.Separator))
gologger.Silent().Msgf("%s\n", path)
for _, tpl := range store.Templates() {
if hasExtraFlags(r.options) {
if r.options.TemplateDisplay {
colorize := !r.options.NoColor
path := tpl.Path
tplBody, err := ioutil.ReadFile(path)
if err != nil {
gologger.Error().Msgf("Could not read the template %s: %s", path, err)
continue
}
if colorize {
path = aurora.Cyan(tpl.Path).String()
tplBody, err = r.highlightTemplate(&tplBody)
if err != nil {
gologger.Error().Msgf("Could not hihglight the template %s: %s", tpl.Path, err)
continue
}
}
gologger.Silent().Msgf("Template: %s\n\n%s", path, tplBody)
} else {
gologger.Silent().Msgf("%s\n", strings.TrimPrefix(tpl.Path, r.templatesConfig.TemplatesDirectory+string(filepath.Separator)))
}
} else {
gologger.Print().Msgf("%s\n", templates.TemplateLogMessage(tl.ID,
types.ToString(tl.Info.Name),
tl.Info.Authors.ToSlice(),
tl.Info.SeverityHolder.Severity))
r.verboseTemplate(tpl)
}
}
}
func (r *Runner) highlightTemplate(body *[]byte) ([]byte, error) {
var buf bytes.Buffer
// YAML lexer, true color terminar formatter and monokai style
err := quick.Highlight(&buf, string(*body), "yaml", "terminal16m", "monokai")
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func hasExtraFlags(options *types.Options) bool {
return options.Templates != nil || options.Authors != nil ||
options.Tags != nil || len(options.ExcludeTags) > 3 ||
options.IncludeTags != nil || options.IncludeIds != nil ||
options.ExcludeIds != nil || options.IncludeTemplates != nil ||
options.ExcludedTemplates != nil || options.ExcludeMatchers != nil ||
options.Severities != nil || options.ExcludeSeverities != nil ||
options.Protocols != nil || options.ExcludeProtocols != nil ||
options.IncludeConditions != nil || options.TemplateList
}

View File

@ -25,8 +25,9 @@ import (
"golang.org/x/oauth2"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei-updatecheck-api/client"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/external/customtemplates"
client "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/updatecheck"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
fileutil "github.com/projectdiscovery/utils/file"
folderutil "github.com/projectdiscovery/utils/folder"
@ -37,12 +38,10 @@ import (
)
const (
userName = "projectdiscovery"
repoName = "nuclei-templates"
nucleiIgnoreFile = ".nuclei-ignore"
nucleiConfigFilename = ".templates-config.json"
customGithubTemplateDirectory = "github"
customS3TemplateDirectory = "s3"
userName = "projectdiscovery"
repoName = "nuclei-templates"
nucleiIgnoreFile = ".nuclei-ignore"
nucleiConfigFilename = ".templates-config.json"
)
var reVersion = regexp.MustCompile(`\d+\.\d+\.\d+`)
@ -105,11 +104,9 @@ func (r *Runner) updateTemplates() error { // TODO this method does more than ju
}
// download | update the custom templates repos
for _, ct := range *r.customTemplates {
if r.options.UpdateTemplates {
if r.options.UpdateTemplates {
for _, ct := range r.customTemplates {
ct.Update(r.templatesConfig.TemplatesDirectory, ctx)
} else {
ct.Download(r.templatesConfig.TemplatesDirectory, ctx)
}
}
@ -133,10 +130,13 @@ func (r *Runner) updateTemplates() error { // TODO this method does more than ju
// createDefaultConfig create template config file is template config is not found
func (r *Runner) createDefaultConfig(defaultTemplatesDirectory string) error {
if r.templatesConfig == nil {
// TODO remove customTemplate check in next version.
if r.templatesConfig == nil || r.templatesConfig.CustomGithubTemplatesDirectory == "" || r.templatesConfig.CustomS3TemplatesDirectory == "" {
currentConfig := &config.Config{
TemplatesDirectory: defaultTemplatesDirectory,
NucleiVersion: config.Version,
TemplatesDirectory: defaultTemplatesDirectory,
NucleiVersion: config.Version,
CustomS3TemplatesDirectory: filepath.Join(defaultTemplatesDirectory, customtemplates.CustomS3TemplateDirectory),
CustomGithubTemplatesDirectory: filepath.Join(defaultTemplatesDirectory, customtemplates.CustomGithubTemplateDirectory),
}
r.templatesConfig = currentConfig
if writeErr := config.WriteConfiguration(currentConfig); writeErr != nil {
@ -175,7 +175,7 @@ func (r *Runner) freshTemplateInstallation(configDir string, ctx context.Context
gologger.Info().Msgf("Successfully downloaded nuclei-templates (v%s) to %s. GoodLuck!\n", version.String(), r.templatesConfig.TemplatesDirectory)
// case where -gtr flag is passed for the first time installation
for _, ct := range *r.customTemplates {
for _, ct := range r.customTemplates {
ct.Download(r.templatesConfig.TemplatesDirectory, ctx)
}
return nil

View File

@ -16,9 +16,13 @@ import (
// Config contains the internal nuclei engine configuration
type Config struct {
TemplatesDirectory string `json:"nuclei-templates-directory,omitempty"`
TemplateVersion string `json:"nuclei-templates-version,omitempty"`
NucleiVersion string `json:"nuclei-version,omitempty"`
NucleiIgnoreHash string `json:"nuclei-ignore-hash,omitempty"`
CustomS3TemplatesDirectory string `json:"custom-s3-templates-directory"`
CustomGithubTemplatesDirectory string `json:"custom-github-templates-directory"`
TemplateVersion string `json:"nuclei-templates-version,omitempty"`
NucleiVersion string `json:"nuclei-version,omitempty"`
NucleiIgnoreHash string `json:"nuclei-ignore-hash,omitempty"`
NucleiLatestVersion string `json:"nuclei-latest-version"`
NucleiTemplatesLatestVersion string `json:"nuclei-templates-latest-version"`
@ -28,7 +32,7 @@ type Config struct {
const nucleiConfigFilename = ".templates-config.json"
// Version is the current version of nuclei
const Version = `2.7.8`
const Version = `2.8.1`
var customConfigDirectory string

View File

@ -2,6 +2,7 @@ package loader
import (
"os"
"sort"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
@ -291,6 +292,11 @@ func (store *Store) LoadTemplates(templatesList []string) []*templates.Template
gologger.Warning().Msgf("Could not load template %s: %s\n", templatePath, err)
}
}
sort.SliceStable(loadedTemplates, func(i, j int) bool {
return loadedTemplates[i].Path < loadedTemplates[j].Path
})
return loadedTemplates
}

View File

@ -31,6 +31,8 @@ type InputProvider interface {
// Scan iterates the input and each found item is passed to the
// callback consumer.
Scan(callback func(value *contextargs.MetaInput) bool)
// Set adds item to input provider
Set(value string)
}
// New returns a new Engine instance

View File

@ -19,10 +19,11 @@ import (
asn "github.com/projectdiscovery/mapcidr/asn"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/uncover"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
fileutil "github.com/projectdiscovery/utils/file"
iputil "github.com/projectdiscovery/utils/ip"
"github.com/projectdiscovery/utils/reader"
readerutil "github.com/projectdiscovery/utils/reader"
sliceutil "github.com/projectdiscovery/utils/slice"
)
@ -91,13 +92,13 @@ func (i *Input) initializeInputSources(options *types.Options) error {
case asn.IsASN(target):
i.expandASNInputValue(target)
default:
i.normalizeStoreInputValue(target)
i.Set(target)
}
}
// Handle stdin
if options.Stdin {
i.scanInputFromReader(reader.TimeoutReader{Reader: os.Stdin, Timeout: time.Duration(options.InputReadTimeout)})
i.scanInputFromReader(readerutil.TimeoutReader{Reader: os.Stdin, Timeout: time.Duration(options.InputReadTimeout)})
}
// Handle target file
@ -110,6 +111,16 @@ func (i *Input) initializeInputSources(options *types.Options) error {
i.scanInputFromReader(input)
}
if options.Uncover && options.UncoverQuery != nil {
gologger.Info().Msgf("Running uncover query against: %s", strings.Join(options.UncoverEngine, ","))
ch, err := uncover.GetTargetsFromUncover(options.UncoverDelay, options.UncoverLimit, options.UncoverField, options.UncoverEngine, options.UncoverQuery)
if err != nil {
return err
}
for c := range ch {
i.Set(c)
}
}
return nil
}
@ -124,43 +135,30 @@ func (i *Input) scanInputFromReader(reader io.Reader) {
case asn.IsASN(item):
i.expandASNInputValue(item)
default:
i.normalizeStoreInputValue(item)
i.Set(item)
}
}
}
// normalizeStoreInputValue normalizes and stores passed input values
func (i *Input) normalizeStoreInputValue(value string) {
// Set normalizes and stores passed input values
func (i *Input) Set(value string) {
URL := strings.TrimSpace(value)
if URL == "" {
return
}
metaInput := &contextargs.MetaInput{Input: URL}
keyURL, err := metaInput.MarshalString()
if err != nil {
gologger.Warning().Msgf("%s\n", err)
return
// actual hostname
var host string
// parse hostname if url is given
parsedURL, err := url.Parse(value)
if err == nil && parsedURL.Host != "" {
host = parsedURL.Host
} else {
parsedURL = nil
host = value
}
if _, ok := i.hostMap.Get(keyURL); ok {
i.dupeCount++
return
}
switch {
case i.ipOptions.ScanAllIPs:
// we need to resolve the hostname
// check if it's an url
var host string
parsedURL, err := url.Parse(value)
if err == nil && parsedURL.Host != "" {
host = parsedURL.Host
} else {
parsedURL = nil
host = value
}
if i.ipOptions.ScanAllIPs {
// scan all ips
dnsData, err := protocolstate.Dialer.GetDNSData(host)
if err == nil && (len(dnsData.A)+len(dnsData.AAAA)) > 0 {
var ips []string
@ -170,36 +168,63 @@ func (i *Input) normalizeStoreInputValue(value string) {
if i.ipOptions.IPV6 {
ips = append(ips, dnsData.AAAA...)
}
for _, ip := range ips {
if ip == "" {
continue
}
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
key, err := metaInput.MarshalString()
if err != nil {
gologger.Warning().Msgf("%s\n", err)
continue
}
_ = i.hostMap.Set(key, nil)
if i.hostMapStream != nil {
_ = i.hostMapStream.Set([]byte(key), nil)
}
i.setItem(metaInput)
}
break
return
}
fallthrough
default:
i.setItem(keyURL)
// failed to scanallips falling back to defaults
gologger.Error().Msgf("failed to scan all ips reverting to default %v", err)
}
ips := []string{}
// only scan the target but ipv6 if it has one
if i.ipOptions.IPV6 {
dnsData, err := protocolstate.Dialer.GetDNSData(host)
if err == nil && len(dnsData.AAAA) > 0 {
// pick/ prefer 1st
ips = append(ips, dnsData.AAAA[0])
} else {
gologger.Warning().Msgf("target does not have ipv6 address falling back to ipv4 %s\n", err)
}
}
if i.ipOptions.IPV4 {
// if IPV4 is enabled do not specify ip let dialer handle it
ips = append(ips, "")
}
for _, ip := range ips {
if ip != "" {
metaInput := &contextargs.MetaInput{Input: URL, CustomIP: ip}
i.setItem(metaInput)
} else {
metaInput := &contextargs.MetaInput{Input: URL}
i.setItem(metaInput)
}
}
}
// setItem in the kv store
func (i *Input) setItem(k string) {
i.inputCount++
_ = i.hostMap.Set(k, nil)
func (i *Input) setItem(metaInput *contextargs.MetaInput) {
key, err := metaInput.MarshalString()
if err != nil {
gologger.Warning().Msgf("%s\n", err)
return
}
if _, ok := i.hostMap.Get(key); ok {
i.dupeCount++
return
}
i.inputCount++ // tracks target count
_ = i.hostMap.Set(key, nil)
if i.hostMapStream != nil {
_ = i.hostMapStream.Set([]byte(k), nil)
_ = i.hostMapStream.Set([]byte(key), nil)
}
}

View File

@ -1,10 +1,13 @@
package hybrid
import (
"net"
"os"
"strconv"
"strings"
"testing"
"github.com/miekg/dns"
"github.com/projectdiscovery/hmap/store/hybrid"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
@ -46,8 +49,41 @@ func Test_expandCIDRInputValue(t *testing.T) {
}
}
type mockDnsHandler struct{}
func (this *mockDnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
msg := dns.Msg{}
msg.SetReply(r)
switch r.Question[0].Qtype {
case dns.TypeA:
msg.Authoritative = true
domain := msg.Question[0].Name
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: net.ParseIP("128.199.158.128"),
})
case dns.TypeAAAA:
msg.Authoritative = true
domain := msg.Question[0].Name
msg.Answer = append(msg.Answer, &dns.AAAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
AAAA: net.ParseIP("2400:6180:0:d0::91:1001"),
})
}
_ = w.WriteMsg(&msg)
}
func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
srv := &dns.Server{Addr: ":" + strconv.Itoa(61234), Net: "udp"}
srv.Handler = &mockDnsHandler{}
go func() {
err := srv.ListenAndServe()
require.Nil(t, err)
}()
defaultOpts := types.DefaultOptions()
defaultOpts.InternalResolversList = []string{"127.0.0.1:61234"}
_ = protocolstate.Init(defaultOpts)
tests := []struct {
hostname string
@ -87,7 +123,7 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
},
}
input.normalizeStoreInputValue(tt.hostname)
input.Set(tt.hostname)
// scan
got := []string{}
input.hostMap.Scan(func(k, v []byte) error {

View File

@ -19,3 +19,8 @@ func (s *SimpleInputProvider) Scan(callback func(value *contextargs.MetaInput) b
}
}
}
// Set adds item to input provider
func (s *SimpleInputProvider) Set(value string) {
s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: value})
}

View File

@ -24,7 +24,7 @@ type customTemplateGithubRepo struct {
// This function download the custom github template repository
func (customTemplate *customTemplateGithubRepo) Download(location string, ctx context.Context) {
downloadPath := filepath.Join(location, customGithubTemplateDirectory)
downloadPath := filepath.Join(location, CustomGithubTemplateDirectory)
clonePath := customTemplate.getLocalRepoClonePath(downloadPath)
if !fileutil.FolderExists(clonePath) {
@ -39,7 +39,7 @@ func (customTemplate *customTemplateGithubRepo) Download(location string, ctx co
}
func (customTemplate *customTemplateGithubRepo) Update(location string, ctx context.Context) {
downloadPath := filepath.Join(location, customGithubTemplateDirectory)
downloadPath := filepath.Join(location, CustomGithubTemplateDirectory)
clonePath := customTemplate.getLocalRepoClonePath(downloadPath)
// If folder does not exits then clone/download the repo

View File

@ -20,10 +20,10 @@ func TestDownloadCustomTemplatesFromGitHub(t *testing.T) {
options := testutils.DefaultOptions
options.GithubTemplateRepo = []string{"projectdiscovery/nuclei-templates", "ehsandeep/nuclei-templates"}
options.GithubToken = os.Getenv("GITHUB_TOKEN")
customTemplates := ParseCustomTemplates(options)
for _, ct := range *customTemplates {
for _, ct := range customTemplates {
ct.Download(templatesDirectory, context.Background())
}

View File

@ -11,17 +11,19 @@ import (
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/stringsutil"
)
type customTemplateS3Bucket struct {
s3Client *s3.Client
bucketName string
prefix string
Location string
}
// download custom templates from s3 bucket
func (bk *customTemplateS3Bucket) Download(location string, ctx context.Context) {
downloadPath := filepath.Join(location, customS3TemplateDirectory, bk.bucketName)
downloadPath := filepath.Join(location, CustomS3TemplateDirectory, bk.bucketName)
manager := manager.NewDownloader(bk.s3Client)
paginator := s3.NewListObjectsV2Paginator(bk.s3Client, &s3.ListObjectsV2Input{
@ -53,6 +55,10 @@ func (bk *customTemplateS3Bucket) Update(location string, ctx context.Context) {
func downloadToFile(downloader *manager.Downloader, targetDirectory, bucket, key string) error {
// Create the directories in the path
file := filepath.Join(targetDirectory, key)
// If empty dir in s3
if stringsutil.HasSuffixI(key, "/") {
return os.MkdirAll(file, 0775)
}
if err := os.MkdirAll(filepath.Dir(file), 0775); err != nil {
return err
}

View File

@ -9,23 +9,19 @@ import (
)
const (
customGithubTemplateDirectory = "github"
customS3TemplateDirectory = "s3"
CustomGithubTemplateDirectory = "github"
CustomS3TemplateDirectory = "s3"
)
type CustomTemplateProvider interface {
type Provider interface {
Download(location string, ctx context.Context)
Update(location string, ctx context.Context)
}
// parseCustomTemplates function reads the options.GithubTemplateRepo list,
// Checks the given repos are valid or not and stores them into runner.CustomTemplates
func ParseCustomTemplates(options *types.Options) *[]CustomTemplateProvider {
// do not sync templates in case of cloud
if options.Cloud {
return nil
}
var customTemplates []CustomTemplateProvider
func ParseCustomTemplates(options *types.Options) []Provider {
var customTemplates []Provider
gitHubClient := getGHClientIncognito()
for _, repoName := range options.GithubTemplateRepo {
@ -51,7 +47,7 @@ func ParseCustomTemplates(options *types.Options) *[]CustomTemplateProvider {
s3c, err := getS3Client(context.TODO(), options.AwsAccessKey, options.AwsSecretKey, options.AwsRegion)
if err != nil {
gologger.Error().Msgf("error downloading s3 bucket %s %s", options.AwsBucketName, err)
return &customTemplates
return customTemplates
}
ctBucket := &customTemplateS3Bucket{
bucketName: options.AwsBucketName,
@ -64,5 +60,5 @@ func ParseCustomTemplates(options *types.Options) *[]CustomTemplateProvider {
}
customTemplates = append(customTemplates, ctBucket)
}
return &customTemplates
return customTemplates
}

View File

@ -64,8 +64,9 @@ func (severity Severity) String() string {
return severityMappings[severity]
}
//nolint:exported,revive //prefer to be explicit about the name, and make it refactor-safe
// Holder holds a Severity type. Required for un/marshalling purposes
//
//nolint:exported,revive //prefer to be explicit about the name, and make it refactor-safe
type Holder struct {
Severity Severity `mapping:"true"`
}

View File

@ -52,12 +52,16 @@ func (stringSlice *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error)
result := make([]string, 0, len(marshalledSlice))
for _, value := range marshalledSlice {
result = append(result, strings.ToLower(strings.TrimSpace(value))) // TODO do we need to introduce RawStringSlice and/or NormalizedStringSlices?
result = append(result, stringSlice.normalize(value))
}
stringSlice.Value = result
return nil
}
func (stringSlice StringSlice) normalize(value string) string {
return strings.ToLower(strings.TrimSpace(value))
}
func (stringSlice StringSlice) MarshalYAML() (interface{}, error) {
return stringSlice.Value, nil
}
@ -82,7 +86,7 @@ func (stringSlice *StringSlice) UnmarshalJSON(data []byte) error {
switch {
case len(marshalledValuesAsSlice) > 0:
result = marshalledValuesAsSlice
case utils.IsNotBlank(marshalledValueAsString):
case !utils.IsBlank(marshalledValueAsString):
result = strings.Split(marshalledValueAsString, ",")
default:
result = []string{}
@ -90,7 +94,7 @@ func (stringSlice *StringSlice) UnmarshalJSON(data []byte) error {
values := make([]string, 0, len(result))
for _, value := range result {
values = append(values, strings.ToLower(strings.TrimSpace(value))) // TODO do we need to introduce RawStringSlice and/or NormalizedStringSlices?
values = append(values, stringSlice.normalize(value))
}
stringSlice.Value = values
return nil
@ -112,7 +116,7 @@ func marshalStringToSlice(unmarshal func(interface{}) error) ([]string, error) {
switch {
case len(marshalledValuesAsSlice) > 0:
result = marshalledValuesAsSlice
case utils.IsNotBlank(marshalledValueAsString):
case !utils.IsBlank(marshalledValueAsString):
result = strings.Split(marshalledValueAsString, ",")
default:
result = []string{}

View File

@ -62,7 +62,7 @@ var functionSignaturePattern = regexp.MustCompile(`(\w+)\s*\((?:([\w\d,\s]+)\s+(
var dateFormatRegex = regexp.MustCompile("%([A-Za-z])")
type dslFunction struct {
signature string
signatures []string
expressFunc govaluate.ExpressionFunction
}
@ -88,8 +88,10 @@ func init() {
"to_lower": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
return strings.ToLower(types.ToString(args[0])), nil
}),
"sort": makeDslWithOptionalArgsFunction(
"(args ...interface{}) interface{}",
"sort": makeMultiSignatureDslFunction([]string{
"(input string) string",
"(input number) string",
"(elements ...interface{}) []interface{}"},
func(args ...interface{}) (interface{}, error) {
argCount := len(args)
if argCount == 0 {
@ -110,8 +112,10 @@ func init() {
}
},
),
"uniq": makeDslWithOptionalArgsFunction(
"(args ...interface{}) interface{}",
"uniq": makeMultiSignatureDslFunction([]string{
"(input string) string",
"(input number) string",
"(elements ...interface{}) []interface{}"},
func(args ...interface{}) (interface{}, error) {
argCount := len(args)
if argCount == 0 {
@ -410,12 +414,40 @@ func init() {
return builder.String(), nil
},
),
"join": makeDslWithOptionalArgsFunction(
"split": makeMultiSignatureDslFunction([]string{
"(input string, n int) []string",
"(input string, separator string, optionalChunkSize) []string"},
func(arguments ...interface{}) (interface{}, error) {
argumentsSize := len(arguments)
if argumentsSize == 2 {
input := types.ToString(arguments[0])
separatorOrCount := types.ToString(arguments[1])
count, err := strconv.Atoi(separatorOrCount)
if err != nil {
return strings.SplitN(input, separatorOrCount, -1), nil
}
return toChunks(input, count), nil
} else if argumentsSize == 3 {
input := types.ToString(arguments[0])
separator := types.ToString(arguments[1])
count, err := strconv.Atoi(types.ToString(arguments[2]))
if err != nil {
return nil, invalidDslFunctionError
}
return strings.SplitN(input, separator, count), nil
} else {
return nil, invalidDslFunctionError
}
},
),
"join": makeMultiSignatureDslFunction([]string{
"(separator string, elements ...interface{}) string",
"(separator string, elements []interface{}) string"},
func(arguments ...interface{}) (interface{}, error) {
argumentsSize := len(arguments)
if argumentsSize < 2 {
return nil, errors.New("incorrect number of arguments received")
return nil, invalidDslFunctionError
} else if argumentsSize == 2 {
separator := types.ToString(arguments[0])
elements, ok := arguments[1].([]string)
@ -431,7 +463,6 @@ func init() {
stringElements := make([]string, 0, argumentsSize)
for _, element := range elements {
if _, ok := element.([]string); ok {
return nil, errors.New("cannot use join on more than one slice element")
}
@ -794,9 +825,18 @@ func init() {
}
func makeDslWithOptionalArgsFunction(signaturePart string, dslFunctionLogic govaluate.ExpressionFunction) func(functionName string) dslFunction {
return makeMultiSignatureDslFunction([]string{signaturePart}, dslFunctionLogic)
}
func makeMultiSignatureDslFunction(signatureParts []string, dslFunctionLogic govaluate.ExpressionFunction) func(functionName string) dslFunction {
return func(functionName string) dslFunction {
methodSignatures := make([]string, 0, len(signatureParts))
for _, signaturePart := range signatureParts {
methodSignatures = append(methodSignatures, functionName+signaturePart)
}
return dslFunction{
functionName + signaturePart,
methodSignatures,
dslFunctionLogic,
}
}
@ -806,7 +846,7 @@ func makeDslFunction(numberOfParameters int, dslFunctionLogic govaluate.Expressi
return func(functionName string) dslFunction {
signature := functionName + createSignaturePart(numberOfParameters)
return dslFunction{
signature,
[]string{signature},
func(args ...interface{}) (interface{}, error) {
if len(args) != numberOfParameters {
return nil, fmt.Errorf(invalidDslFunctionMessageTemplate, invalidDslFunctionError, signature)
@ -843,7 +883,7 @@ func helperFunctions() map[string]govaluate.ExpressionFunction {
func AddHelperFunction(key string, value func(args ...interface{}) (interface{}, error)) error {
if _, ok := dslFunctions[key]; !ok {
dslFunction := dslFunctions[key]
dslFunction.signature = "(args ...interface{}) interface{}"
dslFunction.signatures = []string{"(args ...interface{}) interface{}"}
dslFunction.expressFunc = value
return nil
}
@ -873,7 +913,7 @@ func getDslFunctionSignatures() []string {
result := make([]string, 0, len(dslFunctions))
for _, dslFunction := range dslFunctions {
result = append(result, dslFunction.signature)
result = append(result, dslFunction.signatures...)
}
return result
@ -1028,6 +1068,25 @@ func stringNumberToDecimal(args []interface{}, prefix string, base int) (interfa
return nil, fmt.Errorf("invalid number: %s", input)
}
func toChunks(input string, chunkSize int) []string {
if chunkSize <= 0 || chunkSize >= len(input) {
return []string{input}
}
var chunks = make([]string, 0, (len(input)-1)/chunkSize+1)
currentLength := 0
currentStart := 0
for i := range input {
if currentLength == chunkSize {
chunks = append(chunks, input[currentStart:i])
currentLength = 0
currentStart = i
}
currentLength++
}
chunks = append(chunks, input[currentStart:])
return chunks
}
type CompilationError struct {
DslSignature string
WrappedError error

View File

@ -4,7 +4,6 @@ import (
"fmt"
"math"
"regexp"
"strconv"
"testing"
"time"
@ -118,6 +117,7 @@ func TestGetPrintableDslFunctionSignatures(t *testing.T) {
html_escape(arg1 interface{}) interface{}
html_unescape(arg1 interface{}) interface{}
join(separator string, elements ...interface{}) string
join(separator string, elements []interface{}) string
len(arg1 interface{}) interface{}
line_ends_with(str string, suffix ...string) bool
line_starts_with(str string, prefix ...string) bool
@ -141,7 +141,11 @@ func TestGetPrintableDslFunctionSignatures(t *testing.T) {
sha1(arg1 interface{}) interface{}
sha256(arg1 interface{}) interface{}
sha512(arg1 interface{}) interface{}
sort(args ...interface{}) interface{}
sort(elements ...interface{}) []interface{}
sort(input number) string
sort(input string) string
split(input string, n int) []string
split(input string, separator string, optionalChunkSize) []string
starts_with(str string, prefix ...string) bool
substr(str string, start int, optionalEnd int)
to_lower(arg1 interface{}) interface{}
@ -155,7 +159,9 @@ func TestGetPrintableDslFunctionSignatures(t *testing.T) {
trim_right(arg1, arg2 interface{}) interface{}
trim_space(arg1 interface{}) interface{}
trim_suffix(arg1, arg2 interface{}) interface{}
uniq(args ...interface{}) interface{}
uniq(elements ...interface{}) []interface{}
uniq(input number) string
uniq(input string) string
unix_time(optionalSeconds uint) float64
url_decode(arg1 interface{}) interface{}
url_encode(arg1 interface{}) interface{}
@ -172,7 +178,6 @@ func TestGetPrintableDslFunctionSignatures(t *testing.T) {
}
func TestDslExpressions(t *testing.T) {
dslExpressions := map[string]interface{}{
`base64("Hello")`: "SGVsbG8=",
`base64(1234)`: "MTIzNA==",
@ -244,27 +249,27 @@ func TestDslExpressions(t *testing.T) {
`substr('xxtestxxx',2)`: "testxxx",
`substr('xxtestxxx',2,-2)`: "testx",
`substr('xxtestxxx',2,6)`: "test",
`sort(12453)`: "12345",
`sort("a1b2c3d4e5")`: "12345abcde",
`sort("b", "a", "2", "c", "3", "1", "d", "4")`: []string{"1", "2", "3", "4", "a", "b", "c", "d"},
`split("abcdefg", 2)`: []string{"ab", "cd", "ef", "g"},
`split("ab,cd,efg", ",", 1)`: []string{"ab,cd,efg"},
`split("ab,cd,efg", ",", 2)`: []string{"ab", "cd,efg"},
`split("ab,cd,efg", ",", "3")`: []string{"ab", "cd", "efg"},
`split("ab,cd,efg", ",", -1)`: []string{"ab", "cd", "efg"},
`split("ab,cd,efg", ",")`: []string{"ab", "cd", "efg"},
`join(" ", sort("b", "a", "2", "c", "3", "1", "d", "4"))`: "1 2 3 4 a b c d",
`uniq(123123231)`: "123",
`uniq("abcabdaabbccd")`: "abcd",
`uniq("ab", "cd", "12", "34", "12", "cd")`: []string{"ab", "cd", "12", "34"},
`join(" ", uniq("ab", "cd", "12", "34", "12", "cd"))`: "ab cd 12 34",
`join(", ", split(hex_encode("abcdefg"), 2))`: "61, 62, 63, 64, 65, 66, 67",
}
testDslExpressionScenarios(t, dslExpressions)
}
func Test(t *testing.T) {
if number, err := strconv.ParseInt("0o1234567", 0, 64); err == nil {
fmt.Println(number)
} else {
fmt.Println(err)
}
}
func TestDateTimeDSLFunction(t *testing.T) {
testDateTimeFormat := func(t *testing.T, dateTimeFormat string, dateTimeFunction *govaluate.EvaluableExpression, expectedFormattedTime string, currentUnixTime int64) {
dslFunctionParameters := map[string]interface{}{"dateTimeFormat": dateTimeFormat}
@ -302,7 +307,6 @@ func TestDateTimeDSLFunction(t *testing.T) {
}
func TestDateTimeDslExpressions(t *testing.T) {
t.Run("date_time", func(t *testing.T) {
now := time.Now()

View File

@ -38,7 +38,7 @@ var MatcherTypes = map[MatcherType]string{
DSLMatcher: "dsl",
}
//GetType returns the type of the matcher
// GetType returns the type of the matcher
func (matcher *Matcher) GetType() MatcherType {
return matcher.Type.MatcherType
}

View File

@ -3,6 +3,7 @@ package operators
import (
"fmt"
"strconv"
"strings"
"github.com/pkg/errors"
@ -91,6 +92,23 @@ type Result struct {
LineCount string
}
func (result *Result) HasMatch(name string) bool {
return result.hasItem(name, result.Matches)
}
func (result *Result) HasExtract(name string) bool {
return result.hasItem(name, result.Extracts)
}
func (result *Result) hasItem(name string, m map[string][]string) bool {
for matchName := range m {
if strings.EqualFold(name, matchName) {
return true
}
}
return false
}
// MakeDynamicValuesCallback takes an input dynamic values map and calls
// the callback function with all variations of the data in input in form
// of map[string]string (interface{}).

View File

@ -12,7 +12,7 @@ func (w *StandardWriter) formatScreen(output *ResultEvent) []byte {
builder := &bytes.Buffer{}
if !w.noMetadata {
if !w.noTimestamp {
if w.timestamp {
builder.WriteRune('[')
builder.WriteString(w.aurora.Cyan(output.Timestamp.Format("2006-01-02 15:04:05")).String())
builder.WriteString("] ")

View File

@ -46,7 +46,7 @@ type Writer interface {
type StandardWriter struct {
json bool
jsonReqResp bool
noTimestamp bool
timestamp bool
noMetadata bool
matcherStatus bool
mutex *sync.Mutex
@ -123,7 +123,7 @@ type ResultEvent struct {
}
// NewStandardWriter creates a new output writer based on user configurations
func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp, MatcherStatus, storeResponse bool, file, traceFile string, errorFile string, storeResponseDir string) (*StandardWriter, error) {
func NewStandardWriter(colors, noMetadata, timestamp, json, jsonReqResp, MatcherStatus, storeResponse bool, file, traceFile string, errorFile string, storeResponseDir string) (*StandardWriter, error) {
auroraColorizer := aurora.NewAurora(colors)
var outputFile io.WriteCloser
@ -161,7 +161,7 @@ func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp, Match
jsonReqResp: jsonReqResp,
noMetadata: noMetadata,
matcherStatus: MatcherStatus,
noTimestamp: noTimestamp,
timestamp: timestamp,
aurora: auroraColorizer,
mutex: &sync.Mutex{},
outputFile: outputFile,

View File

@ -7,7 +7,8 @@
// which are then used as tags for the execution of the templates.
//
// Example -
// "Amazon Web Services,Jenkins,Atlassian Jira" -> "amazon,web,services,jenkins,atlassian,jira".
//
// "Amazon Web Services,Jenkins,Atlassian Jira" -> "amazon,web,services,jenkins,atlassian,jira".
//
// Wappalyzergo (https://github.com/projectdiscovery/wappalyzergo) is used for wappalyzer tech
// detection.

View File

@ -16,7 +16,7 @@ type PayloadGenerator struct {
}
// New creates a new generator structure for payload generation
func New(payloads map[string]interface{}, attackType AttackType, templatePath string, catalog catalog.Catalog, customAttackType string) (*PayloadGenerator, error) {
func New(payloads map[string]interface{}, attackType AttackType, templatePath, templateDirectory string, sandbox bool, catalog catalog.Catalog, customAttackType string) (*PayloadGenerator, error) {
if attackType.String() == "" {
attackType = BatteringRamAttack
}
@ -42,7 +42,7 @@ func New(payloads map[string]interface{}, attackType AttackType, templatePath st
return nil, err
}
compiled, err := generator.loadPayloads(payloadsFinal)
compiled, err := generator.loadPayloads(payloadsFinal, templatePath, templateDirectory, sandbox)
if err != nil {
return nil, err
}

View File

@ -12,7 +12,7 @@ func TestBatteringRamGenerator(t *testing.T) {
usernames := []string{"admin", "password"}
catalogInstance := disk.NewCatalog("")
generator, err := New(map[string]interface{}{"username": usernames}, BatteringRamAttack, "", catalogInstance, "")
generator, err := New(map[string]interface{}{"username": usernames}, BatteringRamAttack, "", "", false, catalogInstance, "")
require.Nil(t, err, "could not create generator")
iterator := generator.NewIterator()
@ -32,7 +32,7 @@ func TestPitchforkGenerator(t *testing.T) {
passwords := []string{"password1", "password2", "password3"}
catalogInstance := disk.NewCatalog("")
generator, err := New(map[string]interface{}{"username": usernames, "password": passwords}, PitchForkAttack, "", catalogInstance, "")
generator, err := New(map[string]interface{}{"username": usernames, "password": passwords}, PitchForkAttack, "", "", false, catalogInstance, "")
require.Nil(t, err, "could not create generator")
iterator := generator.NewIterator()
@ -54,7 +54,7 @@ func TestClusterbombGenerator(t *testing.T) {
passwords := []string{"admin", "password", "token"}
catalogInstance := disk.NewCatalog("")
generator, err := New(map[string]interface{}{"username": usernames, "password": passwords}, ClusterBombAttack, "", catalogInstance, "")
generator, err := New(map[string]interface{}{"username": usernames, "password": passwords}, ClusterBombAttack, "", "", false, catalogInstance, "")
require.Nil(t, err, "could not create generator")
iterator := generator.NewIterator()

View File

@ -3,6 +3,7 @@ package generators
import (
"bufio"
"io"
"path/filepath"
"strings"
"github.com/pkg/errors"
@ -10,7 +11,7 @@ import (
)
// loadPayloads loads the input payloads from a map to a data map
func (generator *PayloadGenerator) loadPayloads(payloads map[string]interface{}) (map[string][]string, error) {
func (generator *PayloadGenerator) loadPayloads(payloads map[string]interface{}, templatePath, templateDirectory string, sandbox bool) (map[string][]string, error) {
loadedPayloads := make(map[string][]string)
for name, payload := range payloads {
@ -21,6 +22,13 @@ func (generator *PayloadGenerator) loadPayloads(payloads map[string]interface{})
if len(elements) >= 2 {
loadedPayloads[name] = elements
} else {
if sandbox {
pt = filepath.Clean(pt)
templatePathDir := filepath.Dir(templatePath)
if !(templatePathDir != "/" && strings.HasPrefix(pt, templatePathDir)) && !strings.HasPrefix(pt, templateDirectory) {
return nil, errors.New("denied payload file path specified")
}
}
payloads, err := generator.loadPayloadsFromFile(pt)
if err != nil {
return nil, errors.Wrap(err, "could not load payloads")

View File

@ -0,0 +1,61 @@
package generators
import (
"os"
"path/filepath"
"runtime"
"testing"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/disk"
"github.com/stretchr/testify/require"
)
func TestLoadPayloads(t *testing.T) {
tempdir, err := os.MkdirTemp("", "templates-*")
require.NoError(t, err, "could not create temp dir")
defer os.RemoveAll(tempdir)
generator := &PayloadGenerator{catalog: disk.NewCatalog(tempdir)}
fullpath := filepath.Join(tempdir, "payloads.txt")
err = os.WriteFile(fullpath, []byte("test\nanother"), 0777)
require.NoError(t, err, "could not write payload")
// Test sandbox
t.Run("templates-directory", func(t *testing.T) {
values, err := generator.loadPayloads(map[string]interface{}{
"new": fullpath,
}, "/test", tempdir, true)
require.NoError(t, err, "could not load payloads")
require.Equal(t, map[string][]string{"new": {"test", "another"}}, values, "could not get values")
})
t.Run("template-directory", func(t *testing.T) {
values, err := generator.loadPayloads(map[string]interface{}{
"new": fullpath,
}, filepath.Join(tempdir, "test.yaml"), "/test", true)
require.NoError(t, err, "could not load payloads")
require.Equal(t, map[string][]string{"new": {"test", "another"}}, values, "could not get values")
})
t.Run("no-sandbox-unix", func(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
_, err := generator.loadPayloads(map[string]interface{}{
"new": "/etc/passwd",
}, "/random", "/test", false)
require.NoError(t, err, "could load payloads")
})
t.Run("invalid", func(t *testing.T) {
values, err := generator.loadPayloads(map[string]interface{}{
"new": "/etc/passwd",
}, "/random", "/test", true)
require.Error(t, err, "could load payloads")
require.Equal(t, 0, len(values), "could get values")
values, err = generator.loadPayloads(map[string]interface{}{
"new": fullpath,
}, "/random", "/test", true)
require.Error(t, err, "could load payloads")
require.Equal(t, 0, len(values), "could get values")
})
}

View File

@ -127,7 +127,7 @@ func (c *Cache) MarkFailed(value string, err error) {
_ = c.failedTargets.Set(finalValue, numberOfErrorsValue+1)
}
var checkErrorRegexp = regexp.MustCompile(`(no address found for host|Client\.Timeout exceeded while awaiting headers|could not resolve host)`)
var checkErrorRegexp = regexp.MustCompile(`(no address found for host|Client\.Timeout exceeded while awaiting headers|could not resolve host|connection refused)`)
// checkError checks if an error represents a type that should be
// added to the host skipping table.

View File

@ -9,6 +9,7 @@ import (
"golang.org/x/net/proxy"
"github.com/projectdiscovery/fastdialer/fastdialer"
"github.com/projectdiscovery/networkpolicy"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
@ -90,6 +91,9 @@ func Init(options *types.Options) error {
if options.ResolversFile != "" {
opts.BaseResolvers = options.InternalResolversList
}
if options.Sandbox {
opts.Deny = append(networkpolicy.DefaultIPv4DenylistRanges, networkpolicy.DefaultIPv6DenylistRanges...)
}
opts.WithDialerHistory = true
opts.WithZTLS = options.ZTLS
opts.SNIName = options.SNI

View File

@ -0,0 +1,238 @@
package uncover
import (
"context"
"fmt"
"os"
"strings"
"sync"
"time"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/ratelimit"
ucRunner "github.com/projectdiscovery/uncover/runner"
"github.com/projectdiscovery/uncover/uncover"
"github.com/projectdiscovery/uncover/uncover/agent/censys"
"github.com/projectdiscovery/uncover/uncover/agent/fofa"
"github.com/projectdiscovery/uncover/uncover/agent/hunter"
"github.com/projectdiscovery/uncover/uncover/agent/netlas"
"github.com/projectdiscovery/uncover/uncover/agent/quake"
"github.com/projectdiscovery/uncover/uncover/agent/shodan"
"github.com/projectdiscovery/uncover/uncover/agent/shodanidb"
"github.com/projectdiscovery/uncover/uncover/agent/zoomeye"
mapsutil "github.com/projectdiscovery/utils/maps"
"github.com/remeh/sizedwaitgroup"
)
const maxConcurrentAgents = 50
func GetUncoverSupportedAgents() string {
uncoverSupportedAgents := []string{"shodan", "shodan-idb", "fofa", "censys", "quake", "hunter", "zoomeye", "netlas"}
return strings.Join(uncoverSupportedAgents, ",")
}
func GetTargetsFromUncover(delay, limit int, field string, engine, query []string) (chan string, error) {
uncoverOptions := &ucRunner.Options{
Provider: &ucRunner.Provider{},
Delay: delay,
Limit: limit,
Query: query,
Engine: engine,
}
for _, eng := range engine {
err := loadKeys(eng, uncoverOptions)
if err != nil {
gologger.Error().Label("WRN").Msgf(err.Error())
continue
}
}
return getTargets(uncoverOptions, field)
}
func GetUncoverTargetsFromMetadata(templates []*templates.Template, delay, limit int, field string) chan string {
ret := make(chan string)
var uqMap = make(map[string][]string)
var eng, query string
for _, template := range templates {
for k, v := range template.Info.Metadata {
switch k {
case "shodan-query":
eng = "shodan"
case "fofa-query":
eng = "fofa"
case "censys-query":
eng = "censys"
case "quake-query":
eng = "quake"
case "hunter-query":
eng = "hunter"
case "zoomeye-query":
eng = "zoomeye"
case "netlas-query":
eng = "netlas"
default:
continue
}
query = fmt.Sprintf("%v", v)
uqMap[eng] = append(uqMap[eng], query)
}
}
keys := mapsutil.GetKeys(uqMap)
gologger.Info().Msgf("Running uncover query against: %s", strings.Join(keys, ","))
var wg sync.WaitGroup
go func() {
for k, v := range uqMap {
wg.Add(1)
go func(engine, query []string) {
ch, _ := GetTargetsFromUncover(delay, limit, field, engine, query)
for c := range ch {
ret <- c
}
wg.Done()
}([]string{k}, v)
}
wg.Wait()
close(ret)
}()
return ret
}
func getTargets(uncoverOptions *ucRunner.Options, field string) (chan string, error) {
var rateLimiter *ratelimit.Limiter
// create rateLimiter for uncover delay
if uncoverOptions.Delay > 0 {
rateLimiter = ratelimit.New(context.Background(), 1, time.Duration(uncoverOptions.Delay))
} else {
rateLimiter = ratelimit.NewUnlimited(context.Background())
}
var agents []uncover.Agent
// declare clients
for _, engine := range uncoverOptions.Engine {
var (
agent uncover.Agent
err error
)
switch engine {
case "shodan":
agent, err = shodan.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "censys":
agent, err = censys.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "fofa":
agent, err = fofa.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "shodan-idb":
agent, err = shodanidb.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "quake":
agent, err = quake.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "hunter":
agent, err = hunter.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "zoomeye":
agent, err = zoomeye.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
case "netlas":
agent, err = netlas.NewWithOptions(&uncover.AgentOptions{RateLimiter: rateLimiter})
default:
err = errors.Errorf("%s unknown uncover agent type", engine)
}
if err != nil {
return nil, err
}
agents = append(agents, agent)
}
// enumerate
swg := sizedwaitgroup.New(maxConcurrentAgents)
ret := make(chan string)
go func() {
for _, q := range uncoverOptions.Query {
uncoverQuery := &uncover.Query{
Query: q,
Limit: uncoverOptions.Limit,
}
for _, agent := range agents {
swg.Add()
go func(agent uncover.Agent, uncoverQuery *uncover.Query) {
defer swg.Done()
keys := uncoverOptions.Provider.GetKeys()
session, err := uncover.NewSession(&keys, uncoverOptions.Retries, uncoverOptions.Timeout)
if err != nil {
gologger.Error().Label(agent.Name()).Msgf("couldn't create uncover new session: %s", err)
}
ch, err := agent.Query(session, uncoverQuery)
if err != nil {
gologger.Warning().Msgf("%s", err)
return
}
for result := range ch {
replacer := strings.NewReplacer(
"ip", result.IP,
"host", result.Host,
"port", fmt.Sprint(result.Port),
)
ret <- replacer.Replace(field)
}
}(agent, uncoverQuery)
}
}
swg.Wait()
close(ret)
}()
return ret, nil
}
func loadKeys(engine string, options *ucRunner.Options) error {
switch engine {
case "fofa":
if email, exists := os.LookupEnv("FOFA_EMAIL"); exists {
if key, exists := os.LookupEnv("FOFA_KEY"); exists {
options.Provider.Fofa = append(options.Provider.Fofa, fmt.Sprintf("%s:%s", email, key))
} else {
return errors.New("missing FOFA_KEY env variable")
}
} else {
return errors.Errorf("FOFA_EMAIL & FOFA_KEY env variables are not configured")
}
case "shodan":
if key, exists := os.LookupEnv("SHODAN_API_KEY"); exists {
options.Provider.Shodan = append(options.Provider.Shodan, key)
} else {
return errors.Errorf("SHODAN_API_KEY env variable is not configured")
}
case "censys":
if id, exists := os.LookupEnv("CENSYS_API_ID"); exists {
if secret, exists := os.LookupEnv("CENSYS_API_SECRET"); exists {
options.Provider.Censys = append(options.Provider.Censys, fmt.Sprintf("%s:%s", id, secret))
} else {
return errors.New("missing CENSYS_API_SECRET env variable")
}
} else {
return errors.Errorf("CENSYS_API_ID & CENSYS_API_SECRET env variable is not configured")
}
case "hunter":
if key, exists := os.LookupEnv("HUNTER_API_KEY"); exists {
options.Provider.Hunter = append(options.Provider.Hunter, key)
} else {
return errors.Errorf("HUNTER_API_KEY env variable is not configured")
}
case "zoomeye":
if key, exists := os.LookupEnv("ZOOMEYE_API_KEY"); exists {
options.Provider.ZoomEye = append(options.Provider.ZoomEye, key)
} else {
return errors.Errorf("ZOOMEYE_API_KEY env variable is not configured")
}
case "quake":
if key, exists := os.LookupEnv("QUAKE_TOKEN"); exists {
options.Provider.Quake = append(options.Provider.Quake, key)
} else {
return errors.Errorf("QUAKE_TOKEN env variable is not configured")
}
case "netlas":
if key, exists := os.LookupEnv("NETLAS_API_KEY"); exists {
options.Provider.Netlas = append(options.Provider.Netlas, key)
} else {
return errors.Errorf("NETLAS_API_KEY env variable is not configured")
}
default:
return errors.Errorf("unknown uncover agent")
}
return nil
}

View File

@ -0,0 +1,83 @@
package updatecheck
import (
"context"
"io"
"io/ioutil"
"net/http"
"net/url"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
)
const (
RegisterServer = "https://version-check.nuclei.sh/"
VersionsCall = "versions"
IgnoreCall = "ignore"
)
var nucleiVersion string
// LatestVersion is the latest version info for nuclei and templates repos
type LatestVersion struct {
Nuclei string
Templates string
IgnoreHash string
}
func InitNucleiVersion(version string) {
nucleiVersion = version
}
// GetLatestNucleiTemplatesVersion returns the latest version info for nuclei and templates repos
func GetLatestNucleiTemplatesVersion() (*LatestVersion, error) {
body, err := callRegisterServer(VersionsCall)
if err != nil {
return nil, err
}
defer body.Close()
data := make(map[string]string)
if err := jsoniter.NewDecoder(body).Decode(&data); err != nil {
return nil, err
}
return &LatestVersion{Nuclei: data["nuclei"], Templates: data["templates"], IgnoreHash: data["ignore-hash"]}, nil
}
// GetLatestIgnoreFile returns the latest version of nuclei ignore
func GetLatestIgnoreFile() ([]byte, error) {
body, err := callRegisterServer(IgnoreCall)
if err != nil {
return nil, err
}
defer body.Close()
data, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
return data, nil
}
// callRegisterServer makes a request to RegisterServer with a call.
func callRegisterServer(call string) (io.ReadCloser, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, RegisterServer+call, nil)
if err != nil {
return nil, errors.Wrap(err, "could not make request")
}
if nucleiVersion != "" {
query := make(url.Values, 1)
query.Set("v", nucleiVersion)
req.URL.RawQuery = query.Encode()
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "could not do request")
}
return resp.Body, nil
}

View File

@ -17,7 +17,7 @@ type ExcludeMatchers struct {
// <template-id>:<matcher-name> is the syntax. Wildcards can be specified
// using * character for either value.
//
// Ex- http-missing-security-headers:* skips all http-missing-security-header templates
// Ex- http-missing-security-headers:* skips all http-missing-security-header templates
func New(values []string) *ExcludeMatchers {
excludeMatchers := &ExcludeMatchers{
values: make(map[string]struct{}),

View File

@ -39,6 +39,7 @@ func newHttpClient(options *types.Options) (*http.Client, error) {
}
transport := &http.Transport{
ForceAttemptHTTP2: options.ForceAttemptHTTP2,
DialContext: dialer.Dial,
DialTLSContext: dialer.DialTLS,
MaxIdleConns: 500,

View File

@ -424,7 +424,7 @@ func (p *Page) SelectInputElement(act *Action, out map[string]string /*TODO revi
// WaitLoad waits for the page to load
func (p *Page) WaitLoad(act *Action, out map[string]string /*TODO review unused parameter*/) error {
p.page.Timeout(2 * time.Second).WaitNavigation(proto.PageLifecycleEventNameDOMContentLoaded)()
p.page.Timeout(2 * time.Second).WaitNavigation(proto.PageLifecycleEventNameFirstMeaningfulPaint)()
// Wait for the window.onload event and also wait for the network requests
// to become idle for a maximum duration of 3 seconds. If the requests

View File

@ -95,7 +95,7 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
if len(request.Payloads) > 0 {
var err error
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, options.TemplatePath, options.Catalog, options.Options.AttackType)
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, options.TemplatePath, options.Options.TemplatesDirectory, options.Options.Sandbox, options.Catalog, options.Options.AttackType)
if err != nil {
return errors.Wrap(err, "could not parse payloads")
}

View File

@ -10,7 +10,7 @@ import (
// are similar enough to be considered one and can be checked by
// just adding the matcher/extractors for the request and the correct IDs.
func (request *Request) CanCluster(other *Request) bool {
if len(request.Payloads) > 0 || len(request.Raw) > 0 || len(request.Body) > 0 || request.Unsafe || request.NeedsRequestCondition() || request.Name != "" {
if len(request.Payloads) > 0 || len(request.Fuzzing) > 0 || len(request.Raw) > 0 || len(request.Body) > 0 || request.Unsafe || request.NeedsRequestCondition() || request.Name != "" {
return false
}
if request.Method != other.Method ||

View File

@ -68,8 +68,6 @@ func (rule *Rule) buildQueryInput(input *ExecuteRuleInput, parsed url.URL, inter
return err
}
req.Header.Set("User-Agent", uarand.GetRandom())
req.Header.Set("Accept", "*/*")
req.Header.Set("Accept-Language", "en")
} else {
req = input.BaseRequest.Clone(context.Background())
req.URL = &parsed

View File

@ -350,7 +350,7 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
}
if len(request.Payloads) > 0 {
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, request.options.Catalog, request.options.Options.AttackType)
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, request.options.Options.TemplatesDirectory, request.options.Options.Sandbox, request.options.Catalog, request.options.Options.AttackType)
if err != nil {
return errors.Wrap(err, "could not parse payloads")
}

View File

@ -203,6 +203,7 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
}
transport := &http.Transport{
ForceAttemptHTTP2: options.ForceAttemptHTTP2,
DialContext: Dialer.Dial,
DialTLSContext: Dialer.DialTLS,
MaxIdleConns: maxIdleConns,
@ -211,6 +212,7 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
TLSClientConfig: tlsConfig,
DisableKeepAlives: disableKeepAlives,
}
if types.ProxyURL != "" {
if proxyURL, err := url.Parse(types.ProxyURL); err == nil {
transport.Proxy = http.ProxyURL(proxyURL)

View File

@ -755,26 +755,19 @@ func (request *Request) handleSignature(generatedRequest *generatedRequest) erro
case AWSSignature:
var awsSigner signer.Signer
vars := request.options.Options.Vars.AsMap()
awsAccessKeyId := types.ToString(vars["aws-id"])
awsSecretAccessKey := types.ToString(vars["aws-secret"])
awsSignerArgs := signer.AwsSignerArgs{AwsId: awsAccessKeyId, AwsSecretToken: awsSecretAccessKey}
service := types.ToString(generatedRequest.dynamicValues["service"])
region := types.ToString(generatedRequest.dynamicValues["region"])
// if region is empty use default value
if region == "" {
region = types.ToString(signer.AwsDefaultVars["region"])
}
awsSignatureArguments := signer.AwsSignatureArguments{
Service: types.ToString(service),
Region: types.ToString(region),
Time: time.Now(),
awsopts := signer.AWSOptions{
AwsID: types.ToString(vars["aws-id"]),
AwsSecretToken: types.ToString(vars["aws-secret"]),
}
// type ctxkey string
ctx := context.WithValue(context.Background(), signer.SignerArg("service"), generatedRequest.dynamicValues["service"])
ctx = context.WithValue(ctx, signer.SignerArg("region"), generatedRequest.dynamicValues["region"])
awsSigner, err := signerpool.Get(request.options.Options, &signerpool.Configuration{SignerArgs: awsSignerArgs})
awsSigner, err := signerpool.Get(request.options.Options, &signerpool.Configuration{SignerArgs: &awsopts})
if err != nil {
return err
}
err = awsSigner.SignHTTP(generatedRequest.request.Request, awsSignatureArguments)
err = awsSigner.SignHTTP(ctx, generatedRequest.request.Request)
if err != nil {
return err
}

View File

@ -34,7 +34,7 @@ func TestRequestGeneratorClusterBombSingle(t *testing.T) {
Raw: []string{`GET /{{username}}:{{password}} HTTP/1.1`},
}
catalogInstance := disk.NewCatalog("")
req.generator, err = generators.New(req.Payloads, req.AttackType.Value, "", catalogInstance, "")
req.generator, err = generators.New(req.Payloads, req.AttackType.Value, "", "", false, catalogInstance, "")
require.Nil(t, err, "could not create generator")
generator := req.newGenerator(false)
@ -58,7 +58,7 @@ func TestRequestGeneratorClusterBombMultipleRaw(t *testing.T) {
Raw: []string{`GET /{{username}}:{{password}} HTTP/1.1`, `GET /{{username}}@{{password}} HTTP/1.1`},
}
catalogInstance := disk.NewCatalog("")
req.generator, err = generators.New(req.Payloads, req.AttackType.Value, "", catalogInstance, "")
req.generator, err = generators.New(req.Payloads, req.AttackType.Value, "", "", false, catalogInstance, "")
require.Nil(t, err, "could not create generator")
generator := req.newGenerator(false)

View File

@ -0,0 +1,123 @@
package signer
import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"io"
"net/http"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
awsconfig "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
)
// AWSOptions
type AWSOptions struct {
AwsID string
AwsSecretToken string
Service string
Region string
}
// Validate Signature Arguments
func (a *AWSOptions) Validate() error {
if a.Service == "" {
return errors.New("aws service cannot be empty")
}
if a.Region == "" {
return errors.New("aws region cannot be empty")
}
return nil
}
// AWS v4 signer
type AWSSigner struct {
creds *aws.Credentials
signer *v4.Signer
options *AWSOptions
}
// SignHTTP
func (a *AWSSigner) SignHTTP(ctx context.Context, request *http.Request) error {
if region, ok := ctx.Value(SignerArg("region")).(string); ok && region != "" {
a.options.Region = region
}
if service, ok := ctx.Value(SignerArg("service")).(string); ok && service != "" {
a.options.Service = service
}
if err := a.options.Validate(); err != nil {
return err
}
return a.signer.SignHTTP(ctx, *a.creds, request, a.getPayloadHash(request), a.options.Service, a.options.Region, time.Now())
}
// getPayloadHash returns hex encoded SHA-256 of request body
func (a *AWSSigner) getPayloadHash(request *http.Request) string {
if request.Body == nil {
// Default Hash of Empty Payload
return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
// no need to close request body since it is a reusablereadercloser
bin, _ := io.ReadAll(request.Body)
sha256Hash := sha256.Sum256(bin)
return hex.EncodeToString(sha256Hash[:])
}
// NewAwsSigner
func NewAwsSigner(opts *AWSOptions) (*AWSSigner, error) {
credcache := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(opts.AwsID, opts.AwsSecretToken, ""))
awscred, err := credcache.Retrieve(context.TODO())
if err != nil {
return nil, err
}
return &AWSSigner{
creds: &awscred,
options: opts,
signer: v4.NewSigner(),
}, nil
}
// NewAwsSignerFromConfig
func NewAwsSignerFromConfig(opts *AWSOptions) (*AWSSigner, error) {
/*
NewAwsSignerFromConfig fetches credentials from both
1. Environment Variables (old & new)
2. Shared Credentials ($HOME/.aws)
*/
cfg, err := awsconfig.LoadDefaultConfig(context.TODO())
if err != nil {
return nil, err
}
credcache := aws.NewCredentialsCache(cfg.Credentials)
awscred, err := credcache.Retrieve(context.TODO())
if err != nil {
return nil, err
}
return &AWSSigner{
creds: &awscred,
options: opts,
signer: v4.NewSigner(func(signer *v4.SignerOptions) {
// signer.DisableURIPathEscaping = true
}),
}, nil
}
var AwsSkipList = map[string]interface{}{
"region": struct{}{},
}
var AwsDefaultVars = map[string]interface{}{
"region": "us-east-2",
}
var AwsInternalOnlyVars = map[string]interface{}{
"aws-id": struct{}{},
"aws-secret": struct{}{},
}

View File

@ -1,147 +0,0 @@
package signer
import (
"bytes"
"context"
"errors"
"io"
"net/http"
"time"
"github.com/aws/aws-sdk-go/aws/credentials"
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
)
type AwsSigner struct {
creds *credentials.Credentials
signer *v4.Signer
}
type AwsSignerArgs struct {
AwsId string
AwsSecretToken string
}
var credentialCreationError = errors.New("couldn't create the credentials structure")
func (awsSignerArgs AwsSignerArgs) Validate() error {
if awsSignerArgs.AwsId == "" {
return errors.New("empty id")
}
if awsSignerArgs.AwsSecretToken == "" {
return errors.New("empty token")
}
return nil
}
type AwsSignatureArguments struct {
Service string
Region string
Time time.Time
}
func (awsSignatureArguments AwsSignatureArguments) Validate() error {
if awsSignatureArguments.Region == "" {
return errors.New("empty region")
}
if awsSignatureArguments.Service == "" {
return errors.New("empty service")
}
return nil
}
func NewAwsSigner(args AwsSignerArgs) (*AwsSigner, error) {
if err := args.Validate(); err != nil {
return nil, err
}
creds := credentials.NewStaticCredentials(args.AwsId, args.AwsSecretToken, "")
if creds == nil {
return nil, credentialCreationError
}
signer := v4.NewSigner(creds)
return &AwsSigner{creds: creds, signer: signer}, nil
}
func NewAwsSignerFromEnv() (*AwsSigner, error) {
creds := credentials.NewEnvCredentials()
if creds == nil {
return nil, credentialCreationError
}
signer := v4.NewSigner(creds)
return &AwsSigner{creds: creds, signer: signer}, nil
}
func NewAwsSignerFromFile() (*AwsSigner, error) {
creds := credentials.NewSharedCredentials("", "")
if creds == nil {
return nil, credentialCreationError
}
signer := v4.NewSigner(creds)
return &AwsSigner{creds: creds, signer: signer}, nil
}
func (awsSigner *AwsSigner) SignHTTP(request *http.Request, args interface{}) error {
signatureArgs, err := awsSigner.checkSignatureArgs(args)
if err != nil {
return err
}
awsSigner.prepareRequest(request)
var body *bytes.Reader
if request.Body != nil {
bodyBytes, err := io.ReadAll(request.Body)
if err != nil {
return err
}
request.Body.Close()
body = bytes.NewReader(bodyBytes)
}
if _, err := awsSigner.signer.Sign(request, body, signatureArgs.Service, signatureArgs.Region, signatureArgs.Time); err != nil {
return err
}
return nil
}
func (awsSigner *AwsSigner) CalculateHTTPHeaders(request *http.Request, args interface{}) (map[string]string, error) {
signatureArgs, err := awsSigner.checkSignatureArgs(args)
if err != nil {
return nil, err
}
reqClone := request.Clone(context.Background())
awsSigner.prepareRequest(reqClone)
err = awsSigner.SignHTTP(reqClone, signatureArgs)
if err != nil {
return nil, err
}
headers := make(map[string]string)
headers["X-Amz-Date"] = reqClone.Header.Get("X-Amz-Date")
headers["Authorization"] = reqClone.Header.Get("Authorization")
return headers, nil
}
func (awsSigner *AwsSigner) checkSignatureArgs(args interface{}) (AwsSignatureArguments, error) {
if signatureArgs, ok := args.(AwsSignatureArguments); ok {
return signatureArgs, signatureArgs.Validate()
}
return AwsSignatureArguments{}, errors.New("wrong signature type")
}
func (awsSigner *AwsSigner) prepareRequest(request *http.Request) {
request.Header.Del("Host")
}
var AwsSkipList = map[string]interface{}{
"region": struct{}{},
}
var AwsDefaultVars = map[string]interface{}{
"region": "us-east-2",
}
var AwsInternalOnlyVars = map[string]interface{}{
"aws-id": struct{}{},
"aws-secret": struct{}{},
}

View File

@ -1,36 +1,30 @@
package signer
import (
"context"
"errors"
"net/http"
)
// An Argument that can be passed to Signer
type SignerArg string
type Signer interface {
SignHTTP(request *http.Request, args interface{}) error
CalculateHTTPHeaders(request *http.Request, args interface{}) (map[string]string, error)
SignHTTP(ctx context.Context, request *http.Request) error
}
type SignerArgs interface {
Validate() error
}
type SignatureArguments interface {
Validate() error
}
func NewSigner(args SignerArgs) (signer Signer, err error) {
switch signerArgs := args.(type) {
case AwsSignerArgs:
case *AWSOptions:
awsSigner, err := NewAwsSigner(signerArgs)
if err != nil {
// $HOME/.aws/credentials
awsSigner, err = NewAwsSignerFromFile()
awsSigner, err = NewAwsSignerFromConfig(signerArgs)
if err != nil {
// env variables
awsSigner, err = NewAwsSignerFromEnv()
if err != nil {
return nil, err
}
return nil, err
}
}
return awsSigner, err

View File

@ -184,7 +184,7 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
}
if len(request.Payloads) > 0 {
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, request.options.Catalog, request.options.Options.AttackType)
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, request.options.Options.TemplatesDirectory, request.options.Options.Sandbox, request.options.Catalog, request.options.Options.AttackType)
if err != nil {
return errors.Wrap(err, "could not parse payloads")
}

View File

@ -50,7 +50,7 @@ type Request struct {
// - "tls11"
// - "tls12"
// - "tls13"
MinVersion string `yaml:"min_version,omitempty" jsonschema:"title=TLS version,description=Minimum tls version - automatic if not specified.,enum=sslv3,enum=tls10,enum=tls11,enum=tls12,enum=tls13"`
MinVersion string `yaml:"min_version,omitempty" jsonschema:"title=Min. TLS version,description=Minimum tls version - automatic if not specified.,enum=sslv3,enum=tls10,enum=tls11,enum=tls12,enum=tls13"`
// description: |
// Max tls version - auto if not specified.
// values:
@ -59,10 +59,17 @@ type Request struct {
// - "tls11"
// - "tls12"
// - "tls13"
MaxVersion string `yaml:"max_version,omitempty" jsonschema:"title=TLS version,description=Max tls version - automatic if not specified.,enum=sslv3,enum=tls10,enum=tls11,enum=tls12,enum=tls13"`
MaxVersion string `yaml:"max_version,omitempty" jsonschema:"title=Max. TLS version,description=Max tls version - automatic if not specified.,enum=sslv3,enum=tls10,enum=tls11,enum=tls12,enum=tls13"`
// description: |
// Client Cipher Suites - auto if not specified.
CiperSuites []string `yaml:"cipher_suites,omitempty"`
// description: |
// Tls Scan Mode - auto if not specified
// values:
// - "ctls"
// - "ztls"
// - "auto"
ScanMode string `yaml:"scan_mode,omitempty" jsonschema:"title=Scan Mode,description=Scan Mode - auto if not specified.,enum=ctls,enum=ztls,enum=auto"`
// cache any variables that may be needed for operation.
dialer *fastdialer.Dialer
@ -93,9 +100,13 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
Retries: request.options.Options.Retries,
Timeout: request.options.Options.Timeout,
Fastdialer: client,
ClientHello: true,
ServerHello: true,
}
if options.Options.ZTLS {
tlsxOptions.ScanMode = "ztls"
} else if request.ScanMode != "" {
tlsxOptions.ScanMode = request.ScanMode
}
tlsxService, err := tlsx.New(tlsxOptions)
if err != nil {
@ -127,18 +138,18 @@ func (request *Request) GetID() string {
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
address, err := getAddress(input.MetaInput.Input)
hostPort, err := getAddress(input.MetaInput.Input)
if err != nil {
return nil
}
hostname, port, _ := net.SplitHostPort(address)
hostname, port, _ := net.SplitHostPort(hostPort)
requestOptions := request.options
payloadValues := make(map[string]interface{})
for k, v := range dynamicValues {
payloadValues[k] = v
}
payloadValues["Hostname"] = address
payloadValues["Hostname"] = hostPort
payloadValues["Host"] = hostname
payloadValues["Port"] = port
@ -163,15 +174,22 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
return errors.Wrap(err, "could not split input host port")
}
response, err := request.tlsx.Connect(host, host, port)
var hostIp string
if input.MetaInput.CustomIP != "" {
hostIp = input.MetaInput.CustomIP
} else {
hostIp = host
}
response, err := request.tlsx.Connect(host, hostIp, port)
if err != nil {
requestOptions.Output.Request(requestOptions.TemplateID, input.MetaInput.Input, request.Type().String(), err)
requestOptions.Progress.IncrementFailedRequestsBy(1)
return errors.Wrap(err, "could not connect to server")
}
requestOptions.Output.Request(requestOptions.TemplateID, address, request.Type().String(), err)
gologger.Verbose().Msgf("Sent SSL request to %s", address)
requestOptions.Output.Request(requestOptions.TemplateID, hostPort, request.Type().String(), err)
gologger.Verbose().Msgf("Sent SSL request to %s", hostPort)
if requestOptions.Options.Debug || requestOptions.Options.DebugRequests || requestOptions.Options.StoreResponse {
msg := fmt.Sprintf("[%s] Dumped SSL request for %s", requestOptions.TemplateID, input.MetaInput.Input)
@ -193,7 +211,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
data["host"] = input
data["matched"] = addressToDial
if input.MetaInput.CustomIP != "" {
data["ip"] = input.MetaInput.CustomIP
data["ip"] = hostIp
} else {
data["ip"] = request.dialer.GetDialedIP(hostname)
}

View File

@ -104,7 +104,7 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
request.dialer = client
if len(request.Payloads) > 0 {
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, options.Catalog, options.Options.AttackType)
request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, request.options.Options.TemplatesDirectory, request.options.Options.Sandbox, options.Catalog, options.Options.AttackType)
if err != nil {
return errors.Wrap(err, "could not parse payloads")
}

View File

@ -6,6 +6,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/corpix/uarand"
"io"
"net/http"
"time"
@ -112,6 +113,7 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
if len(exporter.authentication) > 0 {
req.Header.Add("Authorization", exporter.authentication)
}
req.Header.Set("User-Agent", uarand.GetRandom())
req.Header.Add("Content-Type", "application/json")
d := data{

View File

@ -1,28 +1,23 @@
package sarif
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"os"
"strings"
"path"
"sync"
"github.com/owenrumney/go-sarif/v2/sarif"
"github.com/pkg/errors"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/format"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
"github.com/projectdiscovery/sarif"
)
// Exporter is an exporter for nuclei sarif output format.
type Exporter struct {
sarif *sarif.Report
run *sarif.Run
mutex *sync.Mutex
home string
sarif *sarif.Report
mutex *sync.Mutex
rulemap map[string]*int // contains rule-id && ruleIndex
rules []sarif.ReportingDescriptor
options *Options
}
@ -34,106 +29,168 @@ type Options struct {
// New creates a new sarif exporter integration client based on options.
func New(options *Options) (*Exporter, error) {
report, err := sarif.New(sarif.Version210)
if err != nil {
return nil, errors.Wrap(err, "could not create sarif exporter")
report := sarif.NewReport()
exporter := &Exporter{
sarif: report,
mutex: &sync.Mutex{},
rules: []sarif.ReportingDescriptor{},
rulemap: map[string]*int{},
options: options,
}
return exporter, nil
}
// addToolDetails adds details of static analysis tool (i.e nuclei)
func (exporter *Exporter) addToolDetails() {
driver := sarif.ToolComponent{
Name: "Nuclei",
Organization: "ProjectDiscovery",
Product: "Nuclei",
ShortDescription: &sarif.MultiformatMessageString{
Text: "Fast and Customizable Vulnerability Scanner",
},
FullDescription: &sarif.MultiformatMessageString{
Text: "Fast and customizable vulnerability scanner based on simple YAML based DSL",
},
FullName: "Nuclei v" + config.Version,
SemanticVersion: "v" + config.Version,
DownloadURI: "https://github.com/projectdiscovery/nuclei/releases",
Rules: exporter.rules,
}
exporter.sarif.RegisterTool(driver)
reportloc := sarif.ArtifactLocation{
Uri: "file:///" + exporter.options.File,
Description: &sarif.Message{
Text: "Nuclei Sarif Report",
},
}
templatePath, err := utils.GetDefaultTemplatePath()
if err != nil {
return nil, errors.Wrap(err, "could not template path")
invocation := sarif.Invocation{
CommandLine: os.Args[0],
Arguments: os.Args[1:],
ResponseFiles: []sarif.ArtifactLocation{reportloc},
}
exporter.sarif.RegisterToolInvocation(invocation)
}
// getSeverity in terms of sarif
func (exporter *Exporter) getSeverity(severity string) (sarif.Level, string) {
switch severity {
case "critical":
return sarif.Error, "9.4"
case "high":
return sarif.Error, "8"
case "medium":
return sarif.Note, "5"
case "low":
return sarif.Note, "2"
case "info":
return sarif.None, "1"
}
run := sarif.NewRunWithInformationURI("nuclei", "https://github.com/projectdiscovery/nuclei")
return &Exporter{options: options, home: templatePath, sarif: report, run: run, mutex: &sync.Mutex{}}, nil
return sarif.None, "9.5"
}
// Export exports a passed result event to sarif structure
func (exporter *Exporter) Export(event *output.ResultEvent) error {
templatePath := strings.TrimPrefix(event.TemplatePath, exporter.home)
h := sha1.New()
_, _ = h.Write([]byte(event.Host))
templateID := event.TemplateID + "-" + hex.EncodeToString(h.Sum(nil))
var ruleName string
if utils.IsNotBlank(event.Info.Name) {
ruleName = event.Info.Name
}
var templateURL string
if strings.HasPrefix(event.TemplatePath, exporter.home) {
templateURL = "https://github.com/projectdiscovery/nuclei-templates/blob/master" + templatePath
} else {
templateURL = "https://github.com/projectdiscovery/nuclei-templates"
}
var ruleDescription string
if utils.IsNotBlank(event.Info.Description) {
ruleDescription = event.Info.Description
}
exporter.mutex.Lock()
defer exporter.mutex.Unlock()
_ = exporter.run.AddRule(templateID).
WithDescription(ruleName).
WithHelp(sarif.NewMarkdownMultiformatMessageString(format.MarkdownDescription(event))).
WithHelpURI(templateURL).
WithFullDescription(sarif.NewMultiformatMessageString(ruleDescription))
severity := event.Info.SeverityHolder.Severity.String()
resultHeader := fmt.Sprintf("%v (%v) found on %v", event.Info.Name, event.TemplateID, event.Host)
resultLevel, vulnRating := exporter.getSeverity(severity)
result := sarif.NewRuleResult(templateID).
WithMessage(sarif.NewTextMessage(event.Host)).
WithLevel(getSarifSeverity(event))
// Extra metdata if generated sarif is uploaded to github security page
ghmeta := map[string]interface{}{}
ghmeta["tags"] = []string{"security"}
ghmeta["security-severity"] = vulnRating
exporter.run.AddResult(result)
// rule contain details of template
rule := sarif.ReportingDescriptor{
Id: event.TemplateID,
Name: event.Info.Name,
FullDescription: &sarif.MultiformatMessageString{
// Points to template URL
Text: event.Info.Description + "\nMore details at\n" + event.TemplateURL + "\n",
},
Properties: ghmeta,
}
// Also write file match metadata to file
if event.Type == "file" && (event.FileToIndexPosition != nil && len(event.FileToIndexPosition) > 0) {
for file, line := range event.FileToIndexPosition {
result.AddLocation(sarif.NewLocation().WithMessage(sarif.NewMessage().WithText(ruleName)).WithPhysicalLocation(
sarif.NewPhysicalLocation().
WithArtifactLocation(sarif.NewArtifactLocation().WithUri(file)).
WithRegion(sarif.NewRegion().WithStartColumn(1).WithStartLine(line).WithEndLine(line).WithEndColumn(32)),
))
// Github Uses ShortDescription as title
if event.Info.Description != "" {
rule.ShortDescription = &sarif.MultiformatMessageString{
Text: resultHeader,
}
}
// If rule is added
ruleIndex := len(exporter.rules) - 1
if exporter.rulemap[rule.Id] == nil {
exporter.rulemap[rule.Id] = &ruleIndex
exporter.rules = append(exporter.rules, rule)
} else {
result.AddLocation(sarif.NewLocation().WithMessage(sarif.NewMessage().WithText(event.Host)).WithPhysicalLocation(
sarif.NewPhysicalLocation().
WithArtifactLocation(sarif.NewArtifactLocation().WithUri("README.md")).
WithRegion(sarif.NewRegion().WithStartColumn(1).WithStartLine(1).WithEndLine(1).WithEndColumn(1)),
))
ruleIndex = *exporter.rulemap[rule.Id]
}
// vulnerability target/location
location := sarif.Location{
Message: &sarif.Message{
Text: path.Join(event.Host, event.Path),
},
PhysicalLocation: sarif.PhysicalLocation{
ArtifactLocation: sarif.ArtifactLocation{
// github only accepts file:// protocol and local & relative files only
// to avoid errors // is used which also translates to file according to specification
Uri: "/" + event.Path,
Description: &sarif.Message{
Text: path.Join(event.Host, event.Path),
},
},
},
}
// vulnerability report/result
result := &sarif.Result{
RuleId: rule.Id,
RuleIndex: ruleIndex,
Level: resultLevel,
Kind: sarif.Open,
Message: &sarif.Message{
Text: resultHeader,
},
Locations: []sarif.Location{location},
Rule: sarif.ReportingDescriptorReference{
Id: rule.Id,
},
}
exporter.sarif.RegisterResult(*result)
return nil
}
// getSarifSeverity returns the sarif severity
func getSarifSeverity(event *output.ResultEvent) string {
switch event.Info.SeverityHolder.Severity {
case severity.Info:
return "note"
case severity.Low, severity.Medium:
return "warning"
case severity.High, severity.Critical:
return "error"
default:
return "note"
}
}
// Close closes the exporter after operation
// Close Writes data and closes the exporter after operation
func (exporter *Exporter) Close() error {
exporter.mutex.Lock()
defer exporter.mutex.Unlock()
exporter.sarif.AddRun(exporter.run)
if len(exporter.run.Results) == 0 {
return nil // do not write when no results
if len(exporter.rules) == 0 {
// no output if there are no results
return nil
}
file, err := os.Create(exporter.options.File)
// links results and rules/templates
exporter.addToolDetails()
bin, err := exporter.sarif.Export()
if err != nil {
return errors.Wrap(err, "could not create sarif output file")
return errors.Wrap(err, "failed to generate sarif report")
}
defer file.Close()
return exporter.sarif.Write(file)
if err := os.WriteFile(exporter.options.File, bin, 0644); err != nil {
return errors.Wrap(err, "failed to create sarif file")
}
return nil
}

View File

@ -14,7 +14,6 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
// Summary returns a formatted built one line summary of the event
func Summary(event *output.ResultEvent) string {
template := GetMatchedTemplate(event)
@ -179,7 +178,7 @@ func ToMarkdownTableString(templateInfo *model.Info) string {
insertionOrderedStringMap.ForEach(func(key string, value interface{}) {
switch value := value.(type) {
case string:
if utils.IsNotBlank(value) {
if !utils.IsBlank(value) {
builder.WriteString(fmt.Sprintf("| %s | %s |\n", key, value))
}
}

View File

@ -1717,7 +1717,7 @@ func init() {
Value: "Matched is the input which was matched upon",
},
}
SSLRequestDoc.Fields = make([]encoder.Doc, 7)
SSLRequestDoc.Fields = make([]encoder.Doc, 8)
SSLRequestDoc.Fields[0].Name = "matchers"
SSLRequestDoc.Fields[0].Type = "[]matchers.Matcher"
SSLRequestDoc.Fields[0].Note = ""
@ -1771,6 +1771,16 @@ func init() {
SSLRequestDoc.Fields[6].Note = ""
SSLRequestDoc.Fields[6].Description = "Client Cipher Suites - auto if not specified."
SSLRequestDoc.Fields[6].Comments[encoder.LineComment] = "Client Cipher Suites - auto if not specified."
SSLRequestDoc.Fields[7].Name = "scan_mode"
SSLRequestDoc.Fields[7].Type = "string"
SSLRequestDoc.Fields[7].Note = ""
SSLRequestDoc.Fields[7].Description = "Tls Scan Mode - auto if not specified"
SSLRequestDoc.Fields[7].Comments[encoder.LineComment] = "Tls Scan Mode - auto if not specified"
SSLRequestDoc.Fields[7].Values = []string{
"ctls",
"ztls",
"auto",
}
WEBSOCKETRequestDoc.Type = "websocket.Request"
WEBSOCKETRequestDoc.Comments[encoder.LineComment] = " Request is a request for the Websocket protocol"

View File

@ -1,5 +1,5 @@
// Package templates
//nolint //do not lint as examples with no usage
// nolint //do not lint as examples with no usage
package templates
import (

View File

@ -91,7 +91,7 @@ func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protoco
IssuesClient: nil,
Browser: nil,
Catalog: disk.NewCatalog(options.TemplatesDirectory),
RateLimiter: ratelimit.New(context.Background(), options.RateLimit, time.Second),
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
}
return executerOpts
}

View File

@ -167,6 +167,8 @@ type Options struct {
// using same matchers/extractors from http protocol without the need
// to send a new request, reading responses from a file.
OfflineHTTP bool
// Force HTTP2 requests
ForceAttemptHTTP2 bool
// StatsJSON writes stats output in JSON format
StatsJSON bool
// Headless specifies whether to allow headless mode templates
@ -220,6 +222,8 @@ type Options struct {
EnableProgressBar bool
// TemplatesVersion shows the templates installed version
TemplatesVersion bool
// TemplateDisplay displays the template contents
TemplateDisplay bool
// TemplateList lists available templates
TemplateList bool
// HangMonitor enables nuclei hang monitoring
@ -232,8 +236,8 @@ type Options struct {
Stream bool
// NoMeta disables display of metadata for the matches
NoMeta bool
// NoTimestamp disables display of timestamp for the matcher
NoTimestamp bool
// Timestamp enables display of timestamp for the matcher
Timestamp bool
// Project is used to avoid sending same HTTP request multiple times
Project bool
// NewTemplates only runs newly added templates from the repository
@ -258,6 +262,8 @@ type Options struct {
ClientCAFile string
// Use ZTLS library
ZTLS bool
// Sandbox enables sandboxed nuclei template execution
Sandbox bool
// ShowMatchLine enables display of match line number
ShowMatchLine bool
// EnablePprof enables exposing pprof runtime information with a webserver.
@ -290,6 +296,18 @@ type Options struct {
IncludeConditions goflags.StringSlice
// Custom Config Directory
CustomConfigDir string
// Enable uncover egine
Uncover bool
// Uncover search query
UncoverQuery goflags.StringSlice
// Uncover search engine
UncoverEngine goflags.StringSlice
// Uncover search field
UncoverField string
// Uncover search limit
UncoverLimit int
// Uncover search delay
UncoverDelay int
// ConfigPath contains the config path (used by healthcheck)
ConfigPath string
// ScanAllIPs associated to a dns record
@ -299,7 +317,7 @@ type Options struct {
// Github token used to clone/pull from private repos for custom templates
GithubToken string
// GithubTemplateRepo is the list of custom public/private templates github repos
GithubTemplateRepo goflags.StringSlice
GithubTemplateRepo []string
// AWS access key for downloading templates from s3 bucket
AwsAccessKey string
// AWS secret key for downloading templates from s3 bucket

View File

@ -14,10 +14,6 @@ func IsBlank(value string) bool {
return strings.TrimSpace(value) == ""
}
func IsNotBlank(value string) bool {
return !IsBlank(value)
}
func UnwrapError(err error) error {
for { // get the last wrapped error
unwrapped := errors.Unwrap(err)

View File

@ -105,8 +105,8 @@ func (matcher *Matcher) Match(result *operators.Result) bool {
}
for i, name := range names {
_, matchOK := result.Matches[name]
_, extractOK := result.Extracts[name]
matchOK := result.HasMatch(name)
extractOK := result.HasExtract(name)
if !matchOK && !extractOK {
if matcher.condition == ANDCondition {