mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-23 06:55:29 +00:00
commit
a31bca524d
8
.github/workflows/dockerhub-push.yml
vendored
8
.github/workflows/dockerhub-push.yml
vendored
@ -20,19 +20,19 @@ jobs:
|
||||
echo "::set-output name=tag::$(curl --silent "https://api.github.com/repos/projectdiscovery/nuclei/releases/latest" | jq -r .tag_name)"
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
2
.github/workflows/lint-test.yml
vendored
2
.github/workflows/lint-test.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3.1.0
|
||||
uses: golangci/golangci-lint-action@v3.2.0
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout 5m
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM golang:1.18.1-alpine as build-env
|
||||
FROM golang:1.18.2-alpine as build-env
|
||||
RUN go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
|
||||
|
||||
FROM alpine:3.15.4
|
||||
|
||||
13
README.md
13
README.md
@ -84,7 +84,7 @@ nuclei -h
|
||||
This will display help for the tool. Here are all the switches it supports.
|
||||
|
||||
|
||||
```yaml
|
||||
```console
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
@ -123,8 +123,8 @@ FILTERING:
|
||||
|
||||
OUTPUT:
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-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")
|
||||
-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
|
||||
@ -133,6 +133,8 @@ OUTPUT:
|
||||
-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
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string path to the nuclei configuration file
|
||||
@ -149,7 +151,8 @@ CONFIGURATIONS:
|
||||
-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
|
||||
-ztls Use ztls library with autofallback to standard one for tls13
|
||||
-ztls use ztls library with autofallback to standard one for tls13
|
||||
-sni string tls sni hostname to use (default: input domain name)
|
||||
|
||||
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)
|
||||
@ -188,8 +191,6 @@ DEBUG:
|
||||
-debug display all requests and responses
|
||||
-dreq, -debug-req display all sent requests
|
||||
-dresp, -debug-resp display all received responses
|
||||
-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")
|
||||
-p, -proxy string[] list of http/socks5 proxy to use (comma separated or file input)
|
||||
-pi, -proxy-internal proxy all internal requests
|
||||
-tlog, -trace-log string file to write sent requests trace log
|
||||
|
||||
18
integration_tests/http/get-override-sni.yaml
Normal file
18
integration_tests/http/get-override-sni.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
id: basic-raw-http-example
|
||||
|
||||
info:
|
||||
name: Test RAW GET Template
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- raw:
|
||||
- |
|
||||
@tls-sni:request.host
|
||||
GET / HTTP/1.1
|
||||
Host: test
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "test-ok"
|
||||
15
integration_tests/http/get-sni.yaml
Normal file
15
integration_tests/http/get-sni.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
id: basic-get
|
||||
|
||||
info:
|
||||
name: Basic GET Request with CLI SNI
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "test-ok"
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -10,10 +11,17 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/nvd"
|
||||
"github.com/projectdiscovery/sliceutil"
|
||||
"github.com/projectdiscovery/stringsutil"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
||||
)
|
||||
|
||||
const (
|
||||
yamlIndentSpaces = 2
|
||||
)
|
||||
|
||||
var (
|
||||
input = flag.String("i", "", "Templates to annotate")
|
||||
templateDir = flag.String("d", "", "Custom template directory for update")
|
||||
@ -63,6 +71,8 @@ var (
|
||||
severityRegex = regexp.MustCompile(`severity: ([a-z]+)`)
|
||||
)
|
||||
|
||||
const maxReferenceCount = 5
|
||||
|
||||
func getCVEData(client *nvd.Client, filePath, data string) {
|
||||
matches := idRegex.FindAllStringSubmatch(data, 1)
|
||||
if len(matches) == 0 {
|
||||
@ -76,10 +86,6 @@ func getCVEData(client *nvd.Client, filePath, data string) {
|
||||
}
|
||||
severityValue := severityMatches[0][1]
|
||||
|
||||
// Skip if there's classification data already
|
||||
if strings.Contains(data, "classification:") {
|
||||
return
|
||||
}
|
||||
cveItem, err := client.FetchCVE(cveName)
|
||||
if err != nil {
|
||||
log.Printf("Could not fetch cve %s: %s\n", cveName, err)
|
||||
@ -98,43 +104,84 @@ func getCVEData(client *nvd.Client, filePath, data string) {
|
||||
infoBlockIndexData := data[strings.Index(data, "info:"):]
|
||||
requestsIndex := strings.Index(infoBlockIndexData, "requests:")
|
||||
networkIndex := strings.Index(infoBlockIndexData, "network:")
|
||||
if requestsIndex == -1 && networkIndex == -1 {
|
||||
variablesIndex := strings.Index(infoBlockIndexData, "variables:")
|
||||
if requestsIndex == -1 && networkIndex == -1 && variablesIndex == -1 {
|
||||
return
|
||||
}
|
||||
if networkIndex != -1 {
|
||||
requestsIndex = networkIndex
|
||||
}
|
||||
if variablesIndex != -1 {
|
||||
requestsIndex = variablesIndex
|
||||
}
|
||||
infoBlockData := infoBlockIndexData[:requestsIndex]
|
||||
infoBlockClean := strings.TrimRight(infoBlockData, "\n")
|
||||
|
||||
newInfoBlock := infoBlockClean
|
||||
var changed bool
|
||||
infoBlock := InfoBlock{}
|
||||
err = yaml.Unmarshal([]byte(data), &infoBlock)
|
||||
if err != nil {
|
||||
log.Printf("Could not unmarshal info block: %s\n", err)
|
||||
}
|
||||
|
||||
var changed bool
|
||||
if newSeverity := isSeverityMatchingCvssScore(severityValue, cvssScore); newSeverity != "" {
|
||||
changed = true
|
||||
newInfoBlock = strings.ReplaceAll(newInfoBlock, severityMatches[0][0], "severity: "+newSeverity)
|
||||
infoBlock.Info.Severity = newSeverity
|
||||
fmt.Printf("Adjusting severity for %s from %s=>%s (%.2f)\n", filePath, severityValue, newSeverity, cvssScore)
|
||||
}
|
||||
if !strings.Contains(infoBlockClean, "classification") && (cvssScore != 0 && cvssMetrics != "") {
|
||||
isCvssEmpty := cvssScore == 0 || cvssMetrics == ""
|
||||
hasCvssChanged := infoBlock.Info.Classification.CvssScore != cvssScore || cvssMetrics != infoBlock.Info.Classification.CvssMetrics
|
||||
if !isCvssEmpty && hasCvssChanged {
|
||||
changed = true
|
||||
newInfoBlock += fmt.Sprintf("\n classification:\n cvss-metrics: %s\n cvss-score: %.2f\n cve-id: %s", cvssMetrics, cvssScore, cveName)
|
||||
infoBlock.Info.Classification.CvssMetrics = cvssMetrics
|
||||
infoBlock.Info.Classification.CvssScore = cvssScore
|
||||
infoBlock.Info.Classification.CveId = cveName
|
||||
if len(cweID) > 0 && (cweID[0] != "NVD-CWE-Other" && cweID[0] != "NVD-CWE-noinfo") {
|
||||
newInfoBlock += fmt.Sprintf("\n cwe-id: %s", strings.Join(cweID, ","))
|
||||
infoBlock.Info.Classification.CweId = strings.Join(cweID, ",")
|
||||
}
|
||||
}
|
||||
// If there is no description field, fill the description from CVE information
|
||||
if !strings.Contains(infoBlockClean, "description:") && len(cveItem.CVE.Description.DescriptionData) > 0 {
|
||||
hasDescriptionData := len(cveItem.CVE.Description.DescriptionData) > 0
|
||||
isDescriptionEmpty := infoBlock.Info.Description == ""
|
||||
if isDescriptionEmpty && hasDescriptionData {
|
||||
changed = true
|
||||
newInfoBlock += fmt.Sprintf("\n description: %s", fmt.Sprintf("%q", cveItem.CVE.Description.DescriptionData[0].Value))
|
||||
// removes all new lines
|
||||
description := stringsutil.ReplaceAny(cveItem.CVE.Description.DescriptionData[0].Value, "", "\n", "\\", "'", "\t")
|
||||
description += "\n"
|
||||
infoBlock.Info.Description = description
|
||||
}
|
||||
if !strings.Contains(infoBlockClean, "reference:") && len(cveItem.CVE.References.ReferenceData) > 0 {
|
||||
|
||||
// we are unmarshaling info block to have valid data
|
||||
var referenceDataURLs []string
|
||||
for _, reference := range cveItem.CVE.References.ReferenceData {
|
||||
referenceDataURLs = append(referenceDataURLs, reference.URL)
|
||||
}
|
||||
hasReferenceData := len(cveItem.CVE.References.ReferenceData) > 0
|
||||
areCveReferencesContained := sliceutil.ContainsItems(infoBlock.Info.Reference, referenceDataURLs)
|
||||
referencesCount := len(infoBlock.Info.Reference)
|
||||
if hasReferenceData && !areCveReferencesContained {
|
||||
changed = true
|
||||
newInfoBlock += "\n reference:"
|
||||
for _, reference := range cveItem.CVE.References.ReferenceData {
|
||||
newInfoBlock += fmt.Sprintf("\n - %s", reference.URL)
|
||||
referencesCount++
|
||||
if referencesCount >= maxReferenceCount {
|
||||
break
|
||||
}
|
||||
infoBlock.Info.Reference = append(infoBlock.Info.Reference, reference.URL)
|
||||
}
|
||||
infoBlock.Info.Reference = sliceutil.PruneEmptyStrings(sliceutil.Dedupe(infoBlock.Info.Reference))
|
||||
}
|
||||
newTemplate := strings.ReplaceAll(data, infoBlockClean, newInfoBlock)
|
||||
|
||||
var newInfoBlock bytes.Buffer
|
||||
yamlEncoder := yaml.NewEncoder(&newInfoBlock)
|
||||
yamlEncoder.SetIndent(yamlIndentSpaces)
|
||||
err = yamlEncoder.Encode(infoBlock)
|
||||
if err != nil {
|
||||
log.Printf("Could not marshal info block: %s\n", err)
|
||||
return
|
||||
}
|
||||
newInfoBlockData := strings.TrimSuffix(newInfoBlock.String(), "\n")
|
||||
|
||||
newTemplate := strings.ReplaceAll(data, infoBlockClean, newInfoBlockData)
|
||||
if changed {
|
||||
_ = ioutil.WriteFile(filePath, []byte(newTemplate), 0644)
|
||||
fmt.Printf("Wrote updated template to %s\n", filePath)
|
||||
@ -161,3 +208,27 @@ func isSeverityMatchingCvssScore(severity string, score float64) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Cloning struct from nuclei as we don't want any validation
|
||||
type InfoBlock struct {
|
||||
Info TemplateInfo `yaml:"info"`
|
||||
}
|
||||
|
||||
type TemplateClassification struct {
|
||||
CvssMetrics string `yaml:"cvss-metrics,omitempty"`
|
||||
CvssScore float64 `yaml:"cvss-score,omitempty"`
|
||||
CveId string `yaml:"cve-id,omitempty"`
|
||||
CweId string `yaml:"cwe-id,omitempty"`
|
||||
}
|
||||
|
||||
type TemplateInfo struct {
|
||||
Name string `yaml:"name"`
|
||||
Author string `yaml:"author"`
|
||||
Severity string `yaml:"severity"`
|
||||
Description string `yaml:"description,omitempty"`
|
||||
Reference []string `yaml:"reference,omitempty"`
|
||||
Remediation string `yaml:"remediation,omitempty"`
|
||||
Classification TemplateClassification `yaml:"classification,omitempty"`
|
||||
Metadata map[string]string `yaml:"metadata,omitempty"`
|
||||
Tags string `yaml:"tags,omitempty"`
|
||||
}
|
||||
|
||||
@ -48,6 +48,8 @@ var httpTestcases = map[string]testutils.TestCase{
|
||||
"http/stop-at-first-match.yaml": &httpStopAtFirstMatch{},
|
||||
"http/stop-at-first-match-with-extractors.yaml": &httpStopAtFirstMatchWithExtractors{},
|
||||
"http/variables.yaml": &httpVariables{},
|
||||
"http/get-override-sni.yaml": &httpSniAnnotation{},
|
||||
"http/get-sni.yaml": &customCLISNI{},
|
||||
}
|
||||
|
||||
type httpInteractshRequest struct{}
|
||||
@ -810,3 +812,47 @@ func (h *httpVariables) Execute(filePath string) error {
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type customCLISNI struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *customCLISNI) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if r.TLS.ServerName == "test" {
|
||||
_, _ = w.Write([]byte("test-ok"))
|
||||
} else {
|
||||
_, _ = w.Write([]byte("test-ko"))
|
||||
}
|
||||
})
|
||||
ts := httptest.NewTLSServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-sni", "test")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpSniAnnotation struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpSniAnnotation) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if r.TLS.ServerName == "test" {
|
||||
_, _ = w.Write([]byte("test-ok"))
|
||||
} else {
|
||||
_, _ = w.Write([]byte("test-ko"))
|
||||
}
|
||||
})
|
||||
ts := httptest.NewTLSServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
@ -119,6 +119,8 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
|
||||
createGroup(flagSet, "output", "Output",
|
||||
flagSet.StringVarP(&options.Output, "output", "o", "", "output file to write found issues/vulnerabilities"),
|
||||
flagSet.BoolVarP(&options.StoreResponse, "store-resp", "sresp", false, "store all request/response passed through nuclei to output directory"),
|
||||
flagSet.StringVarP(&options.StoreResponseDir, "store-resp-dir", "srd", runner.DefaultDumpTrafficOutputFolder, "store all request/response passed through nuclei to custom directory"),
|
||||
flagSet.BoolVar(&options.Silent, "silent", false, "display findings only"),
|
||||
flagSet.BoolVarP(&options.NoColor, "no-color", "nc", false, "disable output content coloring (ANSI escape codes)"),
|
||||
flagSet.BoolVar(&options.JSON, "json", false, "write output in JSONL(ines) format"),
|
||||
@ -146,7 +148,8 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
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"),
|
||||
flagSet.StringVarP(&options.ClientCAFile, "client-ca", "ca", "", "client certificate authority file (PEM-encoded) used for authenticating against scanned hosts"),
|
||||
flagSet.BoolVar(&options.ZTLS, "ztls", false, "Use ztls library with autofallback to standard one for tls13"),
|
||||
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)"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "interactsh", "interactsh",
|
||||
@ -190,8 +193,6 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.BoolVar(&options.Debug, "debug", false, "show all requests and responses"),
|
||||
flagSet.BoolVarP(&options.DebugRequests, "debug-req", "dreq", false, "show all sent requests"),
|
||||
flagSet.BoolVarP(&options.DebugResponse, "debug-resp", "dresp", false, "show all received responses"),
|
||||
flagSet.BoolVarP(&options.StoreResponse, "store-resp", "sresp", false, "store all request/response passed through nuclei to output directory"),
|
||||
flagSet.StringVarP(&options.StoreResponseDir, "store-resp-dir", "srd", runner.DefaultDumpTrafficOutputFolder, "store all request/response passed through nuclei to custom directory"),
|
||||
flagSet.NormalizedOriginalStringSliceVarP(&options.Proxy, "proxy", "p", []string{}, "list of http/socks5 proxy to use (comma separated or file input)"),
|
||||
flagSet.BoolVarP(&options.ProxyInternal, "proxy-internal", "pi", false, "proxy all internal requests"),
|
||||
flagSet.StringVarP(&options.TraceLogFile, "trace-log", "tlog", "", "file to write sent requests trace log"),
|
||||
|
||||
22
v2/go.mod
22
v2/go.mod
@ -12,7 +12,7 @@ require (
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/corpix/uarand v0.1.1
|
||||
github.com/go-playground/validator/v10 v10.11.0
|
||||
github.com/go-rod/rod v0.106.5
|
||||
github.com/go-rod/rod v0.106.6
|
||||
github.com/gobwas/ws v1.1.0
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/itchyny/gojq v0.12.7
|
||||
@ -21,13 +21,13 @@ require (
|
||||
github.com/karlseguin/ccache v2.0.3+incompatible
|
||||
github.com/karrick/godirwalk v1.17.0 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/miekg/dns v1.1.48
|
||||
github.com/miekg/dns v1.1.49
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/owenrumney/go-sarif v1.1.1
|
||||
github.com/owenrumney/go-sarif/v2 v2.1.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectdiscovery/clistats v0.0.8
|
||||
github.com/projectdiscovery/cryptoutil v1.0.0
|
||||
github.com/projectdiscovery/fastdialer v0.0.15-0.20220127193345-f06b0fd54d47
|
||||
github.com/projectdiscovery/fastdialer v0.0.16-0.20220509174423-0e57a7c8cf83
|
||||
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20220427234316-40b2541a84b8
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220412061559-5119d6086323
|
||||
@ -45,12 +45,12 @@ require (
|
||||
github.com/segmentio/ksuid v1.0.4
|
||||
github.com/shirou/gopsutil/v3 v3.22.4
|
||||
github.com/spaolacci/murmur3 v1.1.0
|
||||
github.com/spf13/cast v1.4.1
|
||||
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.1
|
||||
github.com/weppos/publicsuffix-go v0.15.1-0.20210928183822-5ee35905bd95
|
||||
github.com/xanzy/go-gitlab v0.64.0
|
||||
github.com/xanzy/go-gitlab v0.65.0
|
||||
github.com/ysmood/gson v0.7.1 // indirect
|
||||
github.com/ysmood/leakless v0.7.0 // indirect
|
||||
go.uber.org/atomic v1.9.0
|
||||
@ -63,7 +63,7 @@ require (
|
||||
moul.io/http2curl v1.0.0
|
||||
)
|
||||
|
||||
require github.com/aws/aws-sdk-go v1.44.7
|
||||
require github.com/aws/aws-sdk-go v1.44.15
|
||||
|
||||
require github.com/projectdiscovery/folderutil v0.0.0-20220215113126-add60a1e8e08
|
||||
|
||||
@ -76,11 +76,12 @@ require (
|
||||
github.com/openrdap/rdap v0.9.1-0.20191017185644-af93e7ef17b7
|
||||
github.com/projectdiscovery/iputil v0.0.0-20210804143329-3a30fcde43f3
|
||||
github.com/projectdiscovery/nvd v1.0.9-0.20220314070650-d4a214c1f87d
|
||||
github.com/projectdiscovery/sliceutil v0.0.0-20220225084130-8392ac12fa6d
|
||||
github.com/projectdiscovery/sliceutil v0.0.0-20220511171050-c7d9bc5cadd9
|
||||
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921
|
||||
github.com/projectdiscovery/wappalyzergo v0.0.38
|
||||
github.com/projectdiscovery/wappalyzergo v0.0.42
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/zmap/zcrypto v0.0.0-20211005224000-2d0ffdec8a9b
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
require (
|
||||
@ -103,7 +104,6 @@ require (
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/frankban/quicktest v1.14.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
@ -154,7 +154,6 @@ require (
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
github.com/ysmood/goob v0.4.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
github.com/zclconf/go-cty v1.10.0 // indirect
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
@ -169,5 +168,4 @@ require (
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
||||
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
||||
47
v2/go.sum
47
v2/go.sum
@ -86,8 +86,8 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.44.7 h1:LpCM8Fpw/L58vgdve6A+UqJr8dzo6Xj7HX7DIIGHg2A=
|
||||
github.com/aws/aws-sdk-go v1.44.7/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.15 h1:z02BVeV6k7hZMfWEQmKh3X23s3F9PBHFCcIVfNlut7A=
|
||||
github.com/aws/aws-sdk-go v1.44.15/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@ -103,7 +103,6 @@ github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaq
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||
github.com/c4milo/unpackit v0.1.0 h1:91pWJ6B3svZ4LOE+p3rnyucRK5fZwBdF/yQ/pcZO31I=
|
||||
github.com/c4milo/unpackit v0.1.0/go.mod h1:pvXCMYlSV8zwGFWMaT+PWYkAB/cvDjN2mv9r7ZRSxEo=
|
||||
github.com/caddyserver/certmagic v0.16.0/go.mod h1:jKQ5n+ViHAr6DbPwEGLTSM2vDwTO6EvCKBblBRUvvuQ=
|
||||
github.com/caddyserver/certmagic v0.16.1 h1:rdSnjcUVJojmL4M0efJ+yHXErrrijS4YYg3FuwRdJkI=
|
||||
github.com/caddyserver/certmagic v0.16.1/go.mod h1:jKQ5n+ViHAr6DbPwEGLTSM2vDwTO6EvCKBblBRUvvuQ=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@ -152,8 +151,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns=
|
||||
github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
@ -174,8 +173,8 @@ github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2B
|
||||
github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-rod/rod v0.91.1/go.mod h1:/W4lcZiCALPD603MnJGIvhtywP3R6yRB9EDfFfsHiiI=
|
||||
github.com/go-rod/rod v0.106.5 h1:HQOxmOb/xjZ+QnnK4D8t+3+CWFreKSuqid/65zH4poA=
|
||||
github.com/go-rod/rod v0.106.5/go.mod h1:N/ZJik0+EYXNpW/74q0V1H7K3/UTfwHV/tRxY0CY/Vw=
|
||||
github.com/go-rod/rod v0.106.6 h1:zJorVPG7s8Xgbh7PkSySP4FNoo0OiougKaMb3j6zT6w=
|
||||
github.com/go-rod/rod v0.106.6/go.mod h1:xkZOchuKqTOkMOBkrzb7uJpbKZRab1haPCWDvuZkS2U=
|
||||
github.com/goburrow/cache v0.1.4 h1:As4KzO3hgmzPlnaMniZU9+VmoNYseUhuELbxy9mRBfw=
|
||||
github.com/goburrow/cache v0.1.4/go.mod h1:cDFesZDnIlrHoNlMYqqMpCRawuXulgx+y7mXU8HZ+/c=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
@ -324,7 +323,6 @@ github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwS
|
||||
github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.2 h1:3WH+AG7s2+T8o3nrM/8u2rdqUEcQhmga7smjrT41nAw=
|
||||
github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||
@ -375,8 +373,9 @@ github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ=
|
||||
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
|
||||
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
@ -417,6 +416,8 @@ github.com/openrdap/rdap v0.9.1-0.20191017185644-af93e7ef17b7/go.mod h1:inRbqVxN
|
||||
github.com/owenrumney/go-sarif v1.0.11/go.mod h1:hTBFbxU7GuVRUvwMx+eStp9M/Oun4xHCS3vqpPvket8=
|
||||
github.com/owenrumney/go-sarif v1.1.1 h1:QNObu6YX1igyFKhdzd7vgzmw7XsWN3/6NMGuDzBgXmE=
|
||||
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
|
||||
github.com/owenrumney/go-sarif/v2 v2.1.1 h1:JVUO0cEhG8bvEWIxsRmURY4u7wBZUTgdh4zikkkiPM8=
|
||||
github.com/owenrumney/go-sarif/v2 v2.1.1/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
@ -436,8 +437,8 @@ github.com/projectdiscovery/cryptoutil v0.0.0-20210805184155-b5d2512f9345/go.mod
|
||||
github.com/projectdiscovery/cryptoutil v1.0.0 h1:5rQfnWDthJ5ZFcqze+rmT1N7l1HJQ6EB26MrjaYB7I0=
|
||||
github.com/projectdiscovery/cryptoutil v1.0.0/go.mod h1:VJvSNE8f8A1MgpjgAL2GPJSQcJa4jbdaeQJstARFrU4=
|
||||
github.com/projectdiscovery/fastdialer v0.0.12/go.mod h1:RkRbxqDCcCFhfNUbkzBIz/ieD4uda2JuUA4WJ+RLee0=
|
||||
github.com/projectdiscovery/fastdialer v0.0.15-0.20220127193345-f06b0fd54d47 h1:TUsZiwez9uFmph1hlTsiH7rdB+wi4524+lMuV2z6FaM=
|
||||
github.com/projectdiscovery/fastdialer v0.0.15-0.20220127193345-f06b0fd54d47/go.mod h1:GbQvP1ezGlQn0af3lVcl08b5eRQu960T7A9pwazybSo=
|
||||
github.com/projectdiscovery/fastdialer v0.0.16-0.20220509174423-0e57a7c8cf83 h1:1hzvl0lsWpvQ8nn1s9YMyBjO13/Z+f/T4W2jroOohfo=
|
||||
github.com/projectdiscovery/fastdialer v0.0.16-0.20220509174423-0e57a7c8cf83/go.mod h1:wn6jSJ1fIO6kLplFEbFIkRB6Kj/Q6VngnzKuBHLVPiI=
|
||||
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08 h1:NwD1R/du1dqrRKN3SJl9kT6tN3K9puuWFXEvYF2ihew=
|
||||
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08/go.mod h1:paLCnwV8sL7ppqIwVQodQrk3F6mnWafwTDwRd7ywZwQ=
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210914153648-31f843feaad4/go.mod h1:U+QCpQnX8o2N2w0VUGyAzjM3yBAe4BKedVElxiImsx0=
|
||||
@ -459,8 +460,6 @@ github.com/projectdiscovery/hmap v0.0.2-0.20210616215655-7b78e7f33d1f/go.mod h1:
|
||||
github.com/projectdiscovery/hmap v0.0.2-0.20210917080408-0fd7bd286bfa h1:9sZWFUAshIa/ea0RKjGRuuZiS5PzYXAFjTRUnSbezr0=
|
||||
github.com/projectdiscovery/hmap v0.0.2-0.20210917080408-0fd7bd286bfa/go.mod h1:lV5f/PNPmCCjCN/dR317/chN9s7VG5h/xcbFfXOz8Fo=
|
||||
github.com/projectdiscovery/interactsh v0.0.4/go.mod h1:PtJrddeBW1/LeOVgTvvnjUl3Hu/17jTkoIi8rXeEODE=
|
||||
github.com/projectdiscovery/interactsh v1.0.3 h1:QFL/fFTfvhLeIRFBSguWP8r6h8vf65Bhkf8wzKU2/qQ=
|
||||
github.com/projectdiscovery/interactsh v1.0.3/go.mod h1:3943djLJ4SZBZfJ7A2XEy8xspfFmT0BDiN9FCW7PAXY=
|
||||
github.com/projectdiscovery/interactsh v1.0.4 h1:73HHOeqGduU1lkIqeYkuEfzdejXRqxQJFZCEbQ1uvkU=
|
||||
github.com/projectdiscovery/interactsh v1.0.4/go.mod h1:57Xl3Q59aTb8VaFNGkCPO8pWTyTYhlM33p+HDhL8Ygw=
|
||||
github.com/projectdiscovery/ipranger v0.0.2/go.mod h1:kcAIk/lo5rW+IzUrFkeYyXnFJ+dKwYooEOHGVPP/RWE=
|
||||
@ -490,12 +489,10 @@ github.com/projectdiscovery/retryabledns v1.0.13 h1:Ogfv0fl3Nszb+Nq2S2qQmE+PJDlS
|
||||
github.com/projectdiscovery/retryabledns v1.0.13/go.mod h1:EeqHcAPp0g2GljT4qkxKSAE47Dj0ZrJQ46R9ct3Muhk=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1D+SBxoqfAF4nyzvmevkTkWsek=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.2/go.mod h1:dx//aY9V247qHdsRf0vdWHTBZuBQ2vm6Dq5dagxrDYI=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.3-0.20220414143248-bb6eabffa43e h1:ohoSKR8w4GzGjmOaqdCa8pvHm3qbAyv489skpyrkCX0=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.3-0.20220414143248-bb6eabffa43e/go.mod h1:t4buiLTB0HtI+62iHfGDqQVTv/i+8OhAKwaX93TGsFE=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.3-0.20220506110515-811d938bd26d h1:VR+tDkedzHIp1pGKIDcfPFt7J8KjcjxGsJvBAP6RXFQ=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.3-0.20220506110515-811d938bd26d/go.mod h1:t4buiLTB0HtI+62iHfGDqQVTv/i+8OhAKwaX93TGsFE=
|
||||
github.com/projectdiscovery/sliceutil v0.0.0-20220225084130-8392ac12fa6d h1:wIQPYRZEwTeJuoZLv3NT9r+il2fAv1ObRzTdHkNgOxk=
|
||||
github.com/projectdiscovery/sliceutil v0.0.0-20220225084130-8392ac12fa6d/go.mod h1:QHXvznfPfA5f0AZUIBkbLapoUJJlsIDgUlkKva6dOr4=
|
||||
github.com/projectdiscovery/sliceutil v0.0.0-20220511171050-c7d9bc5cadd9 h1:dQO4FNxOhkZqZHW5nUh6f1NXIRUyoZ57bXETXjsyfNk=
|
||||
github.com/projectdiscovery/sliceutil v0.0.0-20220511171050-c7d9bc5cadd9/go.mod h1:crCchiT/KYrAlEY8JbuMGE6XKym61mhAd1E7REq2VwQ=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20210524051937-51dabe3b72c0/go.mod h1:TVSdZC0rRQeMIbsNSiGPhbmhyRtxqqtAGA9JiiNp2r4=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20210823090203-2f5f137e8e1d/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
@ -505,8 +502,8 @@ github.com/projectdiscovery/stringsutil v0.0.0-20220422150559-b54fb5dc6833 h1:yo
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20220422150559-b54fb5dc6833/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921 h1:EgaxpJm7+lKppfAHkFHs+S+II0lodp4Gu3leZCCkWlc=
|
||||
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921/go.mod h1:oXLErqOpqEAp/ueQlknysFxHO3CUNoSiDNnkiHG+Jpo=
|
||||
github.com/projectdiscovery/wappalyzergo v0.0.38 h1:0HGXJfMGMfveM5R0oGIWL0Sc513+gVPoHQkjZxmT2GA=
|
||||
github.com/projectdiscovery/wappalyzergo v0.0.38/go.mod h1:vS+npIOANv7eKsEtODsyRQt2n1v8VofCwj2gjmq72EM=
|
||||
github.com/projectdiscovery/wappalyzergo v0.0.42 h1:4DuJVpgesHSnUNVG+l62QIYEmcMXu3PLyhS1Wp75c30=
|
||||
github.com/projectdiscovery/wappalyzergo v0.0.42/go.mod h1:vS+npIOANv7eKsEtODsyRQt2n1v8VofCwj2gjmq72EM=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.2/go.mod h1:7uSxfMXaBmzvw8m5EhOEjB6nhz0rK/H9sUjq1ciZu24=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.3-0.20211126104922-00d2c6bb43b6 h1:DvWRQpw7Ib2CRL3ogYm/BWM+X0UGPfz1n9Ix9YKgFM8=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.3-0.20211126104922-00d2c6bb43b6/go.mod h1:8OfZj8p/axkUM/TJoS/O9LDjj/S8u17rxRbqluE9CU4=
|
||||
@ -546,8 +543,9 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
@ -599,8 +597,8 @@ github.com/weppos/publicsuffix-go v0.15.1-0.20210928183822-5ee35905bd95/go.mod h
|
||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ=
|
||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
|
||||
github.com/xanzy/go-gitlab v0.50.3/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
|
||||
github.com/xanzy/go-gitlab v0.64.0 h1:rMgQdW9S1w3qvNAH2LYpFd2xh7KNLk+JWJd7sorNuTc=
|
||||
github.com/xanzy/go-gitlab v0.64.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
|
||||
github.com/xanzy/go-gitlab v0.65.0 h1:9xSA9cRVhz3Z54JacIHdvWnNmNAoSz/BDnyMGOf3yIg=
|
||||
github.com/xanzy/go-gitlab v0.65.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
@ -611,8 +609,8 @@ github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
|
||||
github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
|
||||
github.com/ysmood/got v0.9.3/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/got v0.14.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/got v0.28.2 h1:2dtVOneu4YGDk9skgzq8aqW9vZ1ssBla+ddqrE91bNs=
|
||||
github.com/ysmood/got v0.28.2/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/got v0.29.1 h1:7TNTm3Bw5kdBGXFp04qnZ9DqlZ1XS1z1JdeobeJY6Mo=
|
||||
github.com/ysmood/got v0.29.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/gotrace v0.2.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
|
||||
github.com/ysmood/gotrace v0.2.2/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
|
||||
github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY=
|
||||
@ -632,7 +630,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
|
||||
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521 h1:kKCF7VX/wTmdg2ZjEaqlq99Bjsoiz7vH6sFniF/vI4M=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
|
||||
|
||||
@ -570,8 +570,10 @@ func isTemplate(filename string) bool {
|
||||
// SaveResumeConfig to file
|
||||
func (r *Runner) SaveResumeConfig(path string) error {
|
||||
resumeCfg := types.NewResumeCfg()
|
||||
r.resumeCfg.Lock()
|
||||
resumeCfg.ResumeFrom = r.resumeCfg.Current
|
||||
data, _ := json.MarshalIndent(resumeCfg, "", "\t")
|
||||
r.resumeCfg.Unlock()
|
||||
|
||||
return os.WriteFile(path, data, os.ModePerm)
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ type Config struct {
|
||||
const nucleiConfigFilename = ".templates-config.json"
|
||||
|
||||
// Version is the current version of nuclei
|
||||
const Version = `2.7.0`
|
||||
const Version = `2.7.1`
|
||||
|
||||
func getConfigDetails() (string, error) {
|
||||
configDir, err := GetConfigDir()
|
||||
|
||||
@ -9,6 +9,8 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/workflows"
|
||||
)
|
||||
|
||||
const workflowExecutionErrorMessageTemplate = "[%s] Could not execute workflow step: %s\n"
|
||||
|
||||
// executeWorkflow runs a workflow on an input and returns true or false
|
||||
func (e *Engine) executeWorkflow(input string, w *workflows.Workflow) bool {
|
||||
results := &atomic.Bool{}
|
||||
@ -18,7 +20,7 @@ func (e *Engine) executeWorkflow(input string, w *workflows.Workflow) bool {
|
||||
swg.Add()
|
||||
func(template *workflows.WorkflowTemplate) {
|
||||
if err := e.runWorkflowStep(template, input, results, &swg, w); err != nil {
|
||||
gologger.Warning().Msgf("[%s] Could not execute workflow step: %s\n", template.Template, err)
|
||||
gologger.Warning().Msgf(workflowExecutionErrorMessageTemplate, template.Template, err)
|
||||
}
|
||||
swg.Done()
|
||||
}(template)
|
||||
@ -64,7 +66,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, input str
|
||||
if len(template.Executers) == 1 {
|
||||
mainErr = err
|
||||
} else {
|
||||
gologger.Warning().Msgf("[%s] Could not execute workflow step: %s\n", template.Template, err)
|
||||
gologger.Warning().Msgf(workflowExecutionErrorMessageTemplate, template.Template, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -94,7 +96,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, input str
|
||||
|
||||
go func(subtemplate *workflows.WorkflowTemplate) {
|
||||
if err := e.runWorkflowStep(subtemplate, input, results, swg, w); err != nil {
|
||||
gologger.Warning().Msgf("[%s] Could not execute workflow step: %s\n", subtemplate.Template, err)
|
||||
gologger.Warning().Msgf(workflowExecutionErrorMessageTemplate, subtemplate.Template, err)
|
||||
}
|
||||
swg.Done()
|
||||
}(subtemplate)
|
||||
@ -105,7 +107,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, input str
|
||||
if len(template.Executers) == 1 {
|
||||
mainErr = err
|
||||
} else {
|
||||
gologger.Warning().Msgf("[%s] Could not execute workflow step: %s\n", template.Template, err)
|
||||
gologger.Warning().Msgf(workflowExecutionErrorMessageTemplate, template.Template, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -118,7 +120,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, input str
|
||||
|
||||
go func(template *workflows.WorkflowTemplate) {
|
||||
if err := e.runWorkflowStep(template, input, results, swg, w); err != nil {
|
||||
gologger.Warning().Msgf("[%s] Could not execute workflow step: %s\n", template.Template, err)
|
||||
gologger.Warning().Msgf(workflowExecutionErrorMessageTemplate, template.Template, err)
|
||||
}
|
||||
swg.Done()
|
||||
}(subtemplate)
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@ -48,6 +49,7 @@ type StandardWriter struct {
|
||||
noTimestamp bool
|
||||
noMetadata bool
|
||||
matcherStatus bool
|
||||
mutex *sync.Mutex
|
||||
aurora aurora.Aurora
|
||||
outputFile io.WriteCloser
|
||||
traceFile io.WriteCloser
|
||||
@ -161,6 +163,7 @@ func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp, Match
|
||||
matcherStatus: MatcherStatus,
|
||||
noTimestamp: noTimestamp,
|
||||
aurora: auroraColorizer,
|
||||
mutex: &sync.Mutex{},
|
||||
outputFile: outputFile,
|
||||
traceFile: traceOutput,
|
||||
errorFile: errorOutput,
|
||||
@ -193,6 +196,9 @@ func (w *StandardWriter) Write(event *ResultEvent) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
|
||||
_, _ = os.Stdout.Write(data)
|
||||
_, _ = os.Stdout.Write([]byte("\n"))
|
||||
|
||||
|
||||
@ -67,6 +67,8 @@ func New(opts Options) (*Service, error) {
|
||||
if opts.ExecuterOpts.Options.Verbose {
|
||||
gologger.Verbose().Msgf("Normalized mapping (%d): %v\n", len(mappingData), mappingData)
|
||||
}
|
||||
defaultTemplatesDirectories := []string{config.TemplatesDirectory}
|
||||
|
||||
// adding custom template path if available
|
||||
if len(opts.ExecuterOpts.Options.Templates) > 0 {
|
||||
defaultTemplatesDirectories = append(defaultTemplatesDirectories, opts.ExecuterOpts.Options.Templates...)
|
||||
@ -118,10 +120,6 @@ func (s *Service) Execute() {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
defaultTemplatesDirectories = []string{"cves/", "default-logins/", "dns/", "exposures/", "miscellaneous/", "misconfiguration/", "network/", "takeovers/", "vulnerabilities/"}
|
||||
)
|
||||
|
||||
const maxDefaultBody = 2 * 1024 * 1024
|
||||
|
||||
// executeWappalyzerTechDetection implements the logic to run the wappalyzer
|
||||
@ -171,7 +169,7 @@ func (s *Service) processWappalyzerInputPair(input string) {
|
||||
fingerprints := s.wappalyzer.Fingerprint(resp.Header, data)
|
||||
normalized := make(map[string]struct{})
|
||||
for k := range fingerprints {
|
||||
normalized[strings.ToLower(k)] = struct{}{}
|
||||
normalized[normalizeAppName(k)] = struct{}{}
|
||||
}
|
||||
|
||||
if s.opts.Options.Verbose {
|
||||
@ -215,6 +213,15 @@ func (s *Service) processWappalyzerInputPair(input string) {
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeAppName(appName string) string {
|
||||
if strings.Contains(appName, ":") {
|
||||
if parts := strings.Split(appName, ":"); len(parts) == 2 {
|
||||
appName = parts[0]
|
||||
}
|
||||
}
|
||||
return strings.ToLower(appName)
|
||||
}
|
||||
|
||||
func uniqueSlice(slice []string) []string {
|
||||
data := make(map[string]struct{}, len(slice))
|
||||
for _, item := range slice {
|
||||
|
||||
15
v2/pkg/protocols/common/automaticscan/automaticscan_test.go
Normal file
15
v2/pkg/protocols/common/automaticscan/automaticscan_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package automaticscan
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNormalizeAppName(t *testing.T) {
|
||||
appName := normalizeAppName("JBoss")
|
||||
require.Equal(t, "jboss", appName, "could not get normalized name")
|
||||
|
||||
appName = normalizeAppName("JBoss:2.3.5")
|
||||
require.Equal(t, "jboss", appName, "could not get normalized name")
|
||||
}
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -119,17 +120,32 @@ func generateGroovy1Payload(cmd string) []byte {
|
||||
}
|
||||
|
||||
// generateDNSPayload generates DNS interaction deserialization paylaod for a DNS Name.
|
||||
// Based on Gabriel Lawrence gadget
|
||||
func generateDNSPayload(url string) []byte {
|
||||
// Taken from ysoserial DNS gadget.
|
||||
func generateDNSPayload(URL string) []byte {
|
||||
parsed, err := url.Parse(URL)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
buffer := &bytes.Buffer{}
|
||||
hostname := parsed.Hostname()
|
||||
|
||||
prefix, _ := hex.DecodeString("ACED0005737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000017372000C6A6176612E6E65742E55524C962537361AFCE47203000749000868617368436F6465490004706F72744C0009617574686F726974797400124C6A6176612F6C616E672F537472696E673B4C000466696C6571007E00034C0004686F737471007E00034C000870726F746F636F6C71007E00034C000372656671007E00037870FFFFFFFFFFFFFFFF7400")
|
||||
buffer.Write(prefix)
|
||||
buffer.WriteString(string(rune(len(url))))
|
||||
buffer.WriteString(url)
|
||||
suffix, _ := hex.DecodeString("74000071007E00057400056874747073707874001968747470733A2F2F746573742E6A6578626F73732E696E666F78")
|
||||
buffer.Write(suffix)
|
||||
|
||||
buffer.WriteString(string(rune(len(hostname))))
|
||||
buffer.WriteString(hostname)
|
||||
|
||||
middle, _ := hex.DecodeString("74000071007E0005740005")
|
||||
buffer.Write(middle)
|
||||
buffer.WriteString(parsed.Scheme)
|
||||
|
||||
middle, _ = hex.DecodeString("70787400")
|
||||
buffer.Write(middle)
|
||||
buffer.WriteString(string(rune(len(URL))))
|
||||
buffer.WriteString(URL)
|
||||
|
||||
suffix, _ := hex.DecodeString("78")
|
||||
buffer.Write(suffix)
|
||||
return buffer.Bytes()
|
||||
}
|
||||
|
||||
|
||||
@ -56,6 +56,11 @@ var (
|
||||
interactshURLMarkerRegex = regexp.MustCompile(`{{interactsh-url(?:_[0-9]+){0,3}}}`)
|
||||
)
|
||||
|
||||
const (
|
||||
stopAtFirstMatchAttribute = "stop-at-first-match"
|
||||
templateIdAttribute = "template-id"
|
||||
)
|
||||
|
||||
// Options contains configuration options for interactsh nuclei integration.
|
||||
type Options struct {
|
||||
// ServerURL is the URL of the interactsh server.
|
||||
@ -178,8 +183,8 @@ func (c *Client) firstTimeInitializeClient() error {
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := request.Event.InternalEvent["stop-at-first-match"]; ok || c.options.StopAtFirstMatch {
|
||||
gotItem := c.matchedTemplates.Get(hash(request.Event.InternalEvent["template-id"].(string), request.Event.InternalEvent["host"].(string)))
|
||||
if _, ok := request.Event.InternalEvent[stopAtFirstMatchAttribute]; ok || c.options.StopAtFirstMatch {
|
||||
gotItem := c.matchedTemplates.Get(hash(request.Event.InternalEvent[templateIdAttribute].(string), request.Event.InternalEvent["host"].(string)))
|
||||
if gotItem != nil {
|
||||
return
|
||||
}
|
||||
@ -219,8 +224,8 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
|
||||
|
||||
if writer.WriteResult(data.Event, c.options.Output, c.options.Progress, c.options.IssuesClient) {
|
||||
c.matched = true
|
||||
if _, ok := data.Event.InternalEvent["stop-at-first-match"]; ok || c.options.StopAtFirstMatch {
|
||||
c.matchedTemplates.Set(hash(data.Event.InternalEvent["template-id"].(string), data.Event.InternalEvent["host"].(string)), true, defaultInteractionDuration)
|
||||
if _, ok := data.Event.InternalEvent[stopAtFirstMatchAttribute]; ok || c.options.StopAtFirstMatch {
|
||||
c.matchedTemplates.Set(hash(data.Event.InternalEvent[templateIdAttribute].(string), data.Event.InternalEvent["host"].(string)), true, defaultInteractionDuration)
|
||||
}
|
||||
}
|
||||
return true
|
||||
@ -317,8 +322,8 @@ func (c *Client) RequestEvent(interactshURLs []string, data *RequestData) {
|
||||
for _, interactshURL := range interactshURLs {
|
||||
id := strings.TrimRight(strings.TrimSuffix(interactshURL, c.hostname), ".")
|
||||
|
||||
if _, ok := data.Event.InternalEvent["stop-at-first-match"]; ok || c.options.StopAtFirstMatch {
|
||||
gotItem := c.matchedTemplates.Get(hash(data.Event.InternalEvent["template-id"].(string), data.Event.InternalEvent["host"].(string)))
|
||||
if _, ok := data.Event.InternalEvent[stopAtFirstMatchAttribute]; ok || c.options.StopAtFirstMatch {
|
||||
gotItem := c.matchedTemplates.Get(hash(data.Event.InternalEvent[templateIdAttribute].(string), data.Event.InternalEvent["host"].(string)))
|
||||
if gotItem != nil {
|
||||
break
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ func Init(options *types.Options) error {
|
||||
}
|
||||
opts.WithDialerHistory = true
|
||||
opts.WithZTLS = options.ZTLS
|
||||
opts.SNIName = options.SNI
|
||||
dialer, err := fastdialer.NewDialer(opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create dialer")
|
||||
|
||||
@ -28,6 +28,10 @@ func newHttpClient(options *types.Options) (*http.Client, error) {
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
if options.SNI != "" {
|
||||
tlsConfig.ServerName = options.SNI
|
||||
}
|
||||
|
||||
// Add the client certificate authentication to the request if it's configured
|
||||
var err error
|
||||
tlsConfig, err = utils.AddConfiguredClientCertToRequest(tlsConfig, options)
|
||||
@ -37,6 +41,7 @@ func newHttpClient(options *types.Options) (*http.Client, error) {
|
||||
|
||||
transport := &http.Transport{
|
||||
DialContext: dialer.Dial,
|
||||
DialTLSContext: dialer.DialTLS,
|
||||
MaxIdleConns: 500,
|
||||
MaxIdleConnsPerHost: 500,
|
||||
MaxConnsPerHost: 500,
|
||||
|
||||
@ -18,6 +18,15 @@ import (
|
||||
"github.com/segmentio/ksuid"
|
||||
)
|
||||
|
||||
var (
|
||||
invalidArgumentsError = errors.New("invalid arguments provided")
|
||||
)
|
||||
|
||||
const (
|
||||
couldNotGetElementErrorMessage = "could not get element"
|
||||
couldNotScrollErrorMessage = "could not scroll into view"
|
||||
)
|
||||
|
||||
// ExecuteActions executes a list of actions on a page.
|
||||
func (p *Page) ExecuteActions(baseURL *url.URL, actions []*Action) (map[string]string, error) {
|
||||
var err error
|
||||
@ -243,7 +252,7 @@ func (p *Page) ActionSetMethod(act *Action, out map[string]string /*TODO review
|
||||
func (p *Page) NavigateURL(action *Action, out map[string]string, parsed *url.URL /*TODO review unused parameter*/) error {
|
||||
URL := p.getActionArgWithDefaultValues(action, "url")
|
||||
if URL == "" {
|
||||
return errors.New("invalid arguments provided")
|
||||
return invalidArgumentsError
|
||||
}
|
||||
|
||||
// Handle the dynamic value substitution here.
|
||||
@ -267,7 +276,7 @@ func (p *Page) NavigateURL(action *Action, out map[string]string, parsed *url.UR
|
||||
func (p *Page) RunScript(action *Action, out map[string]string) error {
|
||||
code := p.getActionArgWithDefaultValues(action, "code")
|
||||
if code == "" {
|
||||
return errors.New("invalid arguments provided")
|
||||
return invalidArgumentsError
|
||||
}
|
||||
if p.getActionArgWithDefaultValues(action, "hook") == "true" {
|
||||
if _, err := p.page.EvalOnNewDocument(code); err != nil {
|
||||
@ -288,10 +297,10 @@ func (p *Page) RunScript(action *Action, out map[string]string) error {
|
||||
func (p *Page) ClickElement(act *Action, out map[string]string /*TODO review unused parameter*/) error {
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
if err = element.Click(proto.InputMouseButtonLeft); err != nil {
|
||||
return errors.Wrap(err, "could not click element")
|
||||
@ -308,10 +317,10 @@ func (p *Page) KeyboardAction(act *Action, out map[string]string /*TODO review u
|
||||
func (p *Page) RightClickElement(act *Action, out map[string]string /*TODO review unused parameter*/) error {
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
if err = element.Click(proto.InputMouseButtonRight); err != nil {
|
||||
return errors.Wrap(err, "could not right click element")
|
||||
@ -349,14 +358,14 @@ func (p *Page) Screenshot(act *Action, out map[string]string) error {
|
||||
func (p *Page) InputElement(act *Action, out map[string]string /*TODO review unused parameter*/) error {
|
||||
value := p.getActionArgWithDefaultValues(act, "value")
|
||||
if value == "" {
|
||||
return errors.New("invalid arguments provided")
|
||||
return invalidArgumentsError
|
||||
}
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
if err = element.Input(value); err != nil {
|
||||
return errors.Wrap(err, "could not input element")
|
||||
@ -368,14 +377,14 @@ func (p *Page) InputElement(act *Action, out map[string]string /*TODO review unu
|
||||
func (p *Page) TimeInputElement(act *Action, out map[string]string /*TODO review unused parameter*/) error {
|
||||
value := p.getActionArgWithDefaultValues(act, "value")
|
||||
if value == "" {
|
||||
return errors.New("invalid arguments provided")
|
||||
return invalidArgumentsError
|
||||
}
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, value)
|
||||
if err != nil {
|
||||
@ -391,14 +400,14 @@ func (p *Page) TimeInputElement(act *Action, out map[string]string /*TODO review
|
||||
func (p *Page) SelectInputElement(act *Action, out map[string]string /*TODO review unused parameter*/) error {
|
||||
value := p.getActionArgWithDefaultValues(act, "value")
|
||||
if value == "" {
|
||||
return errors.New("invalid arguments provided")
|
||||
return invalidArgumentsError
|
||||
}
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
|
||||
selectedBool := false
|
||||
@ -430,7 +439,7 @@ func (p *Page) WaitLoad(act *Action, out map[string]string /*TODO review unused
|
||||
func (p *Page) GetResource(act *Action, out map[string]string) error {
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
resource, err := element.Resource()
|
||||
if err != nil {
|
||||
@ -446,10 +455,10 @@ func (p *Page) GetResource(act *Action, out map[string]string) error {
|
||||
func (p *Page) FilesInput(act *Action, out map[string]string /*TODO review unused parameter*/) error {
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
value := p.getActionArgWithDefaultValues(act, "value")
|
||||
filesPaths := strings.Split(value, ",")
|
||||
@ -463,10 +472,10 @@ func (p *Page) FilesInput(act *Action, out map[string]string /*TODO review unuse
|
||||
func (p *Page) ExtractElement(act *Action, out map[string]string) error {
|
||||
element, err := p.pageElementBy(act.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get element")
|
||||
return errors.Wrap(err, couldNotGetElementErrorMessage)
|
||||
}
|
||||
if err = element.ScrollIntoView(); err != nil {
|
||||
return errors.Wrap(err, "could not scroll into view")
|
||||
return errors.Wrap(err, couldNotScrollErrorMessage)
|
||||
}
|
||||
switch p.getActionArgWithDefaultValues(act, "target") {
|
||||
case "attribute":
|
||||
|
||||
@ -19,6 +19,8 @@ import (
|
||||
|
||||
var _ protocols.Request = &Request{}
|
||||
|
||||
const couldGetHtmlElementErrorMessage = "could get html element"
|
||||
|
||||
// Type returns the type of the protocol request
|
||||
func (request *Request) Type() templateTypes.ProtocolType {
|
||||
return templateTypes.HeadlessProtocol
|
||||
@ -60,7 +62,7 @@ func (request *Request) executeRequestWithPayloads(inputURL string, payloads map
|
||||
if err != nil {
|
||||
request.options.Output.Request(request.options.TemplatePath, inputURL, request.Type().String(), err)
|
||||
request.options.Progress.IncrementFailedRequestsBy(1)
|
||||
return errors.Wrap(err, "could get html element")
|
||||
return errors.Wrap(err, couldGetHtmlElementErrorMessage)
|
||||
}
|
||||
defer instance.Close()
|
||||
|
||||
@ -70,14 +72,14 @@ func (request *Request) executeRequestWithPayloads(inputURL string, payloads map
|
||||
if err != nil {
|
||||
request.options.Output.Request(request.options.TemplatePath, inputURL, request.Type().String(), err)
|
||||
request.options.Progress.IncrementFailedRequestsBy(1)
|
||||
return errors.Wrap(err, "could get html element")
|
||||
return errors.Wrap(err, couldGetHtmlElementErrorMessage)
|
||||
}
|
||||
timeout := time.Duration(request.options.Options.PageTimeout) * time.Second
|
||||
out, page, err := instance.Run(parsedURL, request.Steps, payloads, timeout)
|
||||
if err != nil {
|
||||
request.options.Output.Request(request.options.TemplatePath, inputURL, request.Type().String(), err)
|
||||
request.options.Progress.IncrementFailedRequestsBy(1)
|
||||
return errors.Wrap(err, "could get html element")
|
||||
return errors.Wrap(err, couldGetHtmlElementErrorMessage)
|
||||
}
|
||||
defer page.Close()
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@ var (
|
||||
urlWithPortRegex = regexp.MustCompile(`{{BaseURL}}:(\d+)`)
|
||||
)
|
||||
|
||||
const evaluateHelperExpressionErrorMessage = "could not evaluate helper expressions"
|
||||
|
||||
// generatedRequest is a single generated request wrapped for a template request
|
||||
type generatedRequest struct {
|
||||
original *Request
|
||||
@ -206,12 +208,12 @@ func (r *requestGenerator) makeHTTPRequestFromModel(ctx context.Context, data st
|
||||
var err error
|
||||
data, err = expressions.Evaluate(data, finalValues)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
||||
}
|
||||
|
||||
method, err := expressions.Evaluate(r.request.Method.String(), finalValues)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
||||
}
|
||||
|
||||
// Build a request on the specified URL
|
||||
@ -245,7 +247,7 @@ func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest
|
||||
var err error
|
||||
rawRequest, err = expressions.Evaluate(rawRequest, finalValues)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
||||
}
|
||||
rawRequestData, err := raw.Parse(rawRequest, baseURL, r.request.Unsafe)
|
||||
if err != nil {
|
||||
@ -288,7 +290,10 @@ func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parseAnnotations(rawRequest, req)
|
||||
if reqWithAnnotations, hasAnnotations := parseAnnotations(rawRequest, req); hasAnnotations {
|
||||
req = reqWithAnnotations
|
||||
request = request.WithContext(req.Context())
|
||||
}
|
||||
|
||||
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues, interactshURLs: r.interactshURLs}, nil
|
||||
}
|
||||
@ -302,7 +307,7 @@ func (r *requestGenerator) fillRequest(req *http.Request, values map[string]inte
|
||||
}
|
||||
value, err := expressions.Evaluate(value, values)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
||||
}
|
||||
req.Header[header] = []string{value}
|
||||
if header == "Host" {
|
||||
@ -323,7 +328,7 @@ func (r *requestGenerator) fillRequest(req *http.Request, values map[string]inte
|
||||
}
|
||||
body, err := expressions.Evaluate(body, values)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
||||
}
|
||||
req.Body = ioutil.NopCloser(strings.NewReader(body))
|
||||
}
|
||||
|
||||
@ -179,6 +179,10 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
if options.SNI != "" {
|
||||
tlsConfig.ServerName = options.SNI
|
||||
}
|
||||
|
||||
// Add the client certificate authentication to the request if it's configured
|
||||
tlsConfig, err = utils.AddConfiguredClientCertToRequest(tlsConfig, options)
|
||||
if err != nil {
|
||||
@ -187,6 +191,7 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
|
||||
|
||||
transport := &http.Transport{
|
||||
DialContext: Dialer.Dial,
|
||||
DialTLSContext: Dialer.DialTLS,
|
||||
MaxIdleConns: maxIdleConns,
|
||||
MaxIdleConnsPerHost: maxIdleConnsPerHost,
|
||||
MaxConnsPerHost: maxConnsPerHost,
|
||||
|
||||
@ -130,6 +130,9 @@ read_line:
|
||||
rawRequest.Path = strings.TrimSuffix(rawRequest.Path, "/")
|
||||
}
|
||||
rawRequest.FullURL = fmt.Sprintf("%s://%s%s", parsedURL.Scheme, strings.TrimSpace(hostURL), rawRequest.Path)
|
||||
if parsedURL.RawQuery != "" {
|
||||
rawRequest.FullURL = fmt.Sprintf("%s?%s", rawRequest.FullURL, parsedURL.RawQuery)
|
||||
}
|
||||
|
||||
// If raw request doesn't have a Host header and isn't marked unsafe,
|
||||
// this will generate the Host header from the parsed baseURL
|
||||
|
||||
@ -1,22 +1,33 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/fastdialer/fastdialer"
|
||||
"github.com/projectdiscovery/iputil"
|
||||
"github.com/projectdiscovery/stringsutil"
|
||||
"github.com/projectdiscovery/urlutil"
|
||||
)
|
||||
|
||||
// @Host:target overrides the input target with the annotated one (similar to self-contained requests)
|
||||
var reHostAnnotation = regexp.MustCompile(`(?m)^@Host:\s*(.+)\s*$`)
|
||||
var (
|
||||
// @Host:target overrides the input target with the annotated one (similar to self-contained requests)
|
||||
reHostAnnotation = regexp.MustCompile(`(?m)^@Host:\s*(.+)\s*$`)
|
||||
// @tls-sni:target overrides the input target with the annotated one
|
||||
// special values:
|
||||
// request.host: takes the value from the host header
|
||||
// target: overiddes with the specific value
|
||||
reSniAnnotation = regexp.MustCompile(`(?m)^@tls-sni:\s*(.+)\s*$`)
|
||||
)
|
||||
|
||||
// parseAnnotations and override requests settings
|
||||
func parseAnnotations(rawRequest string, request *http.Request) {
|
||||
func parseAnnotations(rawRequest string, request *http.Request) (*http.Request, bool) {
|
||||
// parse request for known ovverride annotations
|
||||
var modified bool
|
||||
// @Host:target
|
||||
if hosts := reHostAnnotation.FindStringSubmatch(rawRequest); len(hosts) > 0 {
|
||||
value := strings.TrimSpace(hosts[1])
|
||||
// handle scheme
|
||||
@ -39,7 +50,25 @@ func parseAnnotations(rawRequest string, request *http.Request) {
|
||||
}
|
||||
request.URL.Host = hostPort
|
||||
}
|
||||
modified = true
|
||||
}
|
||||
|
||||
// @tls-sni:target
|
||||
if hosts := reSniAnnotation.FindStringSubmatch(rawRequest); len(hosts) > 0 {
|
||||
value := strings.TrimSpace(hosts[1])
|
||||
value = stringsutil.TrimPrefixAny(value, "http://", "https://")
|
||||
if idxForwardSlash := strings.Index(value, "/"); idxForwardSlash >= 0 {
|
||||
value = value[:idxForwardSlash]
|
||||
}
|
||||
|
||||
if stringsutil.EqualFoldAny(value, "request.host") {
|
||||
value = request.Host
|
||||
}
|
||||
ctx := context.WithValue(request.Context(), fastdialer.SniName, value)
|
||||
request = request.Clone(ctx)
|
||||
modified = true
|
||||
}
|
||||
return request, modified
|
||||
}
|
||||
|
||||
func isHostPort(value string) bool {
|
||||
|
||||
@ -12,11 +12,13 @@ import (
|
||||
// values. Paths and Raw requests are supported as base input, so
|
||||
// it will automatically select between them based on the template.
|
||||
type requestGenerator struct {
|
||||
currentIndex int
|
||||
request *Request
|
||||
options *protocols.ExecuterOptions
|
||||
payloadIterator *generators.Iterator
|
||||
interactshURLs []string
|
||||
currentIndex int
|
||||
currentPayloads map[string]interface{}
|
||||
okCurrentPayload bool
|
||||
request *Request
|
||||
options *protocols.ExecuterOptions
|
||||
payloadIterator *generators.Iterator
|
||||
interactshURLs []string
|
||||
}
|
||||
|
||||
// LeaveDefaultPorts skips normalization of default standard ports
|
||||
@ -35,61 +37,45 @@ func (request *Request) newGenerator() *requestGenerator {
|
||||
// nextValue returns the next path or the next raw request depending on user input
|
||||
// It returns false if all the inputs have been exhausted by the generator instance.
|
||||
func (r *requestGenerator) nextValue() (value string, payloads map[string]interface{}, result bool) {
|
||||
// For both raw/path requests, start with the request at current index.
|
||||
// If we are not at the start, then check if the iterator for payloads
|
||||
// has finished if there are any.
|
||||
// Iterate each payload sequentially for each request path/raw
|
||||
//
|
||||
// If the iterator has finished for the current request
|
||||
// then reset it and move on to the next value, otherwise use the last request.
|
||||
// If the sequence has finished for the current payload values
|
||||
// then restart the sequence from the beginning and move on to the next payloads values
|
||||
// otherwise use the last request.
|
||||
var sequence []string
|
||||
switch {
|
||||
case len(r.request.Path) > 0:
|
||||
sequence = r.request.Path
|
||||
case len(r.request.Raw) > 0:
|
||||
sequence = r.request.Raw
|
||||
default:
|
||||
return "", nil, false
|
||||
}
|
||||
|
||||
if len(r.request.Path) > 0 && r.currentIndex < len(r.request.Path) {
|
||||
if r.payloadIterator != nil {
|
||||
payload, ok := r.payloadIterator.Value()
|
||||
if !ok {
|
||||
r.currentIndex++
|
||||
r.payloadIterator.Reset()
|
||||
hasPayloadIterator := r.payloadIterator != nil
|
||||
hasInitializedPayloads := r.currentPayloads != nil
|
||||
|
||||
// No more payloads request for us now.
|
||||
if len(r.request.Path) == r.currentIndex {
|
||||
return "", nil, false
|
||||
if r.currentIndex == 0 && hasPayloadIterator && !hasInitializedPayloads {
|
||||
r.currentPayloads, r.okCurrentPayload = r.payloadIterator.Value()
|
||||
}
|
||||
if r.currentIndex < len(sequence) {
|
||||
currentRequest := sequence[r.currentIndex]
|
||||
r.currentIndex++
|
||||
return currentRequest, r.currentPayloads, true
|
||||
}
|
||||
if r.currentIndex == len(sequence) {
|
||||
if r.okCurrentPayload {
|
||||
r.currentIndex = 0
|
||||
currentRequest := sequence[r.currentIndex]
|
||||
if hasPayloadIterator {
|
||||
r.currentPayloads, r.okCurrentPayload = r.payloadIterator.Value()
|
||||
if r.okCurrentPayload {
|
||||
r.currentIndex++
|
||||
return currentRequest, r.currentPayloads, true
|
||||
}
|
||||
if item := r.request.Path[r.currentIndex]; item != "" {
|
||||
newPayload, ok := r.payloadIterator.Value()
|
||||
return item, newPayload, ok
|
||||
}
|
||||
return "", nil, false
|
||||
}
|
||||
return r.request.Path[r.currentIndex], payload, true
|
||||
}
|
||||
if value := r.request.Path[r.currentIndex]; value != "" {
|
||||
r.currentIndex++
|
||||
return value, nil, true
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.request.Raw) > 0 && r.currentIndex < len(r.request.Raw) {
|
||||
if r.payloadIterator != nil {
|
||||
payload, ok := r.payloadIterator.Value()
|
||||
if !ok {
|
||||
r.currentIndex++
|
||||
r.payloadIterator.Reset()
|
||||
|
||||
// No more payloads request for us now.
|
||||
if len(r.request.Raw) == r.currentIndex {
|
||||
return "", nil, false
|
||||
}
|
||||
if item := r.request.Raw[r.currentIndex]; item != "" {
|
||||
newPayload, ok := r.payloadIterator.Value()
|
||||
return item, newPayload, ok
|
||||
}
|
||||
return "", nil, false
|
||||
}
|
||||
return r.request.Raw[r.currentIndex], payload, true
|
||||
}
|
||||
if item := r.request.Raw[r.currentIndex]; item != "" {
|
||||
r.currentIndex++
|
||||
return item, nil, true
|
||||
}
|
||||
}
|
||||
return "", nil, false
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@ type AwsSignerArgs struct {
|
||||
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")
|
||||
@ -56,7 +58,7 @@ func NewAwsSigner(args AwsSignerArgs) (*AwsSigner, error) {
|
||||
}
|
||||
creds := credentials.NewStaticCredentials(args.AwsId, args.AwsSecretToken, "")
|
||||
if creds == nil {
|
||||
return nil, errors.New("couldn't create the credentials structure")
|
||||
return nil, credentialCreationError
|
||||
}
|
||||
signer := v4.NewSigner(creds)
|
||||
return &AwsSigner{creds: creds, signer: signer}, nil
|
||||
@ -65,7 +67,7 @@ func NewAwsSigner(args AwsSignerArgs) (*AwsSigner, error) {
|
||||
func NewAwsSignerFromEnv() (*AwsSigner, error) {
|
||||
creds := credentials.NewEnvCredentials()
|
||||
if creds == nil {
|
||||
return nil, errors.New("couldn't create the credentials structure")
|
||||
return nil, credentialCreationError
|
||||
}
|
||||
signer := v4.NewSigner(creds)
|
||||
return &AwsSigner{creds: creds, signer: signer}, nil
|
||||
@ -74,7 +76,7 @@ func NewAwsSignerFromEnv() (*AwsSigner, error) {
|
||||
func NewAwsSignerFromFile() (*AwsSigner, error) {
|
||||
creds := credentials.NewSharedCredentials("", "")
|
||||
if creds == nil {
|
||||
return nil, errors.New("couldn't create the credentials structure")
|
||||
return nil, credentialCreationError
|
||||
}
|
||||
signer := v4.NewSigner(creds)
|
||||
return &AwsSigner{creds: creds, signer: signer}, nil
|
||||
|
||||
@ -86,6 +86,11 @@ type Input struct {
|
||||
Name string `yaml:"name,omitempty" jsonschema:"title=optional name for data read,description=Optional name of the data read to provide matching on"`
|
||||
}
|
||||
|
||||
const (
|
||||
parseUrlErrorMessage = "could not parse input url"
|
||||
evaluateTemplateExpressionErrorMessage = "could not evaluate template expressions"
|
||||
)
|
||||
|
||||
// Compile compiles the request generators preparing any requests possible.
|
||||
func (request *Request) Compile(options *protocols.ExecuterOptions) error {
|
||||
request.options = options
|
||||
@ -164,7 +169,7 @@ func (request *Request) executeRequestWithPayloads(input, hostname string, dynam
|
||||
}
|
||||
parsed, err := url.Parse(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse input url")
|
||||
return errors.Wrap(err, parseUrlErrorMessage)
|
||||
}
|
||||
payloadValues["Hostname"] = parsed.Host
|
||||
payloadValues["Host"] = parsed.Hostname()
|
||||
@ -181,22 +186,26 @@ func (request *Request) executeRequestWithPayloads(input, hostname string, dynam
|
||||
if dataErr != nil {
|
||||
requestOptions.Output.Request(requestOptions.TemplateID, input, request.Type().String(), dataErr)
|
||||
requestOptions.Progress.IncrementFailedRequestsBy(1)
|
||||
return errors.Wrap(dataErr, "could not evaluate template expressions")
|
||||
return errors.Wrap(dataErr, evaluateTemplateExpressionErrorMessage)
|
||||
}
|
||||
header.Set(key, string(finalData))
|
||||
}
|
||||
tlsConfig := &tls.Config{InsecureSkipVerify: true, ServerName: hostname}
|
||||
if requestOptions.Options.SNI != "" {
|
||||
tlsConfig.ServerName = requestOptions.Options.SNI
|
||||
}
|
||||
websocketDialer := ws.Dialer{
|
||||
Header: ws.HandshakeHeaderHTTP(header),
|
||||
Timeout: time.Duration(requestOptions.Options.Timeout) * time.Second,
|
||||
NetDial: request.dialer.Dial,
|
||||
TLSConfig: &tls.Config{InsecureSkipVerify: true, ServerName: hostname},
|
||||
TLSConfig: tlsConfig,
|
||||
}
|
||||
|
||||
finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues)
|
||||
if dataErr != nil {
|
||||
requestOptions.Output.Request(requestOptions.TemplateID, input, request.Type().String(), dataErr)
|
||||
requestOptions.Progress.IncrementFailedRequestsBy(1)
|
||||
return errors.Wrap(dataErr, "could not evaluate template expressions")
|
||||
return errors.Wrap(dataErr, evaluateTemplateExpressionErrorMessage)
|
||||
}
|
||||
|
||||
addressToDial := string(finalAddress)
|
||||
@ -204,7 +213,7 @@ func (request *Request) executeRequestWithPayloads(input, hostname string, dynam
|
||||
if err != nil {
|
||||
requestOptions.Output.Request(requestOptions.TemplateID, input, request.Type().String(), err)
|
||||
requestOptions.Progress.IncrementFailedRequestsBy(1)
|
||||
return errors.Wrap(err, "could not parse input url")
|
||||
return errors.Wrap(err, parseUrlErrorMessage)
|
||||
}
|
||||
parsedAddress.Path = path.Join(parsedAddress.Path, parsed.Path)
|
||||
addressToDial = parsedAddress.String()
|
||||
@ -279,7 +288,7 @@ func (request *Request) readWriteInputWebsocket(conn net.Conn, payloadValues map
|
||||
if dataErr != nil {
|
||||
requestOptions.Output.Request(requestOptions.TemplateID, input, request.Type().String(), dataErr)
|
||||
requestOptions.Progress.IncrementFailedRequestsBy(1)
|
||||
return nil, "", errors.Wrap(dataErr, "could not evaluate template expressions")
|
||||
return nil, "", errors.Wrap(dataErr, evaluateTemplateExpressionErrorMessage)
|
||||
}
|
||||
reqBuilder.WriteString(string(finalData))
|
||||
|
||||
@ -323,7 +332,7 @@ func (request *Request) readWriteInputWebsocket(conn net.Conn, payloadValues map
|
||||
func getAddress(toTest string) (string, error) {
|
||||
parsed, err := url.Parse(toTest)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "could not parse input url")
|
||||
return "", errors.Wrap(err, parseUrlErrorMessage)
|
||||
}
|
||||
scheme := strings.ToLower(parsed.Scheme)
|
||||
|
||||
|
||||
@ -63,6 +63,7 @@ func New(option *Options) (*Exporter, error) {
|
||||
MaxIdleConns: 10,
|
||||
MaxIdleConnsPerHost: 10,
|
||||
DialContext: protocolstate.Dialer.Dial,
|
||||
DialTLSContext: protocolstate.Dialer.DialTLS,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: option.SSLVerification},
|
||||
},
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/owenrumney/go-sarif/sarif"
|
||||
"github.com/owenrumney/go-sarif/v2/sarif"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||
@ -44,7 +44,7 @@ func New(options *Options) (*Exporter, error) {
|
||||
return nil, errors.Wrap(err, "could not template path")
|
||||
}
|
||||
|
||||
run := sarif.NewRun("nuclei", "https://github.com/projectdiscovery/nuclei")
|
||||
run := sarif.NewRunWithInformationURI("nuclei", "https://github.com/projectdiscovery/nuclei")
|
||||
return &Exporter{options: options, home: templatePath, sarif: report, run: run, mutex: &sync.Mutex{}}, nil
|
||||
}
|
||||
|
||||
@ -56,9 +56,6 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
|
||||
_, _ = h.Write([]byte(event.Host))
|
||||
templateID := event.TemplateID + "-" + hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
fullDescription := format.MarkdownDescription(event)
|
||||
sarifSeverity := getSarifSeverity(event)
|
||||
|
||||
var ruleName string
|
||||
if utils.IsNotBlank(event.Info.Name) {
|
||||
ruleName = event.Info.Name
|
||||
@ -81,25 +78,27 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
|
||||
|
||||
_ = exporter.run.AddRule(templateID).
|
||||
WithDescription(ruleName).
|
||||
WithHelp(fullDescription).
|
||||
WithHelp(sarif.NewMarkdownMultiformatMessageString(format.MarkdownDescription(event))).
|
||||
WithHelpURI(templateURL).
|
||||
WithFullDescription(sarif.NewMultiformatMessageString(ruleDescription))
|
||||
|
||||
result := exporter.run.AddResult(templateID).
|
||||
WithMessage(sarif.NewMessage().WithText(event.Host)).
|
||||
WithLevel(sarifSeverity)
|
||||
result := sarif.NewRuleResult(templateID).
|
||||
WithMessage(sarif.NewTextMessage(event.Host)).
|
||||
WithLevel(getSarifSeverity(event))
|
||||
|
||||
exporter.run.AddResult(result)
|
||||
|
||||
// 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.WithLocation(sarif.NewLocation().WithMessage(sarif.NewMessage().WithText(ruleName)).WithPhysicalLocation(
|
||||
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)),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
result.WithLocation(sarif.NewLocation().WithMessage(sarif.NewMessage().WithText(event.Host)).WithPhysicalLocation(
|
||||
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)),
|
||||
|
||||
@ -14,6 +14,7 @@ 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)
|
||||
@ -53,20 +54,18 @@ func MarkdownDescription(event *output.ResultEvent) string { // TODO remove the
|
||||
builder.WriteString(ToMarkdownTableString(&event.Info))
|
||||
|
||||
if event.Request != "" {
|
||||
builder.WriteString("\n**Request**\n\n```http\n")
|
||||
builder.WriteString(types.ToHexOrString(event.Request))
|
||||
builder.WriteString("\n```\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Request", types.ToHexOrString(event.Request), "http"))
|
||||
}
|
||||
if event.Response != "" {
|
||||
builder.WriteString("\n**Response**\n\n```http\n")
|
||||
var responseString string
|
||||
// If the response is larger than 5 kb, truncate it before writing.
|
||||
if len(event.Response) > 5*1024 {
|
||||
builder.WriteString(event.Response[:5*1024])
|
||||
builder.WriteString(".... Truncated ....")
|
||||
responseString = (event.Response[:5*1024])
|
||||
responseString += ".... Truncated ...."
|
||||
} else {
|
||||
builder.WriteString(event.Response)
|
||||
responseString = event.Response
|
||||
}
|
||||
builder.WriteString("\n```\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Response", responseString, "http"))
|
||||
}
|
||||
|
||||
if len(event.ExtractedResults) > 0 || len(event.Metadata) > 0 {
|
||||
@ -107,14 +106,10 @@ func MarkdownDescription(event *output.ResultEvent) string { // TODO remove the
|
||||
builder.WriteString(event.Interaction.UniqueID)
|
||||
|
||||
if event.Interaction.RawRequest != "" {
|
||||
builder.WriteString("\n\n**Interaction Request**\n\n```\n")
|
||||
builder.WriteString(event.Interaction.RawRequest)
|
||||
builder.WriteString("\n```\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Interaction Request", event.Interaction.RawRequest, ""))
|
||||
}
|
||||
if event.Interaction.RawResponse != "" {
|
||||
builder.WriteString("\n**Interaction Response**\n\n```\n")
|
||||
builder.WriteString(event.Interaction.RawResponse)
|
||||
builder.WriteString("\n```\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Interaction Response", event.Interaction.RawResponse, ""))
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,3 +232,11 @@ func generateCVECWEIDLinksFromClassification(classification *model.Classificatio
|
||||
fields.Set("CVE-ID", strings.Join(cveIDs, ","))
|
||||
}
|
||||
}
|
||||
|
||||
func createMarkdownCodeBlock(title string, content string, language string) string {
|
||||
return "\n" + createBoldMarkdown(title) + "\n```" + language + "\n" + content + "\n```\n"
|
||||
}
|
||||
|
||||
func createBoldMarkdown(value string) string {
|
||||
return "**" + value + "**"
|
||||
}
|
||||
|
||||
@ -47,6 +47,11 @@ type Filter struct {
|
||||
Tags stringslice.StringSlice `yaml:"tags"`
|
||||
}
|
||||
|
||||
const (
|
||||
reportingClientCreationErrorMessage = "could not create reporting client"
|
||||
exportClientCreationErrorMessage = "could not create exporting client"
|
||||
)
|
||||
|
||||
// GetMatch returns true if a filter matches result event
|
||||
func (filter *Filter) GetMatch(event *output.ResultEvent) bool {
|
||||
return isSeverityMatch(event, filter) && isTagMatch(event, filter) // TODO revisit this
|
||||
@ -113,7 +118,7 @@ func New(options *Options, db string) (*Client, error) {
|
||||
options.GitHub.HttpClient = options.HttpClient
|
||||
tracker, err := github.New(options.GitHub)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create reporting client")
|
||||
return nil, errors.Wrap(err, reportingClientCreationErrorMessage)
|
||||
}
|
||||
client.trackers = append(client.trackers, tracker)
|
||||
}
|
||||
@ -121,7 +126,7 @@ func New(options *Options, db string) (*Client, error) {
|
||||
options.GitLab.HttpClient = options.HttpClient
|
||||
tracker, err := gitlab.New(options.GitLab)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create reporting client")
|
||||
return nil, errors.Wrap(err, reportingClientCreationErrorMessage)
|
||||
}
|
||||
client.trackers = append(client.trackers, tracker)
|
||||
}
|
||||
@ -129,21 +134,21 @@ func New(options *Options, db string) (*Client, error) {
|
||||
options.Jira.HttpClient = options.HttpClient
|
||||
tracker, err := jira.New(options.Jira)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create reporting client")
|
||||
return nil, errors.Wrap(err, reportingClientCreationErrorMessage)
|
||||
}
|
||||
client.trackers = append(client.trackers, tracker)
|
||||
}
|
||||
if options.MarkdownExporter != nil {
|
||||
exporter, err := markdown.New(options.MarkdownExporter)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create exporting client")
|
||||
return nil, errors.Wrap(err, exportClientCreationErrorMessage)
|
||||
}
|
||||
client.exporters = append(client.exporters, exporter)
|
||||
}
|
||||
if options.SarifExporter != nil {
|
||||
exporter, err := sarif.New(options.SarifExporter)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create exporting client")
|
||||
return nil, errors.Wrap(err, exportClientCreationErrorMessage)
|
||||
}
|
||||
client.exporters = append(client.exporters, exporter)
|
||||
}
|
||||
@ -151,7 +156,7 @@ func New(options *Options, db string) (*Client, error) {
|
||||
options.ElasticsearchExporter.HttpClient = options.HttpClient
|
||||
exporter, err := es.New(options.ElasticsearchExporter)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create exporting client")
|
||||
return nil, errors.Wrap(err, exportClientCreationErrorMessage)
|
||||
}
|
||||
client.exporters = append(client.exporters, exporter)
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ type Options struct {
|
||||
HttpClient *retryablehttp.Client
|
||||
}
|
||||
|
||||
|
||||
// New creates a new issue tracker integration client based on options.
|
||||
func New(options *Options) (*Integration, error) {
|
||||
username := options.Email
|
||||
@ -185,9 +186,7 @@ func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove th
|
||||
builder.WriteString("\n\n*Template Information*\n\n| Key | Value |\n")
|
||||
builder.WriteString(format.ToMarkdownTableString(&event.Info))
|
||||
|
||||
builder.WriteString("\n*Request*\n\n{code}\n")
|
||||
builder.WriteString(event.Request)
|
||||
builder.WriteString("\n{code}\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Request", event.Request))
|
||||
|
||||
builder.WriteString("\n*Response*\n\n{code}\n")
|
||||
// If the response is larger than 5 kb, truncate it before writing.
|
||||
@ -236,14 +235,10 @@ func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove th
|
||||
builder.WriteString(event.Interaction.UniqueID)
|
||||
|
||||
if event.Interaction.RawRequest != "" {
|
||||
builder.WriteString("\n\n*Interaction Request*\n\n{code}\n")
|
||||
builder.WriteString(event.Interaction.RawRequest)
|
||||
builder.WriteString("\n{code}\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Interaction Request", event.Interaction.RawRequest))
|
||||
}
|
||||
if event.Interaction.RawResponse != "" {
|
||||
builder.WriteString("\n*Interaction Response*\n\n{code}\n")
|
||||
builder.WriteString(event.Interaction.RawResponse)
|
||||
builder.WriteString("\n{code}\n")
|
||||
builder.WriteString(createMarkdownCodeBlock("Interaction Response", event.Interaction.RawResponse))
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,3 +266,11 @@ func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove th
|
||||
data := builder.String()
|
||||
return data
|
||||
}
|
||||
|
||||
func createMarkdownCodeBlock(title string, content string) string {
|
||||
return "\n" + createBoldMarkdown(title) + "\n" + content + "*\n\n{code}"
|
||||
}
|
||||
|
||||
func createBoldMarkdown(value string) string {
|
||||
return "*" + value + "*\n\n{code}"
|
||||
}
|
||||
|
||||
@ -16,9 +16,9 @@ const DefaultResumeFileName = "resume-%s.cfg"
|
||||
func DefaultResumeFilePath() string {
|
||||
configDir, err := config.GetConfigDir()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("resume-%s.cfg", xid.New().String())
|
||||
return fmt.Sprintf(DefaultResumeFileName, xid.New().String())
|
||||
}
|
||||
resumeFile := filepath.Join(configDir, fmt.Sprintf("resume-%s.cfg", xid.New().String()))
|
||||
resumeFile := filepath.Join(configDir, fmt.Sprintf(DefaultResumeFileName, xid.New().String()))
|
||||
return resumeFile
|
||||
}
|
||||
|
||||
|
||||
@ -214,6 +214,8 @@ type Options struct {
|
||||
StoreResponseDir string
|
||||
// DisableRedirects disables following redirects for http request module
|
||||
DisableRedirects bool
|
||||
// SNI custom hostname
|
||||
SNI string
|
||||
}
|
||||
|
||||
func (options *Options) AddVarPayload(key string, value interface{}) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user