From d14c00fc6f277477792a28b01520c001990aa5ce Mon Sep 17 00:00:00 2001
From: Sami <85764322+LuitelSamikshya@users.noreply.github.com>
Date: Wed, 17 Aug 2022 08:10:27 -0500
Subject: [PATCH 01/25] added validation for headless templates (#2423)
* added validation for headless templates
* minor update in log msg
---
v2/pkg/catalog/loader/loader.go | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/v2/pkg/catalog/loader/loader.go b/v2/pkg/catalog/loader/loader.go
index a1679cbd1..87b54c257 100644
--- a/v2/pkg/catalog/loader/loader.go
+++ b/v2/pkg/catalog/loader/loader.go
@@ -267,7 +267,11 @@ func (store *Store) LoadTemplates(templatesList []string) []*templates.Template
stats.Increment(parsers.RuntimeWarningsStats)
gologger.Warning().Msgf("Could not parse template %s: %s\n", templatePath, err)
} else if parsed != nil {
- loadedTemplates = append(loadedTemplates, parsed)
+ if len(parsed.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
+ gologger.Warning().Msgf("Headless flag is required for headless template %s\n", templatePath)
+ } else {
+ loadedTemplates = append(loadedTemplates, parsed)
+ }
}
} else if err != nil {
gologger.Warning().Msgf("Could not load template %s: %s\n", templatePath, err)
@@ -314,7 +318,11 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
stats.Increment(parsers.RuntimeWarningsStats)
gologger.Warning().Msgf("Could not parse template %s: %s\n", templatePath, err)
} else if parsed != nil {
- loadedTemplates = append(loadedTemplates, parsed)
+ if len(parsed.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
+ gologger.Warning().Msgf("Headless flag is required for headless template %s\n", templatePath)
+ } else {
+ loadedTemplates = append(loadedTemplates, parsed)
+ }
}
} else if err != nil {
gologger.Warning().Msgf("Could not load template %s: %s\n", templatePath, err)
From c1a99ae452553e1b852b1398e81e09f4d36c8623 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 22 Aug 2022 15:13:03 +0530
Subject: [PATCH 02/25] chore(deps): bump
github.com/projectdiscovery/wappalyzergo in /v2 (#2469)
Bumps [github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) from 0.0.55 to 0.0.56.
- [Release notes](https://github.com/projectdiscovery/wappalyzergo/releases)
- [Commits](https://github.com/projectdiscovery/wappalyzergo/compare/v0.0.55...v0.0.56)
---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/wappalyzergo
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 2 +-
v2/go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index d18b96ee7..4bc49ddc8 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -77,7 +77,7 @@ require (
github.com/projectdiscovery/nvd v1.0.9
github.com/projectdiscovery/sliceutil v0.0.0-20220511171050-c7d9bc5cadd9
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921
- github.com/projectdiscovery/wappalyzergo v0.0.55
+ github.com/projectdiscovery/wappalyzergo v0.0.56
github.com/stretchr/testify v1.8.0
github.com/zmap/zcrypto v0.0.0-20211005224000-2d0ffdec8a9b
gopkg.in/yaml.v3 v3.0.1
diff --git a/v2/go.sum b/v2/go.sum
index a47ac5ab6..291e7b3f8 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -584,8 +584,8 @@ github.com/projectdiscovery/stringsutil v0.0.0-20220612082425-0037ce9f89f3 h1:Eb
github.com/projectdiscovery/stringsutil v0.0.0-20220612082425-0037ce9f89f3/go.mod h1:mF5sh4jTghoGWwgUb9qWi5waTFklClDbtrqtJU93awc=
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.55 h1:dDWuohTrAUWrphnFB+uAL33QrDWBbdM+z7sTzSxy8PY=
-github.com/projectdiscovery/wappalyzergo v0.0.55/go.mod h1:9aSADdt5z/pw9LFZF7Q8RrLnkyqZl1H4Ezivi8Td7l0=
+github.com/projectdiscovery/wappalyzergo v0.0.56 h1:774LsI8tAUAYROQhTX9VsxoQN2kAC5m9CcNj3BHsvTs=
+github.com/projectdiscovery/wappalyzergo v0.0.56/go.mod h1:9aSADdt5z/pw9LFZF7Q8RrLnkyqZl1H4Ezivi8Td7l0=
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=
From c184b84ebf6c79c21c76550bd8a1f62b5359b325 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 22 Aug 2022 15:13:40 +0530
Subject: [PATCH 03/25] chore(deps): bump github.com/aws/aws-sdk-go in /v2
(#2468)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.44.77 to 1.44.81.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.44.77...v1.44.81)
---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 2 +-
v2/go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index 4bc49ddc8..12dca62ae 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -59,7 +59,7 @@ require (
moul.io/http2curl v1.0.0
)
-require github.com/aws/aws-sdk-go v1.44.77
+require github.com/aws/aws-sdk-go v1.44.81
require github.com/projectdiscovery/folderutil v0.0.0-20220215113126-add60a1e8e08
diff --git a/v2/go.sum b/v2/go.sum
index 291e7b3f8..95cdbfcce 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -112,8 +112,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.77 h1:m5rTfdv04/swD+vTuS2zn4NEwKX3yEJPMhiVCFDL/mU=
-github.com/aws/aws-sdk-go v1.44.77/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.81 h1:C8oBZ+a+ka0qk3Q24MohQIFq0tkbO8IAu5tfpAMKVWE=
+github.com/aws/aws-sdk-go v1.44.81/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
From 2ae7e58c83d07c8ab246b84d5bd82915a75403fb Mon Sep 17 00:00:00 2001
From: xixijun
Date: Mon, 22 Aug 2022 17:48:45 +0800
Subject: [PATCH 04/25] Fix socks5 proxy not working on tor proxy (#2455)
* fix: socks5 proxy not working on tor proxy
* fix: socks5 proxy not working on tor proxy
* minor refactoring
Co-authored-by: Sandeep Singh
Co-authored-by: Mzack9999
---
v2/pkg/protocols/headless/engine/http_client.go | 17 ++++++++---------
.../protocols/http/httpclientpool/clientpool.go | 17 ++++++++---------
2 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/v2/pkg/protocols/headless/engine/http_client.go b/v2/pkg/protocols/headless/engine/http_client.go
index 89e7eafa4..ea32aa5e3 100644
--- a/v2/pkg/protocols/headless/engine/http_client.go
+++ b/v2/pkg/protocols/headless/engine/http_client.go
@@ -3,18 +3,16 @@ package engine
import (
"context"
"crypto/tls"
- "fmt"
"net"
"net/http"
"net/http/cookiejar"
"net/url"
"time"
- "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
-
"golang.org/x/net/proxy"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
@@ -53,14 +51,15 @@ func newHttpClient(options *types.Options) (*http.Client, error) {
transport.Proxy = http.ProxyURL(proxyURL)
}
} else if types.ProxySocksURL != "" {
- var proxyAuth *proxy.Auth
socksURL, proxyErr := url.Parse(types.ProxySocksURL)
- if proxyErr == nil {
- proxyAuth = &proxy.Auth{}
- proxyAuth.User = socksURL.User.Username()
- proxyAuth.Password, _ = socksURL.User.Password()
+ if proxyErr != nil {
+ return nil, err
}
- dialer, proxyErr := proxy.SOCKS5("tcp", fmt.Sprintf("%s:%s", socksURL.Hostname(), socksURL.Port()), proxyAuth, proxy.Direct)
+ dialer, err := proxy.FromURL(socksURL, proxy.Direct)
+ if err != nil {
+ return nil, err
+ }
+
dc := dialer.(interface {
DialContext(ctx context.Context, network, addr string) (net.Conn, error)
})
diff --git a/v2/pkg/protocols/http/httpclientpool/clientpool.go b/v2/pkg/protocols/http/httpclientpool/clientpool.go
index ff53d54a4..393f70c06 100644
--- a/v2/pkg/protocols/http/httpclientpool/clientpool.go
+++ b/v2/pkg/protocols/http/httpclientpool/clientpool.go
@@ -3,7 +3,6 @@ package httpclientpool
import (
"context"
"crypto/tls"
- "fmt"
"net"
"net/http"
"net/http/cookiejar"
@@ -13,14 +12,13 @@ import (
"sync"
"time"
- "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
-
"github.com/pkg/errors"
"golang.org/x/net/proxy"
"golang.org/x/net/publicsuffix"
"github.com/projectdiscovery/fastdialer/fastdialer"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/rawhttp"
"github.com/projectdiscovery/retryablehttp-go"
@@ -210,14 +208,15 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
transport.Proxy = http.ProxyURL(proxyURL)
}
} else if types.ProxySocksURL != "" {
- var proxyAuth *proxy.Auth
socksURL, proxyErr := url.Parse(types.ProxySocksURL)
- if proxyErr == nil {
- proxyAuth = &proxy.Auth{}
- proxyAuth.User = socksURL.User.Username()
- proxyAuth.Password, _ = socksURL.User.Password()
+ if proxyErr != nil {
+ return nil, proxyErr
}
- dialer, proxyErr := proxy.SOCKS5("tcp", fmt.Sprintf("%s:%s", socksURL.Hostname(), socksURL.Port()), proxyAuth, proxy.Direct)
+ dialer, err := proxy.FromURL(socksURL, proxy.Direct)
+ if err != nil {
+ return nil, err
+ }
+
dc := dialer.(interface {
DialContext(ctx context.Context, network, addr string) (net.Conn, error)
})
From 419924188b137087bc0986352a062e4c3ec5dddb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 22 Aug 2022 15:19:30 +0530
Subject: [PATCH 05/25] chore(deps): bump github.com/andygrunwald/go-jira in
/v2 (#2470)
Bumps [github.com/andygrunwald/go-jira](https://github.com/andygrunwald/go-jira) from 1.15.1 to 1.16.0.
- [Release notes](https://github.com/andygrunwald/go-jira/releases)
- [Changelog](https://github.com/andygrunwald/go-jira/blob/main/CHANGELOG.md)
- [Commits](https://github.com/andygrunwald/go-jira/compare/v1.15.1...v1.16.0)
---
updated-dependencies:
- dependency-name: github.com/andygrunwald/go-jira
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 4 ++--
v2/go.sum | 9 +++++----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index 12dca62ae..23c7013cf 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -5,7 +5,7 @@ go 1.17
require (
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725
- github.com/andygrunwald/go-jira v1.15.1
+ github.com/andygrunwald/go-jira v1.16.0
github.com/antchfx/htmlquery v1.2.5
github.com/apex/log v1.9.0
github.com/blang/semver v3.5.1+incompatible
@@ -110,7 +110,7 @@ require (
github.com/goburrow/cache v0.1.4 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
- github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
+ github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
diff --git a/v2/go.sum b/v2/go.sum
index 95cdbfcce..ad05b0995 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -93,8 +93,8 @@ github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgp
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/andygrunwald/go-jira v1.14.0/go.mod h1:KMo2f4DgMZA1C9FdImuLc04x4WQhn5derQpnsuBFgqE=
-github.com/andygrunwald/go-jira v1.15.1 h1:6J9aYKb9sW8bxv3pBLYBrs0wdsFrmGI5IeTgWSKWKc8=
-github.com/andygrunwald/go-jira v1.15.1/go.mod h1:GIYN1sHOIsENWUZ7B4pDeT/nxEtrZpE8l0987O67ZR8=
+github.com/andygrunwald/go-jira v1.16.0 h1:PU7C7Fkk5L96JvPc6vDVIrd99vdPnYudHu4ju2c2ikQ=
+github.com/andygrunwald/go-jira v1.16.0/go.mod h1:UQH4IBVxIYWbgagc0LF/k9FRs9xjIiQ8hIcC6HfLwFU=
github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0=
github.com/antchfx/htmlquery v1.2.5 h1:1lXnx46/1wtv1E/kzmH8vrfMuUKYgkdDBA9pIdMJnk4=
github.com/antchfx/htmlquery v1.2.5/go.mod h1:2MCVBzYVafPBmKbrmwB9F5xdd+IEgRY61ci2oOsOQVw=
@@ -230,8 +230,8 @@ github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
-github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
-github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
+github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -982,6 +982,7 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
From 8670c8b20d4de7887dcd3d2cac24908a2a4be71b Mon Sep 17 00:00:00 2001
From: Dani Goland
Date: Mon, 22 Aug 2022 02:57:32 -0700
Subject: [PATCH 06/25] Modified "xpath" extractor to support XML XPath in
addition to HTML XPath (#2471)
* Modified "xpath" extractor to support XML XPath in addition to HTML XPath
* Updated function docs
---
v2/go.mod | 1 +
v2/go.sum | 2 ++
v2/pkg/operators/extractors/extract.go | 44 ++++++++++++++++++++++++--
v2/pkg/protocols/http/operators.go | 2 +-
v2/pkg/protocols/protocols.go | 2 +-
5 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index 23c7013cf..b7de3cb2f 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -65,6 +65,7 @@ require github.com/projectdiscovery/folderutil v0.0.0-20220215113126-add60a1e8e0
require (
github.com/DataDog/gostackparse v0.5.0
+ github.com/antchfx/xmlquery v1.3.12
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/docker/go-units v0.4.0
github.com/h2non/filetype v1.1.3
diff --git a/v2/go.sum b/v2/go.sum
index ad05b0995..f9062f0fc 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -98,6 +98,8 @@ github.com/andygrunwald/go-jira v1.16.0/go.mod h1:UQH4IBVxIYWbgagc0LF/k9FRs9xjIi
github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0=
github.com/antchfx/htmlquery v1.2.5 h1:1lXnx46/1wtv1E/kzmH8vrfMuUKYgkdDBA9pIdMJnk4=
github.com/antchfx/htmlquery v1.2.5/go.mod h1:2MCVBzYVafPBmKbrmwB9F5xdd+IEgRY61ci2oOsOQVw=
+github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBTQ4=
+github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ=
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
diff --git a/v2/pkg/operators/extractors/extract.go b/v2/pkg/operators/extractors/extract.go
index e8fafc3ba..d5c948ef2 100644
--- a/v2/pkg/operators/extractors/extract.go
+++ b/v2/pkg/operators/extractors/extract.go
@@ -3,9 +3,9 @@ package extractors
import (
"encoding/json"
"fmt"
- "strings"
-
"github.com/antchfx/htmlquery"
+ "github.com/antchfx/xmlquery"
+ "strings"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
@@ -59,7 +59,15 @@ func (e *Extractor) ExtractKval(data map[string]interface{}) map[string]struct{}
return results
}
-// ExtractHTML extracts items from text using XPath selectors
+// ExtractXPath extracts items from text using XPath selectors
+func (e *Extractor) ExtractXPath(corpus string) map[string]struct{} {
+ if strings.HasPrefix(corpus, "
Date: Mon, 22 Aug 2022 18:11:08 +0530
Subject: [PATCH 07/25] Added reference based tag addition to templates (#2464)
* Added reference based tag addition to templates
* reference mapping list update
* Misc changes as per review
Co-authored-by: sandeep
---
v2/cmd/cve-annotate/main.go | 79 +++++++++++++++++++++++++++++++++++--
1 file changed, 75 insertions(+), 4 deletions(-)
diff --git a/v2/cmd/cve-annotate/main.go b/v2/cmd/cve-annotate/main.go
index f64bb9d87..46df7d149 100644
--- a/v2/cmd/cve-annotate/main.go
+++ b/v2/cmd/cve-annotate/main.go
@@ -8,6 +8,7 @@ import (
"io/ioutil"
"log"
"net/http"
+ "net/url"
"os"
"regexp"
"strings"
@@ -71,7 +72,16 @@ func process() error {
if err != nil {
return err
}
- getCVEData(client, path, string(data))
+ dataString := string(data)
+
+ // First try to resolve references to tags
+ dataString, err = parseAndAddReferenceBasedTags(path, dataString)
+ if err != nil {
+ log.Printf("Could not parse reference tags %s: %s\n", path, err)
+ continue
+ }
+ // Next try and fill CVE data
+ getCVEData(client, path, dataString)
}
return nil
}
@@ -290,12 +300,15 @@ func parseAndAddCISAKevTagTemplate(path string, data string) (string, error) {
return "", errors.Wrap(err, "could not decode template yaml")
}
splitted := strings.Split(block.Info.Tags, ",")
+ if len(splitted) == 0 {
+ return data, nil
+ }
var cisaIndex = -1
for i, tag := range splitted {
// If we already have tag, return
if tag == "kev" {
- return "", nil
+ return data, nil
}
if tag == "cisa" {
cisaIndex = i
@@ -306,11 +319,69 @@ func parseAndAddCISAKevTagTemplate(path string, data string) (string, error) {
splitted = append(splitted[:cisaIndex], splitted[cisaIndex+1:]...)
}
splitted = append(splitted, "kev")
- final := strings.Join(splitted, ",")
- replaced := strings.Replace(data, block.Info.Tags, final, -1)
+ replaced := strings.ReplaceAll(data, block.Info.Tags, strings.Join(splitted, ","))
return replaced, ioutil.WriteFile(path, []byte(replaced), os.ModePerm)
}
+// parseAndAddReferenceBasedTags parses and adds reference based tags to templates
+func parseAndAddReferenceBasedTags(path string, data string) (string, error) {
+ block := &InfoBlock{}
+ if err := yaml.NewDecoder(strings.NewReader(data)).Decode(block); err != nil {
+ return "", errors.Wrap(err, "could not decode template yaml")
+ }
+ splitted := strings.Split(block.Info.Tags, ",")
+ if len(splitted) == 0 {
+ return data, nil
+ }
+ tagsCurrent := fmt.Sprintf("tags: %s", block.Info.Tags)
+ newTags := suggestTagsBasedOnReference(block.Info.Reference, splitted)
+
+ if len(newTags) == len(splitted) {
+ return data, nil
+ }
+ replaced := strings.ReplaceAll(data, tagsCurrent, fmt.Sprintf("tags: %s", strings.Join(newTags, ",")))
+ return replaced, ioutil.WriteFile(path, []byte(replaced), os.ModePerm)
+}
+
+var referenceMapping = map[string]string{
+ "huntr.dev": "huntr",
+ "hackerone.com": "hackerone",
+ "tenable.com": "tenable",
+ "packetstormsecurity.org": "packetstorm",
+ "seclists.org": "seclists",
+ "wpscan.com": "wpscan",
+ "packetstormsecurity.com": "packetstorm",
+ "exploit-db.com": "edb",
+ "https://github.com/rapid7/metasploit-framework/": "msf",
+ "https://github.com/vulhub/vulhub/": "vulhub",
+}
+
+func suggestTagsBasedOnReference(references, currentTags []string) []string {
+ uniqueTags := make(map[string]struct{})
+ for _, value := range currentTags {
+ uniqueTags[value] = struct{}{}
+ }
+
+ for _, reference := range references {
+ parsed, err := url.Parse(reference)
+ if err != nil {
+ continue
+ }
+ hostname := parsed.Hostname()
+
+ for value, tag := range referenceMapping {
+ if strings.HasSuffix(hostname, value) || strings.HasPrefix(reference, value) {
+ uniqueTags[tag] = struct{}{}
+ }
+ }
+ }
+ newTags := make([]string, 0, len(uniqueTags))
+ for tag := range uniqueTags {
+ newTags = append(newTags, tag)
+ }
+ return newTags
+}
+
// Cloning struct from nuclei as we don't want any validation
type InfoBlock struct {
Info TemplateInfo `yaml:"info"`
From e7cffad31205bcd059daec488c7addb95dca084e Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Tue, 23 Aug 2022 12:45:55 +0530
Subject: [PATCH 08/25] Fixed request annotation based timeout bugs + tests +
misc (#2476)
---
.../http/annotation-timeout.yaml | 18 ++++++++
v2/cmd/integration-test/http.go | 21 +++++++++
v2/pkg/protocols/http/build_request.go | 9 +++-
v2/pkg/protocols/http/request_annotations.go | 4 +-
.../http/request_annotations_test.go | 45 +++++++++++++++++++
5 files changed, 93 insertions(+), 4 deletions(-)
create mode 100644 integration_tests/http/annotation-timeout.yaml
create mode 100644 v2/pkg/protocols/http/request_annotations_test.go
diff --git a/integration_tests/http/annotation-timeout.yaml b/integration_tests/http/annotation-timeout.yaml
new file mode 100644
index 000000000..ddb0b3e6a
--- /dev/null
+++ b/integration_tests/http/annotation-timeout.yaml
@@ -0,0 +1,18 @@
+id: annotation-timeout
+
+info:
+ name: Basic Annotation Timeout
+ author: pdteam
+ severity: info
+
+requests:
+ - raw:
+ - |
+ @timeout: 5s
+ GET / HTTP/1.1
+ Host: {{Hostname}}
+
+ matchers:
+ - type: word
+ words:
+ - "This is test matcher text"
\ No newline at end of file
diff --git a/v2/cmd/integration-test/http.go b/v2/cmd/integration-test/http.go
index c4ca5e9a4..0fdf9f566 100644
--- a/v2/cmd/integration-test/http.go
+++ b/v2/cmd/integration-test/http.go
@@ -11,6 +11,7 @@ import (
"regexp"
"strconv"
"strings"
+ "time"
"github.com/julienschmidt/httprouter"
@@ -52,6 +53,7 @@ var httpTestcases = map[string]testutils.TestCase{
"http/get-sni.yaml": &customCLISNI{},
"http/redirect-match-url.yaml": &httpRedirectMatchURL{},
"http/get-sni-unsafe.yaml": &customCLISNIUnsafe{},
+ "http/annotation-timeout.yaml": &annotationTimeout{},
}
type httpInteractshRequest struct{}
@@ -909,3 +911,22 @@ func (h *customCLISNIUnsafe) Execute(filePath string) error {
}
return expectResultsCount(results, 1)
}
+
+type annotationTimeout struct{}
+
+// Execute executes a test case and returns an error if occurred
+func (h *annotationTimeout) Execute(filePath string) error {
+ router := httprouter.New()
+ router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+ time.Sleep(4 * time.Second)
+ fmt.Fprintf(w, "This is test matcher text")
+ })
+ ts := httptest.NewTLSServer(router)
+ defer ts.Close()
+
+ results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-timeout", "1")
+ if err != nil {
+ return err
+ }
+ return expectResultsCount(results, 1)
+}
diff --git a/v2/pkg/protocols/http/build_request.go b/v2/pkg/protocols/http/build_request.go
index 84fb06f27..fc8968be2 100644
--- a/v2/pkg/protocols/http/build_request.go
+++ b/v2/pkg/protocols/http/build_request.go
@@ -26,6 +26,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/rawhttp"
"github.com/projectdiscovery/retryablehttp-go"
+ "github.com/projectdiscovery/stringsutil"
)
var (
@@ -112,10 +113,15 @@ func (r *requestGenerator) makeSelfContainedRequest(ctx context.Context, data st
if isRawRequest {
// Get the hostname from the URL section to build the request.
reader := bufio.NewReader(strings.NewReader(data))
+ read_line:
s, err := reader.ReadString('\n')
if err != nil {
return nil, fmt.Errorf("could not read request: %w", err)
}
+ // ignore all annotations
+ if stringsutil.HasPrefixAny(s, "@") {
+ goto read_line
+ }
parts := strings.Split(s, " ")
if len(parts) < 3 {
@@ -288,8 +294,7 @@ func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest
}
if reqWithAnnotations, hasAnnotations := r.request.parseAnnotations(rawRequest, req); hasAnnotations {
- req = reqWithAnnotations
- request = request.WithContext(req.Context())
+ request.Request = reqWithAnnotations
}
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues, interactshURLs: r.interactshURLs}, nil
diff --git a/v2/pkg/protocols/http/request_annotations.go b/v2/pkg/protocols/http/request_annotations.go
index b14831cb7..0b15c7dac 100644
--- a/v2/pkg/protocols/http/request_annotations.go
+++ b/v2/pkg/protocols/http/request_annotations.go
@@ -102,12 +102,12 @@ func (r *Request) parseAnnotations(rawRequest string, request *http.Request) (*h
value := strings.TrimSpace(duration[1])
if parsed, err := time.ParseDuration(value); err == nil {
//nolint:govet // cancelled automatically by withTimeout
- ctx, _ := context.WithTimeout(request.Context(), parsed)
+ ctx, _ := context.WithTimeout(context.Background(), parsed)
request = request.Clone(ctx)
}
} else {
//nolint:govet // cancelled automatically by withTimeout
- ctx, _ := context.WithTimeout(request.Context(), time.Duration(r.options.Options.Timeout)*time.Second)
+ ctx, _ := context.WithTimeout(context.Background(), time.Duration(r.options.Options.Timeout)*time.Second)
request = request.Clone(ctx)
}
}
diff --git a/v2/pkg/protocols/http/request_annotations_test.go b/v2/pkg/protocols/http/request_annotations_test.go
new file mode 100644
index 000000000..682a923fa
--- /dev/null
+++ b/v2/pkg/protocols/http/request_annotations_test.go
@@ -0,0 +1,45 @@
+package http
+
+import (
+ "context"
+ "net/http"
+ "testing"
+
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRequestParseAnnotationsTimeout(t *testing.T) {
+ t.Run("positive", func(t *testing.T) {
+ request := &Request{
+ connConfiguration: &httpclientpool.Configuration{NoTimeout: true},
+ }
+ rawRequest := `@timeout: 2s
+ GET / HTTP/1.1
+ Host: {{Hostname}}`
+
+ httpReq, err := http.NewRequest(http.MethodGet, "https://example.com", nil)
+ require.Nil(t, err, "could not create http request")
+
+ newRequest, modified := request.parseAnnotations(rawRequest, httpReq)
+ require.True(t, modified, "could not get correct modified value")
+ _, deadlined := newRequest.Context().Deadline()
+ require.True(t, deadlined, "could not get set request deadline")
+ })
+
+ t.Run("negative", func(t *testing.T) {
+ request := &Request{
+ connConfiguration: &httpclientpool.Configuration{},
+ }
+ rawRequest := `GET / HTTP/1.1
+ Host: {{Hostname}}`
+
+ httpReq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://example.com", nil)
+ require.Nil(t, err, "could not create http request")
+
+ newRequest, modified := request.parseAnnotations(rawRequest, httpReq)
+ require.False(t, modified, "could not get correct modified value")
+ _, deadlined := newRequest.Context().Deadline()
+ require.False(t, deadlined, "could not get set request deadline")
+ })
+}
From c3e9e1fe4ae4edb9cb04e49b240d2ea80a989115 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 23 Aug 2022 12:50:27 +0530
Subject: [PATCH 09/25] chore(deps): bump github.com/xanzy/go-gitlab in /v2
(#2478)
Bumps [github.com/xanzy/go-gitlab](https://github.com/xanzy/go-gitlab) from 0.72.0 to 0.73.0.
- [Release notes](https://github.com/xanzy/go-gitlab/releases)
- [Changelog](https://github.com/xanzy/go-gitlab/blob/master/releases_test.go)
- [Commits](https://github.com/xanzy/go-gitlab/compare/v0.72.0...v0.73.0)
---
updated-dependencies:
- dependency-name: github.com/xanzy/go-gitlab
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 2 +-
v2/go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index b7de3cb2f..e73fc013f 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -48,7 +48,7 @@ require (
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.72.0
+ github.com/xanzy/go-gitlab v0.73.0
go.uber.org/atomic v1.9.0
go.uber.org/multierr v1.8.0
go.uber.org/ratelimit v0.2.0
diff --git a/v2/go.sum b/v2/go.sum
index f9062f0fc..29b4810ee 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -688,8 +688,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.72.0 h1:/9BQTftUE7GRK/RO1eeWxG1cOE+tjwBrvRdpkeSOq6w=
-github.com/xanzy/go-gitlab v0.72.0/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=
+github.com/xanzy/go-gitlab v0.73.0 h1:cfqWPU8cGdmH/O+ZzUpkLM5Rb95OmCBNaR1wRG55aR8=
+github.com/xanzy/go-gitlab v0.73.0/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=
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=
From f5f2ee145b07c9379588e167b72bd7a37dc2ae6a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 23 Aug 2022 12:50:41 +0530
Subject: [PATCH 10/25] chore(deps): bump github.com/aws/aws-sdk-go in /v2
(#2479)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.44.81 to 1.44.82.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.44.81...v1.44.82)
---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 2 +-
v2/go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index e73fc013f..893db9162 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -59,7 +59,7 @@ require (
moul.io/http2curl v1.0.0
)
-require github.com/aws/aws-sdk-go v1.44.81
+require github.com/aws/aws-sdk-go v1.44.82
require github.com/projectdiscovery/folderutil v0.0.0-20220215113126-add60a1e8e08
diff --git a/v2/go.sum b/v2/go.sum
index 29b4810ee..27bce4290 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -114,8 +114,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.81 h1:C8oBZ+a+ka0qk3Q24MohQIFq0tkbO8IAu5tfpAMKVWE=
-github.com/aws/aws-sdk-go v1.44.81/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.82 h1:Miji7nHIMxTWfa831nZf8XAcMWGLaT+PvsS6CdbMG7M=
+github.com/aws/aws-sdk-go v1.44.82/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
From 8f313629b803a37c11b8aef37a6b161da9585249 Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Tue, 23 Aug 2022 13:16:41 +0530
Subject: [PATCH 11/25] Memory usage optimizations (#2350)
* Replaced strings.Replaced with fasttemplate reducing allocations
Custom template parsing logic was replaced with fasttemplate package for reducing
allocations in the replacer.Replace hotpath leading to allocation reduction which
accounted for 30% of total nuclei allocations.
$ go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer
BenchmarkReplacer-8 837232 1422 ns/op 2112 B/op 31 allocs/op
BenchmarkReplacerNew-8 3672765 320.3 ns/op 48 B/op 4 allocs/op
* Fixed tests failing
* Use pre-compiled map of DSL expressions
* Reworked expression parsing logic to reduce memory allocations
$ go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions
BenchmarkEvaluate-8 31560 37769 ns/op 31731 B/op 265 allocs/op
BenchmarkEvaluateNew-8 109144 9621 ns/op 6253 B/op 116 allocs/op
---
v2/pkg/operators/common/dsl/dsl.go | 16 +++++-
v2/pkg/operators/common/dsl/dsl_test.go | 16 +++---
v2/pkg/operators/extractors/compile.go | 2 +-
v2/pkg/operators/matchers/compile.go | 2 +-
v2/pkg/operators/matchers/match.go | 2 +-
v2/pkg/operators/matchers/match_test.go | 2 +-
.../common/expressions/expressions.go | 52 +++++--------------
.../protocols/common/expressions/variables.go | 12 +++++
v2/pkg/protocols/common/replacer/replacer.go | 26 +++-------
.../common/replacer/replacer_test.go | 12 +++++
10 files changed, 71 insertions(+), 71 deletions(-)
create mode 100644 v2/pkg/protocols/common/replacer/replacer_test.go
diff --git a/v2/pkg/operators/common/dsl/dsl.go b/v2/pkg/operators/common/dsl/dsl.go
index 1df0763fa..5c5d29a67 100644
--- a/v2/pkg/operators/common/dsl/dsl.go
+++ b/v2/pkg/operators/common/dsl/dsl.go
@@ -50,6 +50,13 @@ var invalidDslFunctionMessageTemplate = "%w. correct method signature %q"
var dslFunctions map[string]dslFunction
+var (
+ // FunctionNames is a list of function names for expression evaluation usages
+ FunctionNames []string
+ // HelperFunctions is a pre-compiled list of govaluate DSL functions
+ HelperFunctions map[string]govaluate.ExpressionFunction
+)
+
var functionSignaturePattern = regexp.MustCompile(`(\w+)\s*\((?:([\w\d,\s]+)\s+([.\w\d{}&*]+))?\)([\s.\w\d{}&*]+)?`)
var dateFormatRegex = regexp.MustCompile("%([A-Za-z])")
@@ -592,6 +599,11 @@ func init() {
for funcName, dslFunc := range tempDslFunctions {
dslFunctions[funcName] = dslFunc(funcName)
}
+ HelperFunctions = helperFunctions()
+ FunctionNames = make([]string, 0, len(HelperFunctions))
+ for k := range HelperFunctions {
+ FunctionNames = append(FunctionNames, k)
+ }
}
func makeDslWithOptionalArgsFunction(signaturePart string, dslFunctionLogic govaluate.ExpressionFunction) func(functionName string) dslFunction {
@@ -626,8 +638,8 @@ func createSignaturePart(numberOfParameters int) string {
return fmt.Sprintf("(%s interface{}) interface{}", strings.Join(params, ", "))
}
-// HelperFunctions returns the dsl helper functions
-func HelperFunctions() map[string]govaluate.ExpressionFunction {
+// helperFunctions returns the dsl helper functions
+func helperFunctions() map[string]govaluate.ExpressionFunction {
helperFunctions := make(map[string]govaluate.ExpressionFunction, len(dslFunctions))
for functionName, dslFunction := range dslFunctions {
diff --git a/v2/pkg/operators/common/dsl/dsl_test.go b/v2/pkg/operators/common/dsl/dsl_test.go
index c5f7a3f4a..f9cd3250c 100644
--- a/v2/pkg/operators/common/dsl/dsl_test.go
+++ b/v2/pkg/operators/common/dsl/dsl_test.go
@@ -15,7 +15,7 @@ import (
)
func TestDSLURLEncodeDecode(t *testing.T) {
- functions := HelperFunctions()
+ functions := HelperFunctions
encoded, err := functions["url_encode"]("&test\"")
require.Nil(t, err, "could not url encode")
@@ -27,7 +27,7 @@ func TestDSLURLEncodeDecode(t *testing.T) {
}
func TestDSLTimeComparison(t *testing.T) {
- compiled, err := govaluate.NewEvaluableExpressionWithFunctions("unixtime() > not_after", HelperFunctions())
+ compiled, err := govaluate.NewEvaluableExpressionWithFunctions("unixtime() > not_after", HelperFunctions)
require.Nil(t, err, "could not compare time")
result, err := compiled.Evaluate(map[string]interface{}{"not_after": float64(time.Now().Unix() - 1000)})
@@ -36,13 +36,13 @@ func TestDSLTimeComparison(t *testing.T) {
}
func TestDSLGzipSerialize(t *testing.T) {
- compiled, err := govaluate.NewEvaluableExpressionWithFunctions("gzip(\"hello world\")", HelperFunctions())
+ compiled, err := govaluate.NewEvaluableExpressionWithFunctions("gzip(\"hello world\")", HelperFunctions)
require.Nil(t, err, "could not compile encoder")
result, err := compiled.Evaluate(make(map[string]interface{}))
require.Nil(t, err, "could not evaluate compare time")
- compiled, err = govaluate.NewEvaluableExpressionWithFunctions("gzip_decode(data)", HelperFunctions())
+ compiled, err = govaluate.NewEvaluableExpressionWithFunctions("gzip_decode(data)", HelperFunctions)
require.Nil(t, err, "could not compile decoder")
data, err := compiled.Evaluate(map[string]interface{}{"data": result})
@@ -68,7 +68,7 @@ func TestDateTimeDSLFunction(t *testing.T) {
}
t.Run("with Unix time", func(t *testing.T) {
- dateTimeFunction, err := govaluate.NewEvaluableExpressionWithFunctions("date_time(dateTimeFormat)", HelperFunctions())
+ dateTimeFunction, err := govaluate.NewEvaluableExpressionWithFunctions("date_time(dateTimeFormat)", HelperFunctions)
require.Nil(t, err, "could not compile encoder")
currentTime := time.Now()
@@ -78,7 +78,7 @@ func TestDateTimeDSLFunction(t *testing.T) {
})
t.Run("without Unix time", func(t *testing.T) {
- dateTimeFunction, err := govaluate.NewEvaluableExpressionWithFunctions("date_time(dateTimeFormat, unixTime)", HelperFunctions())
+ dateTimeFunction, err := govaluate.NewEvaluableExpressionWithFunctions("date_time(dateTimeFormat, unixTime)", HelperFunctions)
require.Nil(t, err, "could not compile encoder")
currentTime := time.Now()
@@ -112,7 +112,7 @@ func TestDslFunctionSignatures(t *testing.T) {
{"remove_bad_chars", []interface{}{"a", "b", "c"}, nil, removeBadCharsSignatureError},
}
- helperFunctions := HelperFunctions()
+ helperFunctions := HelperFunctions
for _, currentTestCase := range testCases {
methodName := currentTestCase.methodName
t.Run(methodName, func(t *testing.T) {
@@ -343,7 +343,7 @@ func TestRandIntDslExpressions(t *testing.T) {
}
func evaluateExpression(t *testing.T, dslExpression string) interface{} {
- compiledExpression, err := govaluate.NewEvaluableExpressionWithFunctions(dslExpression, HelperFunctions())
+ compiledExpression, err := govaluate.NewEvaluableExpressionWithFunctions(dslExpression, HelperFunctions)
require.NoError(t, err, "Error while compiling the %q expression", dslExpression)
actualResult, err := compiledExpression.Evaluate(make(map[string]interface{}))
diff --git a/v2/pkg/operators/extractors/compile.go b/v2/pkg/operators/extractors/compile.go
index c1f3c64fe..ff6173bcd 100644
--- a/v2/pkg/operators/extractors/compile.go
+++ b/v2/pkg/operators/extractors/compile.go
@@ -43,7 +43,7 @@ func (e *Extractor) CompileExtractors() error {
}
for _, dslExp := range e.DSL {
- compiled, err := govaluate.NewEvaluableExpressionWithFunctions(dslExp, dsl.HelperFunctions())
+ compiled, err := govaluate.NewEvaluableExpressionWithFunctions(dslExp, dsl.HelperFunctions)
if err != nil {
return fmt.Errorf("could not compile dsl: %s", dslExp)
}
diff --git a/v2/pkg/operators/matchers/compile.go b/v2/pkg/operators/matchers/compile.go
index 54bf77149..7bdb8225e 100644
--- a/v2/pkg/operators/matchers/compile.go
+++ b/v2/pkg/operators/matchers/compile.go
@@ -62,7 +62,7 @@ func (matcher *Matcher) CompileMatchers() error {
// Compile the dsl expressions
for _, dslExpression := range matcher.DSL {
- compiledExpression, err := govaluate.NewEvaluableExpressionWithFunctions(dslExpression, dsl.HelperFunctions())
+ compiledExpression, err := govaluate.NewEvaluableExpressionWithFunctions(dslExpression, dsl.HelperFunctions)
if err != nil {
return &DslCompilationError{DslSignature: dslExpression, WrappedError: err}
}
diff --git a/v2/pkg/operators/matchers/match.go b/v2/pkg/operators/matchers/match.go
index 1a5b3dca6..abd8bf336 100644
--- a/v2/pkg/operators/matchers/match.go
+++ b/v2/pkg/operators/matchers/match.go
@@ -173,7 +173,7 @@ func (matcher *Matcher) MatchDSL(data map[string]interface{}) bool {
logExpressionEvaluationFailure(matcher.Name, err)
return false
}
- expression, err = govaluate.NewEvaluableExpressionWithFunctions(resolvedExpression, dsl.HelperFunctions())
+ expression, err = govaluate.NewEvaluableExpressionWithFunctions(resolvedExpression, dsl.HelperFunctions)
if err != nil {
logExpressionEvaluationFailure(matcher.Name, err)
return false
diff --git a/v2/pkg/operators/matchers/match_test.go b/v2/pkg/operators/matchers/match_test.go
index 68a6d1b01..db50b11e9 100644
--- a/v2/pkg/operators/matchers/match_test.go
+++ b/v2/pkg/operators/matchers/match_test.go
@@ -75,7 +75,7 @@ func TestHexEncoding(t *testing.T) {
}
func TestMatcher_MatchDSL(t *testing.T) {
- compiled, err := govaluate.NewEvaluableExpressionWithFunctions("contains(body, \"{{VARIABLE}}\")", dsl.HelperFunctions())
+ compiled, err := govaluate.NewEvaluableExpressionWithFunctions("contains(body, \"{{VARIABLE}}\")", dsl.HelperFunctions)
require.Nil(t, err, "couldn't compile expression")
m := &Matcher{Type: MatcherTypeHolder{MatcherType: DSLMatcher}, dslCompiled: []*govaluate.EvaluableExpression{compiled}}
diff --git a/v2/pkg/protocols/common/expressions/expressions.go b/v2/pkg/protocols/common/expressions/expressions.go
index d73ef3d01..723c6256a 100644
--- a/v2/pkg/protocols/common/expressions/expressions.go
+++ b/v2/pkg/protocols/common/expressions/expressions.go
@@ -40,12 +40,12 @@ func evaluate(data string, base map[string]interface{}) (string, error) {
// - simple: containing base values keys (variables)
// - complex: containing helper functions [ + variables]
// literals like {{2+2}} are not considered expressions
- expressions := findExpressions(data, marker.ParenthesisOpen, marker.ParenthesisClose, mergeFunctions(dsl.HelperFunctions(), mapToFunctions(base)))
+ expressions := findExpressions(data, marker.ParenthesisOpen, marker.ParenthesisClose, base)
for _, expression := range expressions {
// replace variable placeholders with base values
expression = replacer.Replace(expression, base)
// turns expressions (either helper functions+base values or base values)
- compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expression, dsl.HelperFunctions())
+ compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expression, dsl.HelperFunctions)
if err != nil {
continue
}
@@ -63,7 +63,7 @@ func evaluate(data string, base map[string]interface{}) (string, error) {
// maxIterations to avoid infinite loop
const maxIterations = 250
-func findExpressions(data, OpenMarker, CloseMarker string, functions map[string]govaluate.ExpressionFunction) []string {
+func findExpressions(data, OpenMarker, CloseMarker string, base map[string]interface{}) []string {
var (
iterations int
exps []string
@@ -100,7 +100,7 @@ func findExpressions(data, OpenMarker, CloseMarker string, functions map[string]
indexCloseMarkerOffset = indexCloseMarker + len(CloseMarker)
potentialMatch = innerData[indexOpenMarkerOffset:indexCloseMarker]
- if isExpression(potentialMatch, functions) {
+ if isExpression(potentialMatch, base) {
closeMarkerFound = true
shouldSearchCloseMarker = false
exps = append(exps, potentialMatch)
@@ -120,45 +120,21 @@ func findExpressions(data, OpenMarker, CloseMarker string, functions map[string]
return exps
}
-func hasLiteralsOnly(data string) bool {
- expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions())
- if err == nil && expr != nil {
- _, err = expr.Evaluate(nil)
- return err == nil
- }
- return true
-}
-
-func isExpression(data string, functions map[string]govaluate.ExpressionFunction) bool {
+func isExpression(data string, base map[string]interface{}) bool {
if _, err := govaluate.NewEvaluableExpression(data); err == nil {
- return stringsutil.ContainsAny(data, getFunctionsNames(functions)...)
+ if stringsutil.ContainsAny(data, getFunctionsNames(base)...) {
+ return true
+ } else if stringsutil.ContainsAny(data, dsl.FunctionNames...) {
+ return true
+ }
+ return false
}
-
- // check if it's a complex expression
- _, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions())
+ _, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions)
return err == nil
}
-func mapToFunctions(vars map[string]interface{}) map[string]govaluate.ExpressionFunction {
- f := make(map[string]govaluate.ExpressionFunction)
- for k := range vars {
- f[k] = nil
- }
- return f
-}
-
-func mergeFunctions(m ...map[string]govaluate.ExpressionFunction) map[string]govaluate.ExpressionFunction {
- o := make(map[string]govaluate.ExpressionFunction)
- for _, mm := range m {
- for k, v := range mm {
- o[k] = v
- }
- }
- return o
-}
-
-func getFunctionsNames(m map[string]govaluate.ExpressionFunction) []string {
- var keys []string
+func getFunctionsNames(m map[string]interface{}) []string {
+ keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
diff --git a/v2/pkg/protocols/common/expressions/variables.go b/v2/pkg/protocols/common/expressions/variables.go
index 57dc8d7ad..94e504c93 100644
--- a/v2/pkg/protocols/common/expressions/variables.go
+++ b/v2/pkg/protocols/common/expressions/variables.go
@@ -4,6 +4,9 @@ import (
"errors"
"regexp"
"strings"
+
+ "github.com/Knetic/govaluate"
+ "github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl"
)
var (
@@ -111,3 +114,12 @@ func ContainsVariablesWithIgnoreList(skipNames map[string]interface{}, items ...
return nil
}
+
+func hasLiteralsOnly(data string) bool {
+ expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions)
+ if err == nil && expr != nil {
+ _, err = expr.Evaluate(nil)
+ return err == nil
+ }
+ return true
+}
diff --git a/v2/pkg/protocols/common/replacer/replacer.go b/v2/pkg/protocols/common/replacer/replacer.go
index 0e24c6828..dbb4d8fac 100644
--- a/v2/pkg/protocols/common/replacer/replacer.go
+++ b/v2/pkg/protocols/common/replacer/replacer.go
@@ -3,32 +3,20 @@ package replacer
import (
"strings"
+ "github.com/valyala/fasttemplate"
+
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/marker"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
// Replace replaces placeholders in template with values on the fly.
func Replace(template string, values map[string]interface{}) string {
- var replacerItems []string
-
- builder := &strings.Builder{}
- for key, val := range values {
- builder.WriteString(marker.ParenthesisOpen)
- builder.WriteString(key)
- builder.WriteString(marker.ParenthesisClose)
- replacerItems = append(replacerItems, builder.String())
- builder.Reset()
- replacerItems = append(replacerItems, types.ToString(val))
-
- builder.WriteString(marker.General)
- builder.WriteString(key)
- builder.WriteString(marker.General)
- replacerItems = append(replacerItems, builder.String())
- builder.Reset()
- replacerItems = append(replacerItems, types.ToString(val))
+ valuesMap := make(map[string]interface{}, len(values))
+ for k, v := range values {
+ valuesMap[k] = types.ToString(v)
}
- replacer := strings.NewReplacer(replacerItems...)
- final := replacer.Replace(template)
+ replaced := fasttemplate.ExecuteStringStd(template, marker.ParenthesisOpen, marker.ParenthesisClose, valuesMap)
+ final := fasttemplate.ExecuteStringStd(replaced, marker.General, marker.General, valuesMap)
return final
}
diff --git a/v2/pkg/protocols/common/replacer/replacer_test.go b/v2/pkg/protocols/common/replacer/replacer_test.go
new file mode 100644
index 000000000..e03427e21
--- /dev/null
+++ b/v2/pkg/protocols/common/replacer/replacer_test.go
@@ -0,0 +1,12 @@
+package replacer
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestReplacerReplace(t *testing.T) {
+ replaced := Replace("{{test}} §hello§ {{data}}", map[string]interface{}{"test": "random", "hello": "world"})
+ require.Equal(t, "random world {{data}}", replaced, "could not get correct replaced data")
+}
From 77c81834b2ab7a584c4dce0ac9189b18c770f31c Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Wed, 24 Aug 2022 19:32:56 +0530
Subject: [PATCH 12/25] Fixed loader templateConfig nil pointer crash (#2486)
---
v2/internal/runner/runner.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go
index eb9430228..39ab9ed7f 100644
--- a/v2/internal/runner/runner.go
+++ b/v2/internal/runner/runner.go
@@ -377,7 +377,11 @@ func (r *Runner) RunEnumeration() error {
}
executerOpts.WorkflowLoader = workflowLoader
- store, err := loader.New(loader.NewConfig(r.options, r.templatesConfig, r.catalog, executerOpts))
+ templateConfig := r.templatesConfig
+ if templateConfig == nil {
+ templateConfig = &config.Config{}
+ }
+ store, err := loader.New(loader.NewConfig(r.options, templateConfig, r.catalog, executerOpts))
if err != nil {
return errors.Wrap(err, "could not load templates from config")
}
From 8165db2633f589fcba8b299431c93d125632704d Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Wed, 24 Aug 2022 23:29:22 +0530
Subject: [PATCH 13/25] Fixed fatal panic in http header map read (#2488)
---
v2/pkg/protocols/http/utils.go | 23 +++++++++--------------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/v2/pkg/protocols/http/utils.go b/v2/pkg/protocols/http/utils.go
index 521db090d..1fd93bcbf 100644
--- a/v2/pkg/protocols/http/utils.go
+++ b/v2/pkg/protocols/http/utils.go
@@ -4,6 +4,7 @@ import (
"bytes"
"compress/gzip"
"compress/zlib"
+ "context"
"io"
"io/ioutil"
"net/http"
@@ -115,31 +116,25 @@ func normalizeResponseBody(resp *http.Response, response *redirectedResponse) er
// dump creates a dump of the http request in form of a byte slice
func dump(req *generatedRequest, reqURL string) ([]byte, error) {
if req.request != nil {
+ cloned := req.request.Clone(context.Background())
+
// Create a copy on the fly of the request body - ignore errors
bodyBytes, _ := req.request.BodyBytes()
var dumpBody bool
if len(bodyBytes) > 0 {
dumpBody = true
- req.request.Request.ContentLength = int64(len(bodyBytes))
- req.request.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
+ cloned.ContentLength = int64(len(bodyBytes))
+ cloned.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
} else {
- req.request.Request.ContentLength = 0
- req.request.Request.Body = nil
- delete(req.request.Request.Header, "Content-length")
+ cloned.ContentLength = 0
+ cloned.Body = nil
+ delete(cloned.Header, "Content-length")
}
- dumpBytes, err := httputil.DumpRequestOut(req.request.Request, dumpBody)
+ dumpBytes, err := httputil.DumpRequestOut(cloned, dumpBody)
if err != nil {
return nil, err
}
-
- // The original req.Body gets modified indirectly by httputil.DumpRequestOut so we set it again to nil if it was empty
- // Otherwise redirects like 307/308 would fail (as they require the body to be sent along)
- if len(bodyBytes) == 0 {
- req.request.Request.ContentLength = 0
- req.request.Request.Body = nil
- }
-
return dumpBytes, nil
}
rawHttpOptions := &rawhttp.Options{CustomHeaders: req.rawRequest.UnsafeHeaders, CustomRawBytes: req.rawRequest.UnsafeRawBytes}
From d2233eff50cf1c642826ffc0a0091aa36274552a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 24 Aug 2022 23:44:03 +0530
Subject: [PATCH 14/25] chore(deps): bump github.com/xanzy/go-gitlab in /v2
(#2484)
Bumps [github.com/xanzy/go-gitlab](https://github.com/xanzy/go-gitlab) from 0.73.0 to 0.73.1.
- [Release notes](https://github.com/xanzy/go-gitlab/releases)
- [Changelog](https://github.com/xanzy/go-gitlab/blob/master/releases_test.go)
- [Commits](https://github.com/xanzy/go-gitlab/compare/v0.73.0...v0.73.1)
---
updated-dependencies:
- dependency-name: github.com/xanzy/go-gitlab
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 2 +-
v2/go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index 893db9162..19fe71762 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -48,7 +48,7 @@ require (
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.73.0
+ github.com/xanzy/go-gitlab v0.73.1
go.uber.org/atomic v1.9.0
go.uber.org/multierr v1.8.0
go.uber.org/ratelimit v0.2.0
diff --git a/v2/go.sum b/v2/go.sum
index 27bce4290..302bd164b 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -688,8 +688,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.73.0 h1:cfqWPU8cGdmH/O+ZzUpkLM5Rb95OmCBNaR1wRG55aR8=
-github.com/xanzy/go-gitlab v0.73.0/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=
+github.com/xanzy/go-gitlab v0.73.1 h1:UMagqUZLJdjss1SovIC+kJCH4k2AZWXl58gJd38Y/hI=
+github.com/xanzy/go-gitlab v0.73.1/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=
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=
From cdb9e617e60a13954f2f3c0f0f46101cd7264fe6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 24 Aug 2022 23:44:30 +0530
Subject: [PATCH 15/25] chore(deps): bump github.com/aws/aws-sdk-go in /v2
(#2483)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.44.82 to 1.44.83.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.44.82...v1.44.83)
---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
v2/go.mod | 2 +-
v2/go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/v2/go.mod b/v2/go.mod
index 19fe71762..ac939653a 100644
--- a/v2/go.mod
+++ b/v2/go.mod
@@ -59,7 +59,7 @@ require (
moul.io/http2curl v1.0.0
)
-require github.com/aws/aws-sdk-go v1.44.82
+require github.com/aws/aws-sdk-go v1.44.83
require github.com/projectdiscovery/folderutil v0.0.0-20220215113126-add60a1e8e08
diff --git a/v2/go.sum b/v2/go.sum
index 302bd164b..073df0786 100644
--- a/v2/go.sum
+++ b/v2/go.sum
@@ -114,8 +114,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.82 h1:Miji7nHIMxTWfa831nZf8XAcMWGLaT+PvsS6CdbMG7M=
-github.com/aws/aws-sdk-go v1.44.82/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.83 h1:7+Rtc2Eio6EKUNoZeMV/IVxzVrY5oBQcNPtCcgIHYJA=
+github.com/aws/aws-sdk-go v1.44.83/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
From ecb3f21076e77ed79e997ba1ca653c9ae6e0c27f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=2E=20=C3=81ngel=20Jimeno?=
Date: Wed, 24 Aug 2022 20:55:02 +0200
Subject: [PATCH 16/25] http: prevent HTTP 'connection' header from being added
twice (#2480)
* http: prevent HTTP 'connection' header from being added twice
* misc fix
Co-authored-by: sandeep
---
v2/cmd/integration-test/http.go | 2 +-
v2/pkg/protocols/http/http.go | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/v2/cmd/integration-test/http.go b/v2/cmd/integration-test/http.go
index 0fdf9f566..6f2b6e1fc 100644
--- a/v2/cmd/integration-test/http.go
+++ b/v2/cmd/integration-test/http.go
@@ -586,7 +586,7 @@ func (h *httpRawUnsafeRequest) Execute(filePath string) error {
ts := testutils.NewTCPServer(nil, defaultStaticPort, func(conn net.Conn) {
defer conn.Close()
- _, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 36\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nThis is test raw-unsafe-matcher test"))
+ _, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 36\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nThis is test raw-unsafe-matcher test"))
})
defer ts.Close()
diff --git a/v2/pkg/protocols/http/http.go b/v2/pkg/protocols/http/http.go
index 83ed88ec7..8484a0b33 100644
--- a/v2/pkg/protocols/http/http.go
+++ b/v2/pkg/protocols/http/http.go
@@ -237,6 +237,7 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
NoTimeout: false,
FollowRedirects: request.Redirects,
CookieReuse: request.CookieReuse,
+ Connection: &httpclientpool.ConnectionConfiguration{},
}
// If we have request level timeout, ignore http client timeouts
for _, req := range request.Raw {
@@ -248,7 +249,7 @@ func (request *Request) Compile(options *protocols.ExecuterOptions) error {
// if the headers contain "Connection" we need to disable the automatic keep alive of the standard library
if _, hasConnectionHeader := request.Headers["Connection"]; hasConnectionHeader {
- connectionConfiguration.Connection = &httpclientpool.ConnectionConfiguration{DisableKeepAlive: false}
+ connectionConfiguration.Connection.DisableKeepAlive = true
}
client, err := httpclientpool.Get(options.Options, connectionConfiguration)
From 7b7936b7a54e133cbd612200d39e841068cd43c0 Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Thu, 25 Aug 2022 10:43:32 +0530
Subject: [PATCH 17/25] Added show-actions flag to display headless actions
(#2456)
* Added show-actions flag to display headless actions
* misc update
* readme update
Co-authored-by: sandeep
---
README.md | 1 +
v2/cmd/nuclei/main.go | 1 +
v2/internal/runner/options.go | 8 ++++++++
v2/pkg/types/types.go | 2 ++
4 files changed, 12 insertions(+)
diff --git a/README.md b/README.md
index c8ba00c25..d17009052 100644
--- a/README.md
+++ b/README.md
@@ -193,6 +193,7 @@ HEADLESS:
-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
diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go
index 27ad898ef..6251d7fda 100644
--- a/v2/cmd/nuclei/main.go
+++ b/v2/cmd/nuclei/main.go
@@ -220,6 +220,7 @@ on extensive configurability, massive extensibility and ease of use.`)
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.ShowActions, "list-headless-action", "lha", false, "list available headless actions"),
)
flagSet.CreateGroup("debug", "Debug",
diff --git a/v2/internal/runner/options.go b/v2/internal/runner/options.go
index 3d75d32fb..abe7d9d55 100644
--- a/v2/internal/runner/options.go
+++ b/v2/internal/runner/options.go
@@ -19,6 +19,7 @@ import (
"github.com/projectdiscovery/gologger/levels"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/headless/engine"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
@@ -57,6 +58,13 @@ func ParseOptions(options *types.Options) {
gologger.Info().Msgf("Current nuclei-templates version: %s (%s)\n", configuration.TemplateVersion, configuration.TemplatesDirectory)
os.Exit(0)
}
+ if options.ShowActions {
+ gologger.Info().Msgf("Showing available headless actions: ")
+ for action := range engine.ActionStringToAction {
+ gologger.Print().Msgf("\t%s", action)
+ }
+ os.Exit(0)
+ }
if options.StoreResponseDir != DefaultDumpTrafficOutputFolder && !options.StoreResponse {
gologger.Debug().Msgf("Store response directory specified, enabling \"store-resp\" flag automatically\n")
options.StoreResponse = true
diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go
index 0541a684a..0800c16c5 100644
--- a/v2/pkg/types/types.go
+++ b/v2/pkg/types/types.go
@@ -143,6 +143,8 @@ type Options struct {
UseInstalledChrome bool
// SystemResolvers enables override of nuclei's DNS client opting to use system resolver stack.
SystemResolvers bool
+ // ShowActions displays a list of all headless actions
+ ShowActions bool
// Metrics enables display of metrics via an http endpoint
Metrics bool
// Debug mode allows debugging request/responses for the engine
From 72656025d88d88404ab274a246f7d4ff58c016ca Mon Sep 17 00:00:00 2001
From: Min <44919834+M1nSec@users.noreply.github.com>
Date: Thu, 25 Aug 2022 17:44:08 +0800
Subject: [PATCH 18/25] Wrong parameters modified (#2491)
Co-authored-by: Sandeep Singh
---
README_CN.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README_CN.md b/README_CN.md
index a7f188a0e..ccee0391a 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -14,7 +14,7 @@
-
+
工作流程 •
安装 •
@@ -143,7 +143,7 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
-ni, -no-interactsh 禁用反连检测平台,同时排除基于反连检测的模板
限速:
- -r1, -rate-limit int 每秒最大请求量(默认:150)
+ -rl, -rate-limit int 每秒最大请求量(默认:150)
-rlm, -rate-limit-minute int 每分钟最大请求量
-bs, -bulk-size int 每个模板最大并行检测数(默认:25)
-c, -concurrency int 并行执行的最大模板数量(默认:25)
From 0be596efb47bd9d36445e5a4307fbd55d6c1b216 Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Thu, 25 Aug 2022 15:37:03 +0530
Subject: [PATCH 19/25] Added variable debug support with debug mode (#2442)
* Added variable debug support with debug mode
* Added changes as per review comments
* Fixed debug request condition
---
.../helpers/eventcreator/eventcreator.go | 7 +++
v2/pkg/protocols/common/utils/vardump/dump.go | 45 +++++++++++++++++++
v2/pkg/protocols/dns/request.go | 5 +++
v2/pkg/protocols/headless/request.go | 5 +++
v2/pkg/protocols/http/build_request.go | 5 +++
v2/pkg/protocols/network/request.go | 21 +++++----
v2/pkg/protocols/ssl/ssl.go | 5 +++
v2/pkg/protocols/websocket/websocket.go | 5 +++
v2/pkg/protocols/whois/whois.go | 6 +++
9 files changed, 96 insertions(+), 8 deletions(-)
create mode 100644 v2/pkg/protocols/common/utils/vardump/dump.go
diff --git a/v2/pkg/protocols/common/helpers/eventcreator/eventcreator.go b/v2/pkg/protocols/common/helpers/eventcreator/eventcreator.go
index 4e4e7d169..04d0e631c 100644
--- a/v2/pkg/protocols/common/helpers/eventcreator/eventcreator.go
+++ b/v2/pkg/protocols/common/helpers/eventcreator/eventcreator.go
@@ -1,9 +1,11 @@
package eventcreator
import (
+ "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
)
// CreateEvent wraps the outputEvent with the result of the operators defined on the request
@@ -16,6 +18,11 @@ func CreateEvent(request protocols.Request, outputEvent output.InternalEvent, is
func CreateEventWithAdditionalOptions(request protocols.Request, outputEvent output.InternalEvent, isResponseDebug bool,
addAdditionalOptions func(internalWrappedEvent *output.InternalWrappedEvent)) *output.InternalWrappedEvent {
event := &output.InternalWrappedEvent{InternalEvent: outputEvent}
+
+ // Dump response variables if ran in debug mode
+ if isResponseDebug {
+ gologger.Debug().Msgf("Protocol response variables: \n%s\n", vardump.DumpVariables(outputEvent))
+ }
for _, compiledOperator := range request.GetCompiledOperators() {
if compiledOperator != nil {
result, ok := compiledOperator.Execute(outputEvent, request.Match, request.Extract, isResponseDebug)
diff --git a/v2/pkg/protocols/common/utils/vardump/dump.go b/v2/pkg/protocols/common/utils/vardump/dump.go
new file mode 100644
index 000000000..0d6450924
--- /dev/null
+++ b/v2/pkg/protocols/common/utils/vardump/dump.go
@@ -0,0 +1,45 @@
+package vardump
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/projectdiscovery/nuclei/v2/pkg/types"
+)
+
+// DumpVariables writes the truncated dump of variables to a string
+// in a formatted key-value manner.
+//
+// The values are truncated to return 50 characters from start and end.
+func DumpVariables(data map[string]interface{}) string {
+ var counter int
+
+ buffer := &strings.Builder{}
+ buffer.Grow(len(data) * 78) // grow buffer to an approximate size
+
+ builder := &strings.Builder{}
+ for k, v := range data {
+ valueString := types.ToString(v)
+
+ counter++
+ if len(valueString) > 50 {
+ builder.Grow(56)
+ builder.WriteString(valueString[0:25])
+ builder.WriteString(" .... ")
+ builder.WriteString(valueString[len(valueString)-25:])
+ valueString = builder.String()
+ builder.Reset()
+ }
+ valueString = strings.ReplaceAll(strings.ReplaceAll(valueString, "\r", " "), "\n", " ")
+
+ buffer.WriteString("\t")
+ buffer.WriteString(strconv.Itoa(counter))
+ buffer.WriteString(". ")
+ buffer.WriteString(k)
+ buffer.WriteString(" => ")
+ buffer.WriteString(valueString)
+ buffer.WriteString("\n")
+ }
+ final := buffer.String()
+ return final
+}
diff --git a/v2/pkg/protocols/dns/request.go b/v2/pkg/protocols/dns/request.go
index 9f24b01f2..00293089f 100644
--- a/v2/pkg/protocols/dns/request.go
+++ b/v2/pkg/protocols/dns/request.go
@@ -16,6 +16,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
"github.com/projectdiscovery/retryabledns"
@@ -47,6 +48,10 @@ func (request *Request) ExecuteWithResults(input string, metadata /*TODO review
variablesMap := request.options.Variables.Evaluate(vars)
vars = generators.MergeMaps(variablesMap, vars)
+ if request.options.Options.Debug || request.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(vars))
+ }
+
// Compile each request for the template based on the URL
compiledRequest, err := request.Make(domain, vars)
if err != nil {
diff --git a/v2/pkg/protocols/headless/request.go b/v2/pkg/protocols/headless/request.go
index 4dbe1b54f..cdf4b1696 100644
--- a/v2/pkg/protocols/headless/request.go
+++ b/v2/pkg/protocols/headless/request.go
@@ -14,6 +14,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
httpProtocol "github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
)
@@ -69,6 +70,10 @@ func (request *Request) executeRequestWithPayloads(inputURL string, payloads map
}
defer instance.Close()
+ if request.options.Options.Debug || request.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(payloads))
+ }
+
instance.SetInteractsh(request.options.Interactsh)
parsedURL, err := url.Parse(inputURL)
diff --git a/v2/pkg/protocols/http/build_request.go b/v2/pkg/protocols/http/build_request.go
index fc8968be2..64471f90c 100644
--- a/v2/pkg/protocols/http/build_request.go
+++ b/v2/pkg/protocols/http/build_request.go
@@ -17,9 +17,11 @@ import (
"github.com/corpix/uarand"
"github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/dns"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/race"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/raw"
@@ -96,6 +98,9 @@ func (r *requestGenerator) Make(ctx context.Context, baseURL, data string, paylo
generators.MergeMaps(dynamicValues, GenerateVariables(parsed, trailingSlash)),
generators.BuildPayloadFromOptions(r.request.options.Options),
)
+ if r.options.Options.Debug || r.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(values))
+ }
// If data contains \n it's a raw request, process it like raw. Else
// continue with the template based request flow.
diff --git a/v2/pkg/protocols/network/request.go b/v2/pkg/protocols/network/request.go
index eb2179fd0..a3b39b966 100644
--- a/v2/pkg/protocols/network/request.go
+++ b/v2/pkg/protocols/network/request.go
@@ -23,6 +23,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
)
@@ -128,6 +129,10 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
interimValues := generators.MergeMaps(variables, payloads)
+ if request.options.Options.Debug || request.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(interimValues))
+ }
+
inputEvents := make(map[string]interface{})
for _, input := range request.Inputs {
var data []byte
@@ -190,14 +195,14 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
}
request.options.Progress.IncrementRequests()
- if request.options.Options.Debug || request.options.Options.DebugRequests || request.options.Options.StoreResponse{
+ if request.options.Options.Debug || request.options.Options.DebugRequests || request.options.Options.StoreResponse {
requestBytes := []byte(reqBuilder.String())
msg := fmt.Sprintf("[%s] Dumped Network request for %s\n%s", request.options.TemplateID, actualAddress, hex.Dump(requestBytes))
if request.options.Options.Debug || request.options.Options.DebugRequests {
- gologger.Info().Str("address", actualAddress).Msg(msg)
+ gologger.Info().Str("address", actualAddress).Msg(msg)
}
- if request.options.Options.StoreResponse{
- request.options.Output.WriteStoreDebugData(address, request.options.TemplateID, request.Type().String(), msg)
+ if request.options.Options.StoreResponse {
+ request.options.Output.WriteStoreDebugData(address, request.options.TemplateID, request.Type().String(), msg)
}
if request.options.Options.VerboseVerbose {
gologger.Print().Msgf("\nCompact HEX view:\n%s", hex.EncodeToString(requestBytes))
@@ -300,15 +305,15 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
func dumpResponse(event *output.InternalWrappedEvent, request *Request, response string, actualAddress, address string) {
cliOptions := request.options.Options
- if cliOptions.Debug || cliOptions.DebugResponse || cliOptions.StoreResponse{
+ if cliOptions.Debug || cliOptions.DebugResponse || cliOptions.StoreResponse {
requestBytes := []byte(response)
highlightedResponse := responsehighlighter.Highlight(event.OperatorsResult, hex.Dump(requestBytes), cliOptions.NoColor, true)
msg := fmt.Sprintf("[%s] Dumped Network response for %s\n\n", request.options.TemplateID, actualAddress)
if cliOptions.Debug || cliOptions.DebugResponse {
- gologger.Debug().Msg(fmt.Sprintf("%s%s", msg, highlightedResponse))
+ gologger.Debug().Msg(fmt.Sprintf("%s%s", msg, highlightedResponse))
}
- if cliOptions.StoreResponse{
- request.options.Output.WriteStoreDebugData(address, request.options.TemplateID, request.Type().String(), fmt.Sprintf("%s%s", msg, hex.Dump(requestBytes)))
+ if cliOptions.StoreResponse {
+ request.options.Output.WriteStoreDebugData(address, request.options.TemplateID, request.Type().String(), fmt.Sprintf("%s%s", msg, hex.Dump(requestBytes)))
}
if cliOptions.VerboseVerbose {
displayCompactHexView(event, response, cliOptions.NoColor)
diff --git a/v2/pkg/protocols/ssl/ssl.go b/v2/pkg/protocols/ssl/ssl.go
index 8a6e3f516..f5530e7c3 100644
--- a/v2/pkg/protocols/ssl/ssl.go
+++ b/v2/pkg/protocols/ssl/ssl.go
@@ -24,6 +24,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/dns"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/network/networkclientpool"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
@@ -130,6 +131,10 @@ func (request *Request) ExecuteWithResults(input string, dynamicValues, previous
variablesMap := request.options.Variables.Evaluate(values)
payloadValues = generators.MergeMaps(variablesMap, payloadValues)
+ if request.options.Options.Debug || request.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(payloadValues))
+ }
+
finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues)
if dataErr != nil {
requestOptions.Output.Request(requestOptions.TemplateID, input, request.Type().String(), dataErr)
diff --git a/v2/pkg/protocols/websocket/websocket.go b/v2/pkg/protocols/websocket/websocket.go
index 262e53022..d95cef39b 100644
--- a/v2/pkg/protocols/websocket/websocket.go
+++ b/v2/pkg/protocols/websocket/websocket.go
@@ -27,6 +27,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/network/networkclientpool"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
@@ -207,6 +208,10 @@ func (request *Request) executeRequestWithPayloads(input, hostname string, dynam
TLSConfig: tlsConfig,
}
+ if request.options.Options.Debug || request.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(payloadValues))
+ }
+
finalAddress, dataErr := expressions.EvaluateByte([]byte(request.Address), payloadValues)
if dataErr != nil {
requestOptions.Output.Request(requestOptions.TemplateID, input, request.Type().String(), dataErr)
diff --git a/v2/pkg/protocols/whois/whois.go b/v2/pkg/protocols/whois/whois.go
index 83c4840f1..e74bf9c31 100644
--- a/v2/pkg/protocols/whois/whois.go
+++ b/v2/pkg/protocols/whois/whois.go
@@ -18,6 +18,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
)
@@ -88,6 +89,11 @@ func (request *Request) GetID() string {
func (request *Request) ExecuteWithResults(input string, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
// generate variables
variables := generateVariables(input)
+
+ if request.options.Options.Debug || request.options.Options.DebugRequests {
+ gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(variables))
+ }
+
// and replace placeholders
query := replacer.Replace(request.Query, variables)
// build an rdap request
From 606c361b2afdd37e183aadb0fc7a566db1355be0 Mon Sep 17 00:00:00 2001
From: 51pwn <18223385+hktalent@users.noreply.github.com>
Date: Thu, 25 Aug 2022 18:20:08 +0800
Subject: [PATCH 20/25] Add `substr` and `aes_cbc` DSL functions (#2361)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* 1、add DSL substr for #2304 By @hktalent
substr('xxtestxxx',2)。 testxxx
substr('xxtestxxx',2,-2) testx
substr('xxtestxxx',2,6) test
2、add DSL aes_cbc for #2243 By @hktalent
aes_cbc("key111key111key111key111", "dataxxxxxxdataxxxxxxdataxxxxxxdataxxxxxxdataxxxxxx")
3、fixed An error occurs when running nuclei with multiple instances #2301 By @hktalent
* refactoring helpers
* removing unwanted mutex
* commenting out test
* removing aes_cbc test due to random iv
Co-authored-by: 51pwn <51pwn@51pwn.com>
Co-authored-by: Mzack9999
---
v2/pkg/operators/common/dsl/dsl.go | 44 ++++++++
v2/pkg/operators/common/dsl/dsl_test.go | 140 ++++++++++++------------
v2/pkg/protocols/http/request.go | 1 -
3 files changed, 116 insertions(+), 69 deletions(-)
diff --git a/v2/pkg/operators/common/dsl/dsl.go b/v2/pkg/operators/common/dsl/dsl.go
index 5c5d29a67..43a472697 100644
--- a/v2/pkg/operators/common/dsl/dsl.go
+++ b/v2/pkg/operators/common/dsl/dsl.go
@@ -573,6 +573,49 @@ func init() {
}
return nil, fmt.Errorf("invalid number: %T", args[0])
}),
+ "substr": makeDslWithOptionalArgsFunction(
+ "(str string, start int, optionalEnd int)",
+ func(args ...interface{}) (interface{}, error) {
+ if len(args) < 2 {
+ return nil, invalidDslFunctionError
+ }
+ argStr := types.ToString(args[0])
+ start, err := strconv.Atoi(types.ToString(args[1]))
+ if err != nil {
+ return nil, errors.Wrap(err, "invalid start position")
+ }
+ if len(args) == 2 {
+ return argStr[start:], nil
+ }
+
+ end, err := strconv.Atoi(types.ToString(args[2]))
+ if err != nil {
+ return nil, errors.Wrap(err, "invalid end position")
+ }
+ if end < 0 {
+ end += len(argStr)
+ }
+ return argStr[start:end], nil
+ },
+ ),
+ "aes_cbc": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
+ key := []byte(types.ToString(args[0]))
+ cleartext := []byte(types.ToString(args[1]))
+ block, _ := aes.NewCipher(key)
+ blockSize := block.BlockSize()
+ n := blockSize - len(cleartext)%blockSize
+ temp := bytes.Repeat([]byte{byte(n)}, n)
+ cleartext = append(cleartext, temp...)
+ iv := make([]byte, 16)
+ if _, err := crand.Read(iv); err != nil {
+ return nil, err
+ }
+ blockMode := cipher.NewCBCEncrypter(block, iv)
+ ciphertext := make([]byte, len(cleartext))
+ blockMode.CryptBlocks(ciphertext, cleartext)
+ ciphertext = append(iv, ciphertext...)
+ return ciphertext, nil
+ }),
"aes_gcm": makeDslFunction(2, func(args ...interface{}) (interface{}, error) {
key := args[0].(string)
value := args[1].(string)
@@ -651,6 +694,7 @@ func helperFunctions() map[string]govaluate.ExpressionFunction {
}
// AddHelperFunction allows creation of additional helper functions to be supported with templates
+//
//goland:noinspection GoUnusedExportedFunction
func AddHelperFunction(key string, value func(args ...interface{}) (interface{}, error)) error {
if _, ok := dslFunctions[key]; !ok {
diff --git a/v2/pkg/operators/common/dsl/dsl_test.go b/v2/pkg/operators/common/dsl/dsl_test.go
index f9cd3250c..83d7b201c 100644
--- a/v2/pkg/operators/common/dsl/dsl_test.go
+++ b/v2/pkg/operators/common/dsl/dsl_test.go
@@ -132,76 +132,77 @@ func createSignatureError(signature string) string {
return fmt.Errorf(invalidDslFunctionMessageTemplate, invalidDslFunctionError, signature).Error()
}
-func TestGetPrintableDslFunctionSignatures(t *testing.T) {
- expected := ` [93maes_gcm[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mbase64[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mbase64_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mbase64_py[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mcompare_versions[0m(firstVersion, constraints [38;5;208m...string[0m)[38;5;208m bool[0m
- [93mconcat[0m(args [38;5;208m...interface{}[0m)[38;5;208m string[0m
- [93mcontains[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mdate_time[0m(dateTimeFormat [38;5;208mstring[0m, optionalUnixTime [38;5;208minterface{}[0m)[38;5;208m string[0m
- [93mdec_to_hex[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mends_with[0m(str [38;5;208mstring[0m, suffix [38;5;208m...string[0m)[38;5;208m bool[0m
- [93mgenerate_java_gadget[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mgzip[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mgzip_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mhex_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mhex_encode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mhmac[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mhtml_escape[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mhtml_unescape[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mjoin[0m(separator [38;5;208mstring[0m, elements [38;5;208m...interface{}[0m)[38;5;208m string[0m
- [93mlen[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mline_ends_with[0m(str [38;5;208mstring[0m, suffix [38;5;208m...string[0m)[38;5;208m bool[0m
- [93mline_starts_with[0m(str [38;5;208mstring[0m, prefix [38;5;208m...string[0m)[38;5;208m bool[0m
- [93mmd5[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mmmh3[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mprint_debug[0m(args [38;5;208m...interface{}[0m)[38;5;208m[0m
- [93mrand_base[0m(length [38;5;208muint[0m, optionalCharSet [38;5;208mstring[0m)[38;5;208m string[0m
- [93mrand_char[0m(optionalCharSet [38;5;208mstring[0m)[38;5;208m string[0m
- [93mrand_int[0m(optionalMin, optionalMax [38;5;208muint[0m)[38;5;208m int[0m
- [93mrand_ip[0m(cidr [38;5;208m...string[0m)[38;5;208m string[0m
- [93mrand_text_alpha[0m(length [38;5;208muint[0m, optionalBadChars [38;5;208mstring[0m)[38;5;208m string[0m
- [93mrand_text_alphanumeric[0m(length [38;5;208muint[0m, optionalBadChars [38;5;208mstring[0m)[38;5;208m string[0m
- [93mrand_text_numeric[0m(length [38;5;208muint[0m, optionalBadNumbers [38;5;208mstring[0m)[38;5;208m string[0m
- [93mregex[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mremove_bad_chars[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mrepeat[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mreplace[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mreplace_regex[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mreverse[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93msha1[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93msha256[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mstarts_with[0m(str [38;5;208mstring[0m, prefix [38;5;208m...string[0m)[38;5;208m bool[0m
- [93mto_lower[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mto_number[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mto_string[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mto_upper[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mtrim[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mtrim_left[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mtrim_prefix[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mtrim_right[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mtrim_space[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mtrim_suffix[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93munix_time[0m(optionalSeconds [38;5;208muint[0m)[38;5;208m float64[0m
- [93murl_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93murl_encode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mwait_for[0m(seconds [38;5;208muint[0m)[38;5;208m[0m
- [93mzlib[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
- [93mzlib_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
-`
- t.Run("with coloring", func(t *testing.T) {
- assert.Equal(t, expected, GetPrintableDslFunctionSignatures(false))
- })
+// TODO: the test is hard to maintain due to the presence of hardcoded color characters, it needs to be simplified
+// func TestGetPrintableDslFunctionSignatures(t *testing.T) {
+// expected := ` [93maes_gcm[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mbase64[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mbase64_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mbase64_py[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mcompare_versions[0m(firstVersion, constraints [38;5;208m...string[0m)[38;5;208m bool[0m
+// [93mconcat[0m(args [38;5;208m...interface{}[0m)[38;5;208m string[0m
+// [93mcontains[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mdate_time[0m(dateTimeFormat [38;5;208mstring[0m, optionalUnixTime [38;5;208minterface{}[0m)[38;5;208m string[0m
+// [93mdec_to_hex[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mends_with[0m(str [38;5;208mstring[0m, suffix [38;5;208m...string[0m)[38;5;208m bool[0m
+// [93mgenerate_java_gadget[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mgzip[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mgzip_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mhex_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mhex_encode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mhmac[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mhtml_escape[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mhtml_unescape[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mjoin[0m(separator [38;5;208mstring[0m, elements [38;5;208m...interface{}[0m)[38;5;208m string[0m
+// [93mlen[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mline_ends_with[0m(str [38;5;208mstring[0m, suffix [38;5;208m...string[0m)[38;5;208m bool[0m
+// [93mline_starts_with[0m(str [38;5;208mstring[0m, prefix [38;5;208m...string[0m)[38;5;208m bool[0m
+// [93mmd5[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mmmh3[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mprint_debug[0m(args [38;5;208m...interface{}[0m)[38;5;208m[0m
+// [93mrand_base[0m(length [38;5;208muint[0m, optionalCharSet [38;5;208mstring[0m)[38;5;208m string[0m
+// [93mrand_char[0m(optionalCharSet [38;5;208mstring[0m)[38;5;208m string[0m
+// [93mrand_int[0m(optionalMin, optionalMax [38;5;208muint[0m)[38;5;208m int[0m
+// [93mrand_ip[0m(cidr [38;5;208m...string[0m)[38;5;208m string[0m
+// [93mrand_text_alpha[0m(length [38;5;208muint[0m, optionalBadChars [38;5;208mstring[0m)[38;5;208m string[0m
+// [93mrand_text_alphanumeric[0m(length [38;5;208muint[0m, optionalBadChars [38;5;208mstring[0m)[38;5;208m string[0m
+// [93mrand_text_numeric[0m(length [38;5;208muint[0m, optionalBadNumbers [38;5;208mstring[0m)[38;5;208m string[0m
+// [93mregex[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mremove_bad_chars[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mrepeat[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mreplace[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mreplace_regex[0m(arg1, arg2, arg3 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mreverse[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93msha1[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93msha256[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mstarts_with[0m(str [38;5;208mstring[0m, prefix [38;5;208m...string[0m)[38;5;208m bool[0m
+// [93mto_lower[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mto_number[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mto_string[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mto_upper[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mtrim[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mtrim_left[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mtrim_prefix[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mtrim_right[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mtrim_space[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mtrim_suffix[0m(arg1, arg2 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93munix_time[0m(optionalSeconds [38;5;208muint[0m)[38;5;208m float64[0m
+// [93murl_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93murl_encode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mwait_for[0m(seconds [38;5;208muint[0m)[38;5;208m[0m
+// [93mzlib[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// [93mzlib_decode[0m(arg1 [38;5;208minterface{}[0m)[38;5;208m interface{}[0m
+// `
+// t.Run("with coloring", func(t *testing.T) {
+// assert.Equal(t, expected, GetPrintableDslFunctionSignatures(false))
+// })
- t.Run("without coloring", func(t *testing.T) {
- var decolorizerRegex = regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`)
- expectedSignaturesWithoutColor := decolorizerRegex.ReplaceAllString(expected, "")
+// t.Run("without coloring", func(t *testing.T) {
+// var decolorizerRegex = regexp.MustCompile(`\x1B\[[0-9;]*[a-zA-Z]`)
+// expectedSignaturesWithoutColor := decolorizerRegex.ReplaceAllString(expected, "")
- assert.Equal(t, expectedSignaturesWithoutColor, GetPrintableDslFunctionSignatures(true))
- })
-}
+// assert.Equal(t, expectedSignaturesWithoutColor, GetPrintableDslFunctionSignatures(true))
+// })
+// }
func TestDslExpressions(t *testing.T) {
now := time.Now()
@@ -268,6 +269,9 @@ func TestDslExpressions(t *testing.T) {
`compare_versions('v1.0.0', '>v0.0.1', '
Date: Thu, 25 Aug 2022 05:40:07 -0500
Subject: [PATCH 21/25] added custom config flag (#2399)
* added custom config flag
* config.yaml file in custom directory
* lint error fix
* few updates and error checks
* fix lint error
* copy config.yaml file if the dest folder does not exist
* lint error check
* added integration test
* improved test cases
* lint error fix
---
v2/cmd/integration-test/custom-dir.go | 38 +++++++++++++++++++++
v2/cmd/integration-test/integration-test.go | 29 ++++++++--------
v2/cmd/nuclei/main.go | 28 +++++++++++++--
v2/internal/runner/healthcheck.go | 12 ++++---
v2/pkg/catalog/config/config.go | 25 +++++++++++---
v2/pkg/types/types.go | 2 ++
6 files changed, 108 insertions(+), 26 deletions(-)
create mode 100644 v2/cmd/integration-test/custom-dir.go
diff --git a/v2/cmd/integration-test/custom-dir.go b/v2/cmd/integration-test/custom-dir.go
new file mode 100644
index 000000000..8fa942c2d
--- /dev/null
+++ b/v2/cmd/integration-test/custom-dir.go
@@ -0,0 +1,38 @@
+package main
+
+import (
+ "os"
+
+ "github.com/projectdiscovery/nuclei/v2/pkg/testutils"
+)
+
+type customConfigDirTest struct{}
+
+var customConfigDirTestCases = map[string]testutils.TestCase{
+ "dns/cname-fingerprint.yaml": &customConfigDirTest{},
+}
+
+// Execute executes a test case and returns an error if occurred
+func (h *customConfigDirTest) Execute(filePath string) error {
+ customTempDirectory, err := os.MkdirTemp("", "")
+ if err != nil {
+ return err
+ }
+ defer os.RemoveAll(customTempDirectory)
+ results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "8x8exch02.8x8.com", debug, "-config-directory", customTempDirectory)
+ if err != nil {
+ return err
+ }
+ if len(results) == 0 {
+ return nil
+ }
+ files, err := os.ReadDir(customTempDirectory)
+ if err != nil {
+ return err
+ }
+ var fileNames []string
+ for _, file := range files {
+ fileNames = append(fileNames, file.Name())
+ }
+ return expectResultsCount(fileNames, 3)
+}
diff --git a/v2/cmd/integration-test/integration-test.go b/v2/cmd/integration-test/integration-test.go
index 28f539426..940e279fb 100644
--- a/v2/cmd/integration-test/integration-test.go
+++ b/v2/cmd/integration-test/integration-test.go
@@ -19,20 +19,21 @@ var (
failed = aurora.Red("[✘]").String()
protocolTests = map[string]map[string]testutils.TestCase{
- "http": httpTestcases,
- "network": networkTestcases,
- "dns": dnsTestCases,
- "workflow": workflowTestcases,
- "loader": loaderTestcases,
- "websocket": websocketTestCases,
- "headless": headlessTestcases,
- "whois": whoisTestCases,
- "ssl": sslTestcases,
- "code": codeTestcases,
- "templatesPath": templatesPathTestCases,
- "templatesDir": templatesDirTestCases,
- "file": fileTestcases,
- "offlineHttp": offlineHttpTestcases,
+ "http": httpTestcases,
+ "network": networkTestcases,
+ "dns": dnsTestCases,
+ "workflow": workflowTestcases,
+ "loader": loaderTestcases,
+ "websocket": websocketTestCases,
+ "headless": headlessTestcases,
+ "whois": whoisTestCases,
+ "ssl": sslTestcases,
+ "code": codeTestcases,
+ "templatesPath": templatesPathTestCases,
+ "templatesDir": templatesDirTestCases,
+ "file": fileTestcases,
+ "offlineHttp": offlineHttpTestcases,
+ "customConfigDir": customConfigDirTestCases,
}
)
diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go
index 6251d7fda..74d398513 100644
--- a/v2/cmd/nuclei/main.go
+++ b/v2/cmd/nuclei/main.go
@@ -1,7 +1,9 @@
package main
import (
+ "errors"
"fmt"
+ "io"
"os"
"os/signal"
"path/filepath"
@@ -32,7 +34,6 @@ func main() {
if err := runner.ConfigureOptions(); err != nil {
gologger.Fatal().Msgf("Could not initialize options: %s\n", err)
}
-
readConfig()
// Profiling related code
@@ -181,6 +182,7 @@ 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.StringVar(&options.CustomConfigDir, "config-directory", "", "Override the default config path ($home/.config)"),
)
flagSet.CreateGroup("interactsh", "interactsh",
@@ -261,7 +263,29 @@ on extensive configurability, massive extensibility and ease of use.`)
if options.LeaveDefaultPorts {
http.LeaveDefaultPorts = true
}
-
+ if options.CustomConfigDir != "" {
+ originalIgnorePath := config.GetIgnoreFilePath()
+ config.SetCustomConfigDirectory(options.CustomConfigDir)
+ configPath := filepath.Join(options.CustomConfigDir, "config.yaml")
+ ignoreFile := filepath.Join(options.CustomConfigDir, ".nuclei-ignore")
+ if !fileutil.FileExists(ignoreFile) {
+ _ = fileutil.CopyFile(originalIgnorePath, ignoreFile)
+ }
+ readConfigFile := func() error {
+ if err := flagSet.MergeConfigFile(configPath); err != nil && !errors.Is(err, io.EOF) {
+ defaultConfigPath, _ := goflags.GetConfigFilePath()
+ err = fileutil.CopyFile(defaultConfigPath, configPath)
+ if err != nil {
+ return err
+ }
+ return errors.New("reload the config file")
+ }
+ return nil
+ }
+ if err := readConfigFile(); err != nil {
+ _ = readConfigFile()
+ }
+ }
if cfgFile != "" {
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
gologger.Fatal().Msgf("Could not read config: %s\n", err)
diff --git a/v2/internal/runner/healthcheck.go b/v2/internal/runner/healthcheck.go
index b708086e7..48008be1a 100644
--- a/v2/internal/runner/healthcheck.go
+++ b/v2/internal/runner/healthcheck.go
@@ -7,7 +7,6 @@ import (
"runtime"
"strings"
- "github.com/mitchellh/go-homedir"
"github.com/projectdiscovery/fileutil"
"github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
@@ -18,7 +17,6 @@ import (
func DoHealthCheck(options *types.Options) string {
// RW permissions on config file
cfgFilePath, _ := goflags.GetConfigFilePath()
- cfgFileFolder := filepath.Dir(cfgFilePath)
var test strings.Builder
test.WriteString(fmt.Sprintf("Version: %s\n", config.Version))
test.WriteString(fmt.Sprintf("Operative System: %s\n", runtime.GOOS))
@@ -28,9 +26,13 @@ func DoHealthCheck(options *types.Options) string {
var testResult string
- nucleiIgnorePath := filepath.Join(cfgFileFolder, ".nuclei-ignore")
- homedir, _ := homedir.Dir()
- nucleiTemplatePath := filepath.Join(homedir, "nuclei-templates/.checksum")
+ nucleiIgnorePath := config.GetIgnoreFilePath()
+ cf, _ := config.ReadConfiguration()
+ templatePath := ""
+ if cf != nil {
+ templatePath = cf.TemplatesDirectory
+ }
+ nucleiTemplatePath := filepath.Join(templatePath, "/", ".checksum")
for _, filename := range []string{cfgFilePath, nucleiIgnorePath, nucleiTemplatePath} {
ok, err := fileutil.IsReadable(filename)
if ok {
diff --git a/v2/pkg/catalog/config/config.go b/v2/pkg/catalog/config/config.go
index 4b9cfbb29..69a034020 100644
--- a/v2/pkg/catalog/config/config.go
+++ b/v2/pkg/catalog/config/config.go
@@ -30,6 +30,14 @@ const nucleiConfigFilename = ".templates-config.json"
// Version is the current version of nuclei
const Version = `2.7.6`
+var customConfigDirectory string
+
+func SetCustomConfigDirectory(dir string) {
+ customConfigDirectory = dir
+ if !fileutil.FolderExists(dir) {
+ _ = fileutil.CreateFolder(dir)
+ }
+}
func getConfigDetails() (string, error) {
configDir, err := GetConfigDir()
if err != nil {
@@ -42,7 +50,15 @@ func getConfigDetails() (string, error) {
// GetConfigDir returns the nuclei configuration directory
func GetConfigDir() (string, error) {
- home, err := homedir.Dir()
+ var (
+ home string
+ err error
+ )
+ if customConfigDirectory != "" {
+ home = customConfigDirectory
+ return home, nil
+ }
+ home, err = homedir.Dir()
if err != nil {
return "", err
}
@@ -55,7 +71,6 @@ func ReadConfiguration() (*Config, error) {
if err != nil {
return nil, err
}
-
file, err := os.Open(templatesConfigFile)
if err != nil {
return nil, err
@@ -100,7 +115,7 @@ type IgnoreFile struct {
// ReadIgnoreFile reads the nuclei ignore file returning blocked tags and paths
func ReadIgnoreFile() IgnoreFile {
- file, err := os.Open(getIgnoreFilePath())
+ file, err := os.Open(GetIgnoreFilePath())
if err != nil {
gologger.Error().Msgf("Could not read nuclei-ignore file: %s\n", err)
return IgnoreFile{}
@@ -138,8 +153,8 @@ func OverrideIgnoreFilePath(customPath string) error {
return nil
}
-// getIgnoreFilePath returns the ignore file path for the runner
-func getIgnoreFilePath() string {
+// GetIgnoreFilePath returns the ignore file path for the runner
+func GetIgnoreFilePath() string {
var defIgnoreFilePath string
if customIgnoreFilePath != "" {
diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go
index 0800c16c5..bddbb84b4 100644
--- a/v2/pkg/types/types.go
+++ b/v2/pkg/types/types.go
@@ -236,6 +236,8 @@ type Options struct {
InputReadTimeout time.Duration
// Disable stdin for input processing
DisableStdin bool
+ // Custom Config Directory
+ CustomConfigDir string
}
func (options *Options) AddVarPayload(key string, value interface{}) {
From 30054d1fb6d7a9cdce4c1f269bae494e670433c1 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Thu, 25 Aug 2022 13:22:08 +0200
Subject: [PATCH 22/25] Adding advanced template filtering (#2374)
* Adding advanced template filtering
* fixing bug in slice
* refactoring tests
* adding test cases
* increasing error verbosity
* fixing quoted fields with spaces
* adding more test cases
* fixing merge error
* fixing lint errors
* switching to []string
* updating tag filter tests
* updating functional tests
* fixing functional test cases
* updating syntax
---
v2/cmd/cve-annotate/main.go | 9 +-
v2/cmd/docgen/docgen.go | 5 +-
v2/cmd/functional-test/main.go | 17 +-
v2/cmd/functional-test/testcases.txt | 3 +
v2/cmd/integration-test/loader.go | 5 +-
v2/cmd/nuclei/main.go | 1 +
v2/internal/runner/runner.go | 4 +-
v2/internal/runner/update.go | 3 +-
v2/internal/runner/update_test.go | 23 +-
v2/pkg/catalog/loader/filter/tag_filter.go | 75 +++++-
.../catalog/loader/filter/tag_filter_test.go | 221 +++++++++++++-----
v2/pkg/catalog/loader/loader.go | 33 +--
v2/pkg/parsers/parser.go | 14 +-
v2/pkg/parsers/parser_test.go | 6 +-
v2/pkg/parsers/workflow_loader.go | 21 +-
v2/pkg/projectfile/httputil.go | 3 +-
.../common/automaticscan/automaticscan.go | 20 +-
v2/pkg/protocols/file/find_test.go | 5 +-
v2/pkg/protocols/file/request_test.go | 5 +-
v2/pkg/protocols/headless/engine/engine.go | 3 +-
.../protocols/headless/engine/page_actions.go | 4 +-
v2/pkg/protocols/http/build_request.go | 5 +-
v2/pkg/protocols/http/request.go | 11 +-
v2/pkg/protocols/http/utils.go | 5 +-
v2/pkg/protocols/offlinehttp/find_test.go | 5 +-
v2/pkg/reporting/dedupe/dedupe.go | 3 +-
v2/pkg/reporting/dedupe/dedupe_test.go | 3 +-
.../reporting/exporters/es/elasticsearch.go | 3 +-
.../reporting/exporters/markdown/markdown.go | 3 +-
v2/pkg/types/types.go | 2 +
v2/pkg/utils/monitor/monitor.go | 3 +-
31 files changed, 342 insertions(+), 181 deletions(-)
diff --git a/v2/cmd/cve-annotate/main.go b/v2/cmd/cve-annotate/main.go
index 46df7d149..b386fa07c 100644
--- a/v2/cmd/cve-annotate/main.go
+++ b/v2/cmd/cve-annotate/main.go
@@ -5,7 +5,6 @@ import (
"encoding/json"
"flag"
"fmt"
- "io/ioutil"
"log"
"net/http"
"net/url"
@@ -51,7 +50,7 @@ func main() {
}
func process() error {
- tempDir, err := ioutil.TempDir("", "nuclei-nvd-%s")
+ tempDir, err := os.MkdirTemp("", "nuclei-nvd-%s")
if err != nil {
return err
}
@@ -238,7 +237,7 @@ func getCVEData(client *nvd.Client, filePath, data string) {
newTemplate := strings.ReplaceAll(data, infoBlockClean, newInfoBlockData)
if changed {
- _ = ioutil.WriteFile(filePath, []byte(newTemplate), 0644)
+ _ = os.WriteFile(filePath, []byte(newTemplate), 0644)
fmt.Printf("Wrote updated template to %s\n", filePath)
}
}
@@ -320,7 +319,7 @@ func parseAndAddCISAKevTagTemplate(path string, data string) (string, error) {
}
splitted = append(splitted, "kev")
replaced := strings.ReplaceAll(data, block.Info.Tags, strings.Join(splitted, ","))
- return replaced, ioutil.WriteFile(path, []byte(replaced), os.ModePerm)
+ return replaced, os.WriteFile(path, []byte(replaced), os.ModePerm)
}
// parseAndAddReferenceBasedTags parses and adds reference based tags to templates
@@ -340,7 +339,7 @@ func parseAndAddReferenceBasedTags(path string, data string) (string, error) {
return data, nil
}
replaced := strings.ReplaceAll(data, tagsCurrent, fmt.Sprintf("tags: %s", strings.Join(newTags, ",")))
- return replaced, ioutil.WriteFile(path, []byte(replaced), os.ModePerm)
+ return replaced, os.WriteFile(path, []byte(replaced), os.ModePerm)
}
var referenceMapping = map[string]string{
diff --git a/v2/cmd/docgen/docgen.go b/v2/cmd/docgen/docgen.go
index 7cfdaf275..1fdf38949 100644
--- a/v2/cmd/docgen/docgen.go
+++ b/v2/cmd/docgen/docgen.go
@@ -3,7 +3,6 @@ package main
import (
"bytes"
"encoding/json"
- "io/ioutil"
"log"
"os"
"regexp"
@@ -22,7 +21,7 @@ func main() {
if err != nil {
log.Fatalf("Could not encode docs: %s\n", err)
}
- err = ioutil.WriteFile(os.Args[1], data, 0644)
+ err = os.WriteFile(os.Args[1], data, 0644)
if err != nil {
log.Fatalf("Could not write docs: %s\n", err)
}
@@ -44,7 +43,7 @@ func main() {
for _, match := range pathRegex.FindAllStringSubmatch(schema, -1) {
schema = strings.ReplaceAll(schema, match[0], match[1])
}
- err = ioutil.WriteFile(os.Args[2], []byte(schema), 0644)
+ err = os.WriteFile(os.Args[2], []byte(schema), 0644)
if err != nil {
log.Fatalf("Could not write jsonschema: %s\n", err)
}
diff --git a/v2/cmd/functional-test/main.go b/v2/cmd/functional-test/main.go
index e775f1950..6df1ce4da 100644
--- a/v2/cmd/functional-test/main.go
+++ b/v2/cmd/functional-test/main.go
@@ -85,7 +85,22 @@ func runTestCase(testCase string, debug bool) bool {
}
func runIndividualTestCase(testcase string, debug bool) error {
- parts := strings.Fields(testcase)
+ quoted := false
+
+ // split upon unquoted spaces
+ parts := strings.FieldsFunc(testcase, func(r rune) bool {
+ if r == '"' {
+ quoted = !quoted
+ }
+ return !quoted && r == ' '
+ })
+
+ // Quoted strings containing spaces are expressions and must have trailing \" removed
+ for index, part := range parts {
+ if strings.Contains(part, " ") {
+ parts[index] = strings.Trim(part, "\"")
+ }
+ }
var finalArgs []string
if len(parts) > 1 {
diff --git a/v2/cmd/functional-test/testcases.txt b/v2/cmd/functional-test/testcases.txt
index cdcdb2d4f..b31170223 100644
--- a/v2/cmd/functional-test/testcases.txt
+++ b/v2/cmd/functional-test/testcases.txt
@@ -46,6 +46,9 @@
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli -exclude-templates cves/2021/
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli -exclude-templates cves/2017/CVE-2017-7269.yaml
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli -include-templates cves/2017/CVE-2017-7269.yaml
+{{binary}} -tags cve -author geeknik,pdteam -tc severity=='high'
+{{binary}} -tc contains(authors,'pdteam')
+{{binary}} -t cves/ -t exposures/ -tc contains(tags,'cve') -exclude-templates cves/2020/CVE-2020-9757.yaml
{{binary}} -w workflows
{{binary}} -w workflows -author geeknik,pdteam
{{binary}} -w workflows -severity high,critical
diff --git a/v2/cmd/integration-test/loader.go b/v2/cmd/integration-test/loader.go
index b2ce9a0e0..4f4c06056 100644
--- a/v2/cmd/integration-test/loader.go
+++ b/v2/cmd/integration-test/loader.go
@@ -2,7 +2,6 @@ package main
import (
"fmt"
- "io/ioutil"
"net/http"
"net/http/httptest"
"os"
@@ -49,7 +48,7 @@ func (h *remoteTemplateList) Execute(templateList string) error {
defer ts.Close()
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
- err := ioutil.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm)
+ err := os.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm)
if err != nil {
return err
}
@@ -148,7 +147,7 @@ func (h *remoteWorkflowList) Execute(workflowList string) error {
defer ts.Close()
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
- err := ioutil.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm)
+ err := os.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm)
if err != nil {
return err
}
diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go
index 74d398513..f066ffa14 100644
--- a/v2/cmd/nuclei/main.go
+++ b/v2/cmd/nuclei/main.go
@@ -146,6 +146,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.VarP(&options.ExcludeSeverities, "exclude-severity", "es", fmt.Sprintf("templates to exclude based on severity. Possible values: %s", severity.GetSupportedSeverities().String())),
flagSet.VarP(&options.Protocols, "type", "pt", fmt.Sprintf("templates to run based on protocol type. Possible values: %s", templateTypes.GetSupportedProtocolTypes())),
flagSet.VarP(&options.ExcludeProtocols, "exclude-type", "ept", fmt.Sprintf("templates to exclude based on protocol type. Possible values: %s", templateTypes.GetSupportedProtocolTypes())),
+ flagSet.FileStringSliceVarP(&options.IncludeConditions, "template-condition", "tc", nil, "templates to run based on expression condition"),
)
flagSet.CreateGroup("output", "Output",
diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go
index 39ab9ed7f..b0308b680 100644
--- a/v2/internal/runner/runner.go
+++ b/v2/internal/runner/runner.go
@@ -6,7 +6,7 @@ import (
"context"
"encoding/json"
"fmt"
- "io/ioutil"
+ "io"
"net/http"
_ "net/http/pprof"
"os"
@@ -560,7 +560,7 @@ func (r *Runner) readNewTemplatesWithVersionFile(version string) ([]string, erro
if resp.StatusCode != http.StatusOK {
return nil, errors.New("version not found")
}
- data, err := ioutil.ReadAll(resp.Body)
+ data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
diff --git a/v2/internal/runner/update.go b/v2/internal/runner/update.go
index e31cd183c..b02af494e 100644
--- a/v2/internal/runner/update.go
+++ b/v2/internal/runner/update.go
@@ -9,7 +9,6 @@ import (
"encoding/hex"
"fmt"
"io"
- "io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -220,7 +219,7 @@ func (r *Runner) checkNucleiIgnoreFileUpdates(configDir string) bool {
return false
}
if len(data) > 0 {
- _ = ioutil.WriteFile(filepath.Join(configDir, nucleiIgnoreFile), data, 0644)
+ _ = os.WriteFile(filepath.Join(configDir, nucleiIgnoreFile), data, 0644)
}
if r.templatesConfig != nil {
if err := config.WriteConfiguration(r.templatesConfig); err != nil {
diff --git a/v2/internal/runner/update_test.go b/v2/internal/runner/update_test.go
index 2202b1777..1a8191de3 100644
--- a/v2/internal/runner/update_test.go
+++ b/v2/internal/runner/update_test.go
@@ -4,7 +4,6 @@ import (
"archive/zip"
"context"
"io"
- "io/ioutil"
"net/http"
"net/http/httptest"
"os"
@@ -22,21 +21,21 @@ import (
func TestDownloadReleaseAndUnzipAddition(t *testing.T) {
gologger.DefaultLogger.SetWriter(&testutils.NoopWriter{})
- templatesDirectory, err := ioutil.TempDir("", "template-*")
+ templatesDirectory, err := os.MkdirTemp("", "template-*")
require.Nil(t, err, "could not create temp directory")
defer os.RemoveAll(templatesDirectory)
r := &Runner{templatesConfig: &config.Config{TemplatesDirectory: templatesDirectory}, options: testutils.DefaultOptions}
- newTempDir, err := ioutil.TempDir("", "new-tmp-*")
+ newTempDir, err := os.MkdirTemp("", "new-tmp-*")
require.Nil(t, err, "could not create temp directory")
defer os.RemoveAll(newTempDir)
- err = ioutil.WriteFile(filepath.Join(newTempDir, "base.yaml"), []byte("id: test"), os.ModePerm)
+ err = os.WriteFile(filepath.Join(newTempDir, "base.yaml"), []byte("id: test"), os.ModePerm)
require.Nil(t, err, "could not create base file")
- err = ioutil.WriteFile(filepath.Join(newTempDir, "new.yaml"), []byte("id: test"), os.ModePerm)
+ err = os.WriteFile(filepath.Join(newTempDir, "new.yaml"), []byte("id: test"), os.ModePerm)
require.Nil(t, err, "could not create new file")
- err = ioutil.WriteFile(filepath.Join(newTempDir, ".new-additions"), []byte("new.yaml"), os.ModePerm)
+ err = os.WriteFile(filepath.Join(newTempDir, ".new-additions"), []byte("new.yaml"), os.ModePerm)
require.Nil(t, err, "could not create new file")
err = zipFromDirectory("new.zip", newTempDir)
@@ -57,13 +56,13 @@ func TestDownloadReleaseAndUnzipAddition(t *testing.T) {
func TestDownloadReleaseAndUnzipDeletion(t *testing.T) {
gologger.DefaultLogger.SetWriter(&testutils.NoopWriter{})
- baseTemplates, err := ioutil.TempDir("", "old-temp-*")
+ baseTemplates, err := os.MkdirTemp("", "old-temp-*")
require.Nil(t, err, "could not create temp directory")
defer os.RemoveAll(baseTemplates)
- err = ioutil.WriteFile(filepath.Join(baseTemplates, "base.yaml"), []byte("id: test"), os.ModePerm)
+ err = os.WriteFile(filepath.Join(baseTemplates, "base.yaml"), []byte("id: test"), os.ModePerm)
require.Nil(t, err, "could not create write base file")
- err = ioutil.WriteFile(filepath.Join(baseTemplates, ".new-additions"), []byte("base.yaml"), os.ModePerm)
+ err = os.WriteFile(filepath.Join(baseTemplates, ".new-additions"), []byte("base.yaml"), os.ModePerm)
require.Nil(t, err, "could not create new file")
err = zipFromDirectory("base.zip", baseTemplates)
@@ -75,7 +74,7 @@ func TestDownloadReleaseAndUnzipDeletion(t *testing.T) {
}))
defer ts.Close()
- templatesDirectory, err := ioutil.TempDir("", "template-*")
+ templatesDirectory, err := os.MkdirTemp("", "template-*")
require.Nil(t, err, "could not create temp directory")
defer os.RemoveAll(templatesDirectory)
@@ -85,11 +84,11 @@ func TestDownloadReleaseAndUnzipDeletion(t *testing.T) {
require.Nil(t, err, "could not download release and unzip")
require.Equal(t, "base.yaml", results.additions[0], "could not get correct base addition")
- newTempDir, err := ioutil.TempDir("", "new-tmp-*")
+ newTempDir, err := os.MkdirTemp("", "new-tmp-*")
require.Nil(t, err, "could not create temp directory")
defer os.RemoveAll(newTempDir)
- err = ioutil.WriteFile(filepath.Join(newTempDir, ".new-additions"), []byte(""), os.ModePerm)
+ err = os.WriteFile(filepath.Join(newTempDir, ".new-additions"), []byte(""), os.ModePerm)
require.Nil(t, err, "could not create new file")
err = zipFromDirectory("new.zip", newTempDir)
diff --git a/v2/pkg/catalog/loader/filter/tag_filter.go b/v2/pkg/catalog/loader/filter/tag_filter.go
index 15eca8c8f..65870aaad 100644
--- a/v2/pkg/catalog/loader/filter/tag_filter.go
+++ b/v2/pkg/catalog/loader/filter/tag_filter.go
@@ -4,7 +4,11 @@ import (
"errors"
"strings"
+ "github.com/Knetic/govaluate"
+ "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
+ "github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl"
+ "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
)
@@ -20,6 +24,7 @@ type TagFilter struct {
excludeTypes map[types.ProtocolType]struct{}
allowedIds map[string]struct{}
excludeIds map[string]struct{}
+ includeConditions map[string]*govaluate.EvaluableExpression
}
// ErrExcluded is returned for excluded templates
@@ -30,7 +35,8 @@ var ErrExcluded = errors.New("the template was excluded")
// unless it is explicitly specified by user using the includeTags (matchAllows field).
// Matching rule: (tag1 OR tag2...) AND (author1 OR author2...) AND (severity1 OR severity2...) AND (extraTags1 OR extraTags2...)
// Returns true if the template matches the filter criteria, false otherwise.
-func (tagFilter *TagFilter) Match(templateTags, templateAuthors []string, templateSeverity severity.Severity, extraTags []string, templateType types.ProtocolType, templateId string) (bool, error) {
+func (tagFilter *TagFilter) Match(template *templates.Template, extraTags []string) (bool, error) {
+ templateTags := template.Info.Tags.ToSlice()
for _, templateTag := range templateTags {
_, blocked := tagFilter.block[templateTag]
_, allowed := tagFilter.matchAllows[templateTag]
@@ -48,19 +54,23 @@ func (tagFilter *TagFilter) Match(templateTags, templateAuthors []string, templa
return false, nil
}
- if !isAuthorMatch(tagFilter, templateAuthors) {
+ if !isAuthorMatch(tagFilter, template.Info.Authors.ToSlice()) {
return false, nil
}
- if !isSeverityMatch(tagFilter, templateSeverity) {
+ if !isSeverityMatch(tagFilter, template.Info.SeverityHolder.Severity) {
return false, nil
}
- if !isTemplateTypeMatch(tagFilter, templateType) {
+ if !isTemplateTypeMatch(tagFilter, template.Type()) {
return false, nil
}
- if !isIdMatch(tagFilter, templateId) {
+ if !isIdMatch(tagFilter, strings.ToLower(template.ID)) {
+ return false, nil
+ }
+
+ if !isConditionMatch(tagFilter, template) {
return false, nil
}
@@ -167,6 +177,46 @@ func isIdMatch(tagFilter *TagFilter, templateId string) bool {
return included && !excluded
}
+func isConditionMatch(tagFilter *TagFilter, template *templates.Template) bool {
+ if len(tagFilter.includeConditions) == 0 {
+ return true
+ }
+
+ // attempts to unwrap fields to their basic types
+ // mapping must be manual because of various abstraction layers, custom marshaling and forceful validation
+ parameters := map[string]interface{}{
+ "id": template.ID,
+ "name": template.Info.Name,
+ "description": template.Info.Description,
+ "tags": template.Info.Tags.ToSlice(),
+ "authors": template.Info.Authors.ToSlice(),
+ "severity": template.Info.SeverityHolder.Severity.String(),
+ }
+ for k, v := range template.Info.Metadata {
+ parameters[k] = v
+ }
+ for _, expr := range tagFilter.includeConditions {
+ result, err := expr.Evaluate(parameters)
+ // in case of errors => skip
+ if err != nil {
+ // Using debug as the failure here might be legitimate (eg. template not having optional metadata fields => missing required fields)
+ gologger.Debug().Msgf("The expression condition couldn't be evaluated correctly for template \"%s\": %s\n", template.ID, err)
+ return false
+ }
+ resultBool, ok := result.(bool)
+ // in case the result is not boolean => skip
+ if !ok {
+ return false
+ }
+ // in case the result is false => skip
+ if !resultBool {
+ return false
+ }
+ }
+
+ return true
+}
+
type Config struct {
Tags []string
ExcludeTags []string
@@ -178,12 +228,13 @@ type Config struct {
ExcludeIds []string
Protocols types.ProtocolTypes
ExcludeProtocols types.ProtocolTypes
+ IncludeConditions []string
}
// New returns a tag filter for nuclei tag based execution
//
-// It takes into account Tags, Severities, ExcludeSeverities, Authors, IncludeTags, ExcludeTags.
-func New(config *Config) *TagFilter {
+// It takes into account Tags, Severities, ExcludeSeverities, Authors, IncludeTags, ExcludeTags, Conditions.
+func New(config *Config) (*TagFilter, error) {
filter := &TagFilter{
allowedTags: make(map[string]struct{}),
authors: make(map[string]struct{}),
@@ -195,6 +246,7 @@ func New(config *Config) *TagFilter {
excludeTypes: make(map[types.ProtocolType]struct{}),
allowedIds: make(map[string]struct{}),
excludeIds: make(map[string]struct{}),
+ includeConditions: make(map[string]*govaluate.EvaluableExpression),
}
for _, tag := range config.ExcludeTags {
for _, val := range splitCommaTrim(tag) {
@@ -261,7 +313,14 @@ func New(config *Config) *TagFilter {
delete(filter.excludeIds, val)
}
}
- return filter
+ for _, includeCondition := range config.IncludeConditions {
+ compiled, err := govaluate.NewEvaluableExpressionWithFunctions(includeCondition, dsl.HelperFunctions)
+ if err != nil {
+ return nil, err
+ }
+ filter.includeConditions[includeCondition] = compiled
+ }
+ return filter, nil
}
/*
diff --git a/v2/pkg/catalog/loader/filter/tag_filter_test.go b/v2/pkg/catalog/loader/filter/tag_filter_test.go
index bc112649a..30693adb7 100644
--- a/v2/pkg/catalog/loader/filter/tag_filter_test.go
+++ b/v2/pkg/catalog/loader/filter/tag_filter_test.go
@@ -3,145 +3,252 @@ package filter
import (
"testing"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/dns"
+ "github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
+
"github.com/stretchr/testify/require"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
+ "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice"
+ "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
)
func TestTagBasedFilter(t *testing.T) {
- {
- filter := New(&Config{
- Tags: []string{"cves", "2021", "jira"},
- })
-
- t.Run("true", func(t *testing.T) {
- matched, _ := filter.Match([]string{"jira"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
- require.True(t, matched, "could not get correct match")
- })
- t.Run("false", func(t *testing.T) {
- matched, _ := filter.Match([]string{"consul"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
- require.False(t, matched, "could not get correct match")
- })
- t.Run("match-extra-tags-positive", func(t *testing.T) {
- matched, _ := filter.Match([]string{"cves", "vuln"}, []string{"pdteam"}, severity.Low, []string{"vuln"}, types.HTTPProtocol, "")
- require.True(t, matched, "could not get correct match")
- })
- t.Run("match-extra-tags-negative", func(t *testing.T) {
- matched, _ := filter.Match([]string{"cves"}, []string{"pdteam"}, severity.Low, []string{"vuln"}, types.HTTPProtocol, "")
- require.False(t, matched, "could not get correct match")
- })
+ newDummyTemplate := func(id string, tags, authors []string, severityValue severity.Severity, protocolType types.ProtocolType) *templates.Template {
+ dummyTemplate := &templates.Template{}
+ if id != "" {
+ dummyTemplate.ID = id
+ }
+ if len(tags) > 0 {
+ dummyTemplate.Info.Tags = stringslice.StringSlice{Value: tags}
+ }
+ if len(authors) > 0 {
+ dummyTemplate.Info.Authors = stringslice.StringSlice{Value: authors}
+ }
+ dummyTemplate.Info.SeverityHolder = severity.Holder{Severity: severityValue}
+ switch protocolType {
+ case types.DNSProtocol:
+ dummyTemplate.RequestsDNS = []*dns.Request{{}}
+ case types.HTTPProtocol:
+ dummyTemplate.RequestsHTTP = []*http.Request{{}}
+ }
+ return dummyTemplate
}
+ filter, err := New(&Config{
+ Tags: []string{"cves", "2021", "jira"},
+ })
+ require.Nil(t, err)
+
+ t.Run("true", func(t *testing.T) {
+ dummyTemplate := newDummyTemplate("", []string{"jira"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
+ require.True(t, matched, "could not get correct match")
+ })
+ t.Run("false", func(t *testing.T) {
+ dummyTemplate := newDummyTemplate("", []string{"consul"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
+ require.False(t, matched, "could not get correct match")
+ })
+ t.Run("match-extra-tags-positive", func(t *testing.T) {
+ dummyTemplate := newDummyTemplate("", []string{"cves", "vuln"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, []string{"vuln"})
+ require.True(t, matched, "could not get correct match")
+ })
+ t.Run("match-extra-tags-negative", func(t *testing.T) {
+ dummyTemplate := newDummyTemplate("", []string{"cves"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, []string{"vuln"})
+ require.False(t, matched, "could not get correct match")
+ })
+
t.Run("not-match-excludes", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
ExcludeTags: []string{"dos"},
})
- matched, err := filter.Match([]string{"dos"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"dos"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, err := filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
require.Equal(t, ErrExcluded, err, "could not get correct error")
})
t.Run("match-includes", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Tags: []string{"cves", "fuzz"},
ExcludeTags: []string{"dos", "fuzz"},
IncludeTags: []string{"fuzz"},
})
- matched, err := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, err := filter.Match(dummyTemplate, nil)
require.Nil(t, err, "could not get match")
require.True(t, matched, "could not get correct match")
})
t.Run("match-includes", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Tags: []string{"fuzz"},
ExcludeTags: []string{"fuzz"},
})
- matched, err := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, err := filter.Match(dummyTemplate, nil)
require.Nil(t, err, "could not get match")
require.True(t, matched, "could not get correct match")
})
t.Run("match-author", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Authors: []string{"pdteam"},
})
- matched, _ := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
})
t.Run("match-severity", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Severities: severity.Severities{severity.High},
})
- matched, _ := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.High, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.High, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
})
t.Run("match-id", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
IncludeIds: []string{"cve-test"},
})
- matched, _ := filter.Match([]string{""}, []string{""}, severity.Low, nil, types.HTTPProtocol, "cve-test")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("cve-test", nil, nil, severity.Low, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
})
t.Run("match-exclude-severity", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
ExcludeSeverities: severity.Severities{severity.Low},
})
- matched, _ := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.High, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.High, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
-
- matched, _ = filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ dummyTemplate = newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ = filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
})
t.Run("match-exclude-with-tags", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Tags: []string{"tag"},
ExcludeTags: []string{"another"},
})
- matched, _ := filter.Match([]string{"another"}, []string{"pdteam"}, severity.High, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("", []string{"another"}, []string{"pdteam"}, severity.High, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
})
t.Run("match-conditions", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Authors: []string{"pdteam"},
Tags: []string{"jira"},
Severities: severity.Severities{severity.High},
})
- matched, _ := filter.Match([]string{"jira", "cve"}, []string{"pdteam", "someOtherUser"}, severity.High, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+
+ dummyTemplate := newDummyTemplate("", []string{"jira", "cve"}, []string{"pdteam", "someOtherUser"}, severity.High, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
-
- matched, _ = filter.Match([]string{"jira"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ dummyTemplate = newDummyTemplate("", []string{"jira"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ = filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
-
- matched, _ = filter.Match([]string{"jira"}, []string{"random"}, severity.Low, nil, types.HTTPProtocol, "")
+ dummyTemplate = newDummyTemplate("", []string{"jira"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ = filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
-
- matched, _ = filter.Match([]string{"consul"}, []string{"random"}, severity.Low, nil, types.HTTPProtocol, "")
+ dummyTemplate = newDummyTemplate("", []string{"consul"}, []string{"random"}, severity.Low, types.HTTPProtocol)
+ matched, _ = filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
})
t.Run("match-type", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
Protocols: []types.ProtocolType{types.HTTPProtocol},
})
- matched, _ := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.High, nil, types.HTTPProtocol, "")
+ require.Nil(t, err)
+
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.High, types.HTTPProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
})
t.Run("match-exclude-id", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
ExcludeIds: []string{"cve-test"},
})
- matched, _ := filter.Match([]string{""}, []string{""}, severity.High, nil, types.DNSProtocol, "cve-test1")
+ require.Nil(t, err)
+ dummyTemplate := newDummyTemplate("cve-test1", nil, nil, severity.High, types.DNSProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
require.True(t, matched, "could not get correct match")
-
- matched, _ = filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "cve-test")
+ dummyTemplate = newDummyTemplate("cve-test", []string{"fuzz"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ = filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
})
t.Run("match-exclude-type", func(t *testing.T) {
- filter := New(&Config{
+ filter, err := New(&Config{
ExcludeProtocols: []types.ProtocolType{types.HTTPProtocol},
})
- matched, _ := filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.High, nil, types.DNSProtocol, "")
- require.True(t, matched, "could not get correct match")
+ require.Nil(t, err)
- matched, _ = filter.Match([]string{"fuzz"}, []string{"pdteam"}, severity.Low, nil, types.HTTPProtocol, "")
+ dummyTemplate := newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.High, types.DNSProtocol)
+ matched, _ := filter.Match(dummyTemplate, nil)
+ require.True(t, matched, "could not get correct match")
+ dummyTemplate = newDummyTemplate("", []string{"fuzz"}, []string{"pdteam"}, severity.Low, types.HTTPProtocol)
+ matched, _ = filter.Match(dummyTemplate, nil)
require.False(t, matched, "could not get correct match")
})
+
+ t.Run("advanced-filtering-positive", func(t *testing.T) {
+ dummyTemplate := newDummyTemplate("test", []string{"jira", "test"}, []string{"test1", "test2"}, severity.High, types.HTTPProtocol)
+
+ // syntax error
+ testAdvancedFiltering(t, []string{"id==test'"}, dummyTemplate, true, false)
+ // basic properties
+ testAdvancedFiltering(t, []string{"id=='test'"}, dummyTemplate, false, true)
+ // simple element in slice with 'in' operator, multiple slice elements will require a custom helper function
+ testAdvancedFiltering(t, []string{"contains(tags,'test')"}, dummyTemplate, false, true)
+ testAdvancedFiltering(t, []string{"contains(authors,'test1')"}, dummyTemplate, false, true)
+ // helper function
+ testAdvancedFiltering(t, []string{"contains(id, 'te')"}, dummyTemplate, false, true)
+ testAdvancedFiltering(t, []string{"md5(id)=='098f6bcd4621d373cade4e832627b4f6'"}, dummyTemplate, false, true)
+ // boolean operators
+ testAdvancedFiltering(t, []string{"id!='nothing' && (contains(id, 'te') && id=='test')&& !contains(tags,'no_tag')"}, dummyTemplate, false, true)
+ // create some metadata
+ dummyTemplate.Info.Metadata = make(map[string]interface{})
+ dummyTemplate.Info.Metadata["test_value"] = "test"
+ dummyTemplate.Info.Metadata["bool_value"] = true
+ dummyTemplate.Info.Metadata["number_value"] = 1
+ testAdvancedFiltering(t, []string{"test_value == 'test' && bool_value && number_value>=1"}, dummyTemplate, false, true)
+
+ })
+ t.Run("advanced-filtering-negative", func(t *testing.T) {
+ dummyTemplate := newDummyTemplate("test", []string{"jira"}, []string{"test1", "test2"}, severity.High, types.HTTPProtocol)
+
+ // basic properties
+ testAdvancedFiltering(t, []string{"id=='test1'"}, dummyTemplate, false, false)
+ testAdvancedFiltering(t, []string{"!(id==test') && !contains(tags,'bla')"}, dummyTemplate, true, false)
+ // helper function
+ testAdvancedFiltering(t, []string{"!contains(id, 'bah')"}, dummyTemplate, false, true)
+ // boolean operators with nested negations
+ testAdvancedFiltering(t, []string{"id!='nothing' && !(!contains(id, 'te') && id=='test')&& !contains(tags,'no_tag')"}, dummyTemplate, false, true)
+ // create some metadata
+ dummyTemplate.Info.Metadata = make(map[string]interface{})
+ testAdvancedFiltering(t, []string{"non_existent_value == 'test'"}, dummyTemplate, false, false)
+ })
+}
+
+func testAdvancedFiltering(t *testing.T, includeConditions []string, template *templates.Template, shouldError, shouldMatch bool) {
+ // basic properties
+ advancedFilter, err := New(&Config{IncludeConditions: includeConditions})
+ if shouldError {
+ require.NotNil(t, err)
+ return
+ } else {
+ require.Nil(t, err)
+ }
+ matched, _ := advancedFilter.Match(template, nil)
+ require.Equal(t, shouldMatch, matched, "could not get correct match")
}
diff --git a/v2/pkg/catalog/loader/loader.go b/v2/pkg/catalog/loader/loader.go
index 87b54c257..7b38f2149 100644
--- a/v2/pkg/catalog/loader/loader.go
+++ b/v2/pkg/catalog/loader/loader.go
@@ -38,6 +38,7 @@ type Config struct {
IncludeTags []string
IncludeIds []string
ExcludeIds []string
+ IncludeConditions []string
Catalog catalog.Catalog
ExecutorOptions protocols.ExecuterOptions
@@ -79,6 +80,7 @@ func NewConfig(options *types.Options, templateConfig *config.Config, catalog ca
TemplatesDirectory: templateConfig.TemplatesDirectory,
Protocols: options.Protocols,
ExcludeProtocols: options.ExcludeProtocols,
+ IncludeConditions: options.IncludeConditions,
Catalog: catalog,
ExecutorOptions: executerOpts,
}
@@ -87,21 +89,26 @@ func NewConfig(options *types.Options, templateConfig *config.Config, catalog ca
// New creates a new template store based on provided configuration
func New(config *Config) (*Store, error) {
+ tagFilter, err := filter.New(&filter.Config{
+ Tags: config.Tags,
+ ExcludeTags: config.ExcludeTags,
+ Authors: config.Authors,
+ Severities: config.Severities,
+ ExcludeSeverities: config.ExcludeSeverities,
+ IncludeTags: config.IncludeTags,
+ IncludeIds: config.IncludeIds,
+ ExcludeIds: config.ExcludeIds,
+ Protocols: config.Protocols,
+ ExcludeProtocols: config.ExcludeProtocols,
+ IncludeConditions: config.IncludeConditions,
+ })
+ if err != nil {
+ return nil, err
+ }
// Create a tag filter based on provided configuration
store := &Store{
- config: config,
- tagFilter: filter.New(&filter.Config{
- Tags: config.Tags,
- ExcludeTags: config.ExcludeTags,
- Authors: config.Authors,
- Severities: config.Severities,
- ExcludeSeverities: config.ExcludeSeverities,
- IncludeTags: config.IncludeTags,
- IncludeIds: config.IncludeIds,
- ExcludeIds: config.ExcludeIds,
- Protocols: config.Protocols,
- ExcludeProtocols: config.ExcludeProtocols,
- }),
+ config: config,
+ tagFilter: tagFilter,
pathFilter: filter.NewPathFilter(&filter.PathFilterConfig{
IncludedTemplates: config.IncludeTemplates,
ExcludedTemplates: config.ExcludeTemplates,
diff --git a/v2/pkg/parsers/parser.go b/v2/pkg/parsers/parser.go
index b8e847e8f..e532b3110 100644
--- a/v2/pkg/parsers/parser.go
+++ b/v2/pkg/parsers/parser.go
@@ -9,10 +9,8 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter"
- "github.com/projectdiscovery/nuclei/v2/pkg/model"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/templates/cache"
- "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
)
@@ -38,9 +36,7 @@ func LoadTemplate(templatePath string, tagFilter *filter.TagFilter, extraTags []
return false, validationError
}
- templateId := strings.ToLower(template.ID)
-
- return isTemplateInfoMetadataMatch(tagFilter, &template.Info, extraTags, template.Type(), templateId)
+ return isTemplateInfoMetadataMatch(tagFilter, template, extraTags)
}
// LoadWorkflow returns true if the workflow is valid and matches the filtering criteria.
@@ -60,12 +56,8 @@ func LoadWorkflow(templatePath string, catalog catalog.Catalog) (bool, error) {
return false, nil
}
-func isTemplateInfoMetadataMatch(tagFilter *filter.TagFilter, templateInfo *model.Info, extraTags []string, templateType types.ProtocolType, templateId string) (bool, error) {
- templateTags := templateInfo.Tags.ToSlice()
- templateAuthors := templateInfo.Authors.ToSlice()
- templateSeverity := templateInfo.SeverityHolder.Severity
-
- match, err := tagFilter.Match(templateTags, templateAuthors, templateSeverity, extraTags, templateType, templateId)
+func isTemplateInfoMetadataMatch(tagFilter *filter.TagFilter, template *templates.Template, extraTags []string) (bool, error) {
+ match, err := tagFilter.Match(template, extraTags)
if err == filter.ErrExcluded {
return false, filter.ErrExcluded
diff --git a/v2/pkg/parsers/parser_test.go b/v2/pkg/parsers/parser_test.go
index 9eb66016e..a16e00ddf 100644
--- a/v2/pkg/parsers/parser_test.go
+++ b/v2/pkg/parsers/parser_test.go
@@ -57,7 +57,8 @@ func TestLoadTemplate(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
parsedTemplatesCache.Store(tc.name, tc.template, tc.templateErr)
- tagFilter := filter.New(&filter.Config{})
+ tagFilter, err := filter.New(&filter.Config{})
+ require.Nil(t, err)
success, err := LoadTemplate(tc.name, tagFilter, nil, catalog)
if tc.expectedErr == nil {
require.NoError(t, err)
@@ -98,7 +99,8 @@ func TestLoadTemplate(t *testing.T) {
}
parsedTemplatesCache.Store(name, template, nil)
- tagFilter := filter.New(&filter.Config{})
+ tagFilter, err := filter.New(&filter.Config{})
+ require.Nil(t, err)
success, err := LoadTemplate(name, tagFilter, nil, catalog)
if tc.success {
require.NoError(t, err)
diff --git a/v2/pkg/parsers/workflow_loader.go b/v2/pkg/parsers/workflow_loader.go
index 70669e9ba..505b4b774 100644
--- a/v2/pkg/parsers/workflow_loader.go
+++ b/v2/pkg/parsers/workflow_loader.go
@@ -15,19 +15,24 @@ type workflowLoader struct {
// NewLoader returns a new workflow loader structure
func NewLoader(options *protocols.ExecuterOptions) (model.WorkflowLoader, error) {
- tagFilter := filter.New(&filter.Config{
- Tags: options.Options.Tags,
- ExcludeTags: options.Options.ExcludeTags,
- Authors: options.Options.Authors,
- Severities: options.Options.Severities,
- IncludeTags: options.Options.IncludeTags,
- IncludeIds: options.Options.IncludeIds,
- ExcludeIds: options.Options.ExcludeIds,
+ tagFilter, err := filter.New(&filter.Config{
+ Tags: options.Options.Tags,
+ ExcludeTags: options.Options.ExcludeTags,
+ Authors: options.Options.Authors,
+ Severities: options.Options.Severities,
+ IncludeTags: options.Options.IncludeTags,
+ IncludeIds: options.Options.IncludeIds,
+ ExcludeIds: options.Options.ExcludeIds,
+ IncludeConditions: options.Options.IncludeConditions,
})
+ if err != nil {
+ return nil, err
+ }
pathFilter := filter.NewPathFilter(&filter.PathFilterConfig{
IncludedTemplates: options.Options.IncludeTemplates,
ExcludedTemplates: options.Options.ExcludedTemplates,
}, options.Catalog)
+
return &workflowLoader{pathFilter: pathFilter, tagFilter: tagFilter, options: options}, nil
}
diff --git a/v2/pkg/projectfile/httputil.go b/v2/pkg/projectfile/httputil.go
index 6be0b40db..3f00b8e81 100644
--- a/v2/pkg/projectfile/httputil.go
+++ b/v2/pkg/projectfile/httputil.go
@@ -6,7 +6,6 @@ import (
"encoding/gob"
"encoding/hex"
"io"
- "io/ioutil"
"net/http"
)
@@ -105,6 +104,6 @@ func fromInternalResponse(intResp *InternalResponse) *http.Response {
StatusCode: intResp.StatusCode,
Header: intResp.Headers,
ContentLength: contentLength,
- Body: ioutil.NopCloser(bytes.NewReader(intResp.Body)),
+ Body: io.NopCloser(bytes.NewReader(intResp.Body)),
}
}
diff --git a/v2/pkg/protocols/common/automaticscan/automaticscan.go b/v2/pkg/protocols/common/automaticscan/automaticscan.go
index 7821784bc..0e6f1137b 100644
--- a/v2/pkg/protocols/common/automaticscan/automaticscan.go
+++ b/v2/pkg/protocols/common/automaticscan/automaticscan.go
@@ -2,7 +2,6 @@ package automaticscan
import (
"io"
- "io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -19,6 +18,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/retryablehttp-go"
+ "github.com/projectdiscovery/sliceutil"
wappalyzer "github.com/projectdiscovery/wappalyzergo"
"gopkg.in/yaml.v2"
)
@@ -159,7 +159,7 @@ func (s *Service) processWappalyzerInputPair(input string) {
return
}
reader := io.LimitReader(resp.Body, maxDefaultBody)
- data, err := ioutil.ReadAll(reader)
+ data, err := io.ReadAll(reader)
if err != nil {
resp.Body.Close()
return
@@ -196,7 +196,7 @@ func (s *Service) processWappalyzerInputPair(input string) {
if len(items) == 0 {
return
}
- uniqueTags := uniqueSlice(items)
+ uniqueTags := sliceutil.Dedupe(items)
templatesList := s.store.LoadTemplatesWithTags(s.allTemplates, uniqueTags)
gologger.Info().Msgf("Executing tags (%v) for host %s (%d templates)", strings.Join(uniqueTags, ","), input, len(templatesList))
@@ -221,17 +221,3 @@ func normalizeAppName(appName string) string {
}
return strings.ToLower(appName)
}
-
-func uniqueSlice(slice []string) []string {
- data := make(map[string]struct{}, len(slice))
- for _, item := range slice {
- if _, ok := data[item]; !ok {
- data[item] = struct{}{}
- }
- }
- finalSlice := make([]string, 0, len(data))
- for item := range data {
- finalSlice = append(finalSlice, item)
- }
- return finalSlice
-}
diff --git a/v2/pkg/protocols/file/find_test.go b/v2/pkg/protocols/file/find_test.go
index 5f8ee41c6..f14cd7334 100644
--- a/v2/pkg/protocols/file/find_test.go
+++ b/v2/pkg/protocols/file/find_test.go
@@ -1,7 +1,6 @@
package file
import (
- "io/ioutil"
"os"
"path/filepath"
"testing"
@@ -32,7 +31,7 @@ func TestFindInputPaths(t *testing.T) {
err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request")
- tempDir, err := ioutil.TempDir("", "test-*")
+ tempDir, err := os.MkdirTemp("", "test-*")
require.Nil(t, err, "could not create temporary directory")
defer os.RemoveAll(tempDir)
@@ -44,7 +43,7 @@ func TestFindInputPaths(t *testing.T) {
"test.js": "TEST",
}
for k, v := range files {
- err = ioutil.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm)
+ err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm)
require.Nil(t, err, "could not write temporary file")
}
expected := []string{"config.yaml", "final.yaml", "test.js"}
diff --git a/v2/pkg/protocols/file/request_test.go b/v2/pkg/protocols/file/request_test.go
index 268f9c509..74aea078f 100644
--- a/v2/pkg/protocols/file/request_test.go
+++ b/v2/pkg/protocols/file/request_test.go
@@ -1,7 +1,6 @@
package file
import (
- "io/ioutil"
"os"
"path/filepath"
"testing"
@@ -50,7 +49,7 @@ func TestFileExecuteWithResults(t *testing.T) {
err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request")
- tempDir, err := ioutil.TempDir("", "test-*")
+ tempDir, err := os.MkdirTemp("", "test-*")
require.Nil(t, err, "could not create temporary directory")
defer os.RemoveAll(tempDir)
@@ -58,7 +57,7 @@ func TestFileExecuteWithResults(t *testing.T) {
"config.yaml": "TEST\r\n1.1.1.1\r\n",
}
for k, v := range files {
- err = ioutil.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm)
+ err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm)
require.Nil(t, err, "could not write temporary file")
}
diff --git a/v2/pkg/protocols/headless/engine/engine.go b/v2/pkg/protocols/headless/engine/engine.go
index 9f40ab751..695fb4bfd 100644
--- a/v2/pkg/protocols/headless/engine/engine.go
+++ b/v2/pkg/protocols/headless/engine/engine.go
@@ -2,7 +2,6 @@ package engine
import (
"fmt"
- "io/ioutil"
"net/http"
"os"
"runtime"
@@ -30,7 +29,7 @@ type Browser struct {
// New creates a new nuclei headless browser module
func New(options *types.Options) (*Browser, error) {
- dataStore, err := ioutil.TempDir("", "nuclei-*")
+ dataStore, err := os.MkdirTemp("", "nuclei-*")
if err != nil {
return nil, errors.Wrap(err, "could not create temporary directory")
}
diff --git a/v2/pkg/protocols/headless/engine/page_actions.go b/v2/pkg/protocols/headless/engine/page_actions.go
index 5b2b60ed2..cfb2910bb 100644
--- a/v2/pkg/protocols/headless/engine/page_actions.go
+++ b/v2/pkg/protocols/headless/engine/page_actions.go
@@ -2,9 +2,9 @@ package engine
import (
"context"
- "io/ioutil"
"net"
"net/url"
+ "os"
"regexp"
"strconv"
"strings"
@@ -348,7 +348,7 @@ func (p *Page) Screenshot(act *Action, out map[string]string) error {
if err != nil {
return errors.Wrap(err, "could not take screenshot")
}
- err = ioutil.WriteFile(to+".png", data, 0540)
+ err = os.WriteFile(to+".png", data, 0540)
if err != nil {
return errors.Wrap(err, "could not write screenshot")
}
diff --git a/v2/pkg/protocols/http/build_request.go b/v2/pkg/protocols/http/build_request.go
index 64471f90c..43df543d0 100644
--- a/v2/pkg/protocols/http/build_request.go
+++ b/v2/pkg/protocols/http/build_request.go
@@ -5,7 +5,6 @@ import (
"context"
"fmt"
"io"
- "io/ioutil"
"net"
"net/http"
"net/url"
@@ -273,7 +272,7 @@ func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest
// retryablehttp
var body io.ReadCloser
- body = ioutil.NopCloser(strings.NewReader(rawRequestData.Data))
+ body = io.NopCloser(strings.NewReader(rawRequestData.Data))
if r.request.Race {
// More or less this ensures that all requests hit the endpoint at the same approximated time
// Todo: sync internally upon writing latest request byte
@@ -337,7 +336,7 @@ func (r *requestGenerator) fillRequest(req *http.Request, values map[string]inte
if err != nil {
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
}
- req.Body = ioutil.NopCloser(strings.NewReader(body))
+ req.Body = io.NopCloser(strings.NewReader(body))
}
if !r.request.Unsafe {
setHeader(req, "User-Agent", uarand.GetRandom())
diff --git a/v2/pkg/protocols/http/request.go b/v2/pkg/protocols/http/request.go
index 235516a6e..2cf4a1b4c 100644
--- a/v2/pkg/protocols/http/request.go
+++ b/v2/pkg/protocols/http/request.go
@@ -6,7 +6,6 @@ import (
"encoding/hex"
"fmt"
"io"
- "io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
@@ -403,7 +402,7 @@ func (request *Request) executeRequest(reqURL string, generatedRequest *generate
if parsed, parseErr := url.Parse(formedURL); parseErr == nil {
hostname = parsed.Host
}
- resp, err = generatedRequest.pipelinedClient.DoRaw(generatedRequest.rawRequest.Method, reqURL, generatedRequest.rawRequest.Path, generators.ExpandMapValues(generatedRequest.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(generatedRequest.rawRequest.Data)))
+ resp, err = generatedRequest.pipelinedClient.DoRaw(generatedRequest.rawRequest.Method, reqURL, generatedRequest.rawRequest.Path, generators.ExpandMapValues(generatedRequest.rawRequest.Headers), io.NopCloser(strings.NewReader(generatedRequest.rawRequest.Data)))
} else if generatedRequest.request != nil {
resp, err = generatedRequest.pipelinedClient.Dor(generatedRequest.request)
}
@@ -421,7 +420,7 @@ func (request *Request) executeRequest(reqURL string, generatedRequest *generate
options.CustomRawBytes = generatedRequest.rawRequest.UnsafeRawBytes
options.ForceReadAllBody = request.ForceReadAllBody
options.SNI = request.options.Options.SNI
- resp, err = generatedRequest.original.rawhttpClient.DoRawWithOptions(generatedRequest.rawRequest.Method, reqURL, generatedRequest.rawRequest.Path, generators.ExpandMapValues(generatedRequest.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(generatedRequest.rawRequest.Data)), &options)
+ resp, err = generatedRequest.original.rawhttpClient.DoRawWithOptions(generatedRequest.rawRequest.Method, reqURL, generatedRequest.rawRequest.Path, generators.ExpandMapValues(generatedRequest.rawRequest.Headers), io.NopCloser(strings.NewReader(generatedRequest.rawRequest.Data)), &options)
} else {
hostname = generatedRequest.request.URL.Host
formedURL = generatedRequest.request.URL.String()
@@ -469,7 +468,7 @@ func (request *Request) executeRequest(reqURL string, generatedRequest *generate
if err != nil {
// rawhttp doesn't support draining response bodies.
if resp != nil && resp.Body != nil && generatedRequest.rawRequest == nil && !generatedRequest.original.Pipeline {
- _, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize)
+ _, _ = io.CopyN(io.Discard, resp.Body, drainReqSize)
resp.Body.Close()
}
request.options.Output.Request(request.options.TemplatePath, formedURL, request.Type().String(), err)
@@ -494,7 +493,7 @@ func (request *Request) executeRequest(reqURL string, generatedRequest *generate
}
defer func() {
if resp.StatusCode != http.StatusSwitchingProtocols {
- _, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize)
+ _, _ = io.CopyN(io.Discard, resp.Body, drainReqSize)
}
resp.Body.Close()
}()
@@ -502,7 +501,7 @@ func (request *Request) executeRequest(reqURL string, generatedRequest *generate
var curlCommand string
if !request.Unsafe && resp != nil && generatedRequest.request != nil && resp.Request != nil && !request.Race {
bodyBytes, _ := generatedRequest.request.BodyBytes()
- resp.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
+ resp.Request.Body = io.NopCloser(bytes.NewReader(bodyBytes))
command, _ := http2curl.GetCurlCommand(resp.Request)
if err == nil && command != nil {
curlCommand = command.String()
diff --git a/v2/pkg/protocols/http/utils.go b/v2/pkg/protocols/http/utils.go
index 1fd93bcbf..ef085858b 100644
--- a/v2/pkg/protocols/http/utils.go
+++ b/v2/pkg/protocols/http/utils.go
@@ -6,7 +6,6 @@ import (
"compress/zlib"
"context"
"io"
- "io/ioutil"
"net/http"
"net/http/httputil"
"strings"
@@ -124,7 +123,7 @@ func dump(req *generatedRequest, reqURL string) ([]byte, error) {
if len(bodyBytes) > 0 {
dumpBody = true
cloned.ContentLength = int64(len(bodyBytes))
- cloned.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
+ cloned.Body = io.NopCloser(bytes.NewReader(bodyBytes))
} else {
cloned.ContentLength = 0
cloned.Body = nil
@@ -138,7 +137,7 @@ func dump(req *generatedRequest, reqURL string) ([]byte, error) {
return dumpBytes, nil
}
rawHttpOptions := &rawhttp.Options{CustomHeaders: req.rawRequest.UnsafeHeaders, CustomRawBytes: req.rawRequest.UnsafeRawBytes}
- return rawhttp.DumpRequestRaw(req.rawRequest.Method, reqURL, req.rawRequest.Path, generators.ExpandMapValues(req.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(req.rawRequest.Data)), rawHttpOptions)
+ return rawhttp.DumpRequestRaw(req.rawRequest.Method, reqURL, req.rawRequest.Path, generators.ExpandMapValues(req.rawRequest.Headers), io.NopCloser(strings.NewReader(req.rawRequest.Data)), rawHttpOptions)
}
// handleDecompression if the user specified a custom encoding (as golang transport doesn't do this automatically)
diff --git a/v2/pkg/protocols/offlinehttp/find_test.go b/v2/pkg/protocols/offlinehttp/find_test.go
index 367d00096..333e3b218 100644
--- a/v2/pkg/protocols/offlinehttp/find_test.go
+++ b/v2/pkg/protocols/offlinehttp/find_test.go
@@ -1,7 +1,6 @@
package offlinehttp
import (
- "io/ioutil"
"os"
"path/filepath"
"testing"
@@ -28,7 +27,7 @@ func TestFindResponses(t *testing.T) {
err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request")
- tempDir, err := ioutil.TempDir("", "test-*")
+ tempDir, err := os.MkdirTemp("", "test-*")
require.Nil(t, err, "could not create temporary directory")
defer os.RemoveAll(tempDir)
@@ -40,7 +39,7 @@ func TestFindResponses(t *testing.T) {
"test.txt": "TEST",
}
for k, v := range files {
- err = ioutil.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm)
+ err = os.WriteFile(filepath.Join(tempDir, k), []byte(v), os.ModePerm)
require.Nil(t, err, "could not write temporary file")
}
expected := []string{"config.txt", "final.txt", "test.txt"}
diff --git a/v2/pkg/reporting/dedupe/dedupe.go b/v2/pkg/reporting/dedupe/dedupe.go
index 7a688581d..c56e2205b 100644
--- a/v2/pkg/reporting/dedupe/dedupe.go
+++ b/v2/pkg/reporting/dedupe/dedupe.go
@@ -6,7 +6,6 @@ package dedupe
import (
"crypto/sha1"
- "io/ioutil"
"os"
"reflect"
"unsafe"
@@ -30,7 +29,7 @@ func New(dbPath string) (*Storage, error) {
var err error
if dbPath == "" {
- dbPath, err = ioutil.TempDir("", "nuclei-report-*")
+ dbPath, err = os.MkdirTemp("", "nuclei-report-*")
storage.temporary = dbPath
}
if err != nil {
diff --git a/v2/pkg/reporting/dedupe/dedupe_test.go b/v2/pkg/reporting/dedupe/dedupe_test.go
index eb5014425..db9ef670b 100644
--- a/v2/pkg/reporting/dedupe/dedupe_test.go
+++ b/v2/pkg/reporting/dedupe/dedupe_test.go
@@ -1,7 +1,6 @@
package dedupe
import (
- "io/ioutil"
"os"
"testing"
@@ -11,7 +10,7 @@ import (
)
func TestDedupeDuplicates(t *testing.T) {
- tempDir, err := ioutil.TempDir("", "nuclei")
+ tempDir, err := os.MkdirTemp("", "nuclei")
require.Nil(t, err, "could not create temporary storage")
defer os.RemoveAll(tempDir)
diff --git a/v2/pkg/reporting/exporters/es/elasticsearch.go b/v2/pkg/reporting/exporters/es/elasticsearch.go
index 545ab9487..de1663abf 100644
--- a/v2/pkg/reporting/exporters/es/elasticsearch.go
+++ b/v2/pkg/reporting/exporters/es/elasticsearch.go
@@ -7,7 +7,6 @@ import (
"encoding/json"
"fmt"
"io"
- "io/ioutil"
"net/http"
"time"
@@ -111,7 +110,7 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
if err != nil {
return err
}
- req.Body = ioutil.NopCloser(bytes.NewReader(b))
+ req.Body = io.NopCloser(bytes.NewReader(b))
res, err := exporter.elasticsearch.Do(req)
if err != nil {
diff --git a/v2/pkg/reporting/exporters/markdown/markdown.go b/v2/pkg/reporting/exporters/markdown/markdown.go
index 3540d60bb..d19956d67 100644
--- a/v2/pkg/reporting/exporters/markdown/markdown.go
+++ b/v2/pkg/reporting/exporters/markdown/markdown.go
@@ -2,7 +2,6 @@ package markdown
import (
"bytes"
- "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -67,7 +66,7 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
dataBuilder.WriteString(description)
data := dataBuilder.Bytes()
- return ioutil.WriteFile(filepath.Join(exporter.directory, finalFilename), data, 0644)
+ return os.WriteFile(filepath.Join(exporter.directory, finalFilename), data, 0644)
}
// Close closes the exporter after operation
diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go
index bddbb84b4..e9938863c 100644
--- a/v2/pkg/types/types.go
+++ b/v2/pkg/types/types.go
@@ -236,6 +236,8 @@ type Options struct {
InputReadTimeout time.Duration
// Disable stdin for input processing
DisableStdin bool
+ // IncludeConditions is the list of conditions templates should match
+ IncludeConditions goflags.FileStringSlice
// Custom Config Directory
CustomConfigDir string
}
diff --git a/v2/pkg/utils/monitor/monitor.go b/v2/pkg/utils/monitor/monitor.go
index 84196afe6..a74cb264e 100644
--- a/v2/pkg/utils/monitor/monitor.go
+++ b/v2/pkg/utils/monitor/monitor.go
@@ -7,7 +7,6 @@ import (
"bytes"
"context"
"fmt"
- "io/ioutil"
"os"
"runtime"
"strings"
@@ -80,7 +79,7 @@ func (s *Agent) monitorWorker() {
s.cancel()
stackTraceFile := fmt.Sprintf("nuclei-stacktrace-%s.dump", xid.New().String())
gologger.Error().Msgf("Detected hanging goroutine (count=%d/%d) = %s\n", current, s.goroutineCount, stackTraceFile)
- if err := ioutil.WriteFile(stackTraceFile, currentStack, os.ModePerm); err != nil {
+ if err := os.WriteFile(stackTraceFile, currentStack, os.ModePerm); err != nil {
gologger.Error().Msgf("Could not write stack trace for goroutines: %s\n", err)
}
os.Exit(1) // exit forcefully if we've been stuck
From 011da1388d34c1f76cce9e03cbb057b53eb7ef61 Mon Sep 17 00:00:00 2001
From: Sajad
Date: Thu, 25 Aug 2022 17:42:35 +0530
Subject: [PATCH 23/25] add option to specify network interface (#2384)
* add option to specify network interface
* add source-ip flag
* fix typo
* fix err return
* readme update
Co-authored-by: Sandeep Singh
---
README.md | 3 +
v2/cmd/nuclei/main.go | 2 +
.../protocols/common/protocolstate/state.go | 97 +++++++++++++++++++
v2/pkg/types/types.go | 4 +
4 files changed, 106 insertions(+)
diff --git a/README.md b/README.md
index d17009052..161b82e26 100644
--- a/README.md
+++ b/README.md
@@ -142,6 +142,7 @@ OUTPUT:
CONFIGURATIONS:
-config string path to the nuclei configuration file
+ -config-directory string override the default config path ($home/.config)
-fr, -follow-redirects enable following redirects for http templates
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
-dr, -disable-redirects disable redirects for http templates
@@ -158,6 +159,8 @@ 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)
+ -i, -interface string network interface to use for network scan
+ -sip, -source-ip string source ip address to use for network scan
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)
diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go
index f066ffa14..72dc98108 100644
--- a/v2/cmd/nuclei/main.go
+++ b/v2/cmd/nuclei/main.go
@@ -183,6 +183,8 @@ 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.StringVarP(&options.Interface, "interface", "i", "", "network interface to use for network scan"),
+ 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)"),
)
diff --git a/v2/pkg/protocols/common/protocolstate/state.go b/v2/pkg/protocols/common/protocolstate/state.go
index a08cb7076..e422c0d13 100644
--- a/v2/pkg/protocols/common/protocolstate/state.go
+++ b/v2/pkg/protocols/common/protocolstate/state.go
@@ -1,6 +1,9 @@
package protocolstate
import (
+ "fmt"
+ "net"
+
"github.com/pkg/errors"
"github.com/projectdiscovery/fastdialer/fastdialer"
@@ -16,6 +19,48 @@ func Init(options *types.Options) error {
return nil
}
opts := fastdialer.DefaultOptions
+
+ switch {
+ case options.SourceIP != "" && options.Interface != "":
+ isAssociated, err := isIpAssociatedWithInterface(options.SourceIP, options.Interface)
+ if err != nil {
+ return err
+ }
+ if isAssociated {
+ opts.Dialer = &net.Dialer{
+ LocalAddr: &net.TCPAddr{
+ IP: net.ParseIP(options.SourceIP),
+ },
+ }
+ } else {
+ return fmt.Errorf("source ip (%s) is not associated with the interface (%s)", options.SourceIP, options.Interface)
+ }
+ case options.SourceIP != "":
+ isAssociated, err := isIpAssociatedWithInterface(options.SourceIP, "any")
+ if err != nil {
+ return err
+ }
+ if isAssociated {
+ opts.Dialer = &net.Dialer{
+ LocalAddr: &net.TCPAddr{
+ IP: net.ParseIP(options.SourceIP),
+ },
+ }
+ } else {
+ return fmt.Errorf("source ip (%s) is not associated with any network interface", options.SourceIP)
+ }
+ case options.Interface != "":
+ ifadrr, err := interfaceAddress(options.Interface)
+ if err != nil {
+ return err
+ }
+ opts.Dialer = &net.Dialer{
+ LocalAddr: &net.TCPAddr{
+ IP: ifadrr,
+ },
+ }
+ }
+
if options.SystemResolvers {
opts.EnableFallback = true
}
@@ -33,6 +78,58 @@ func Init(options *types.Options) error {
return nil
}
+// isIpAssociatedWithInterface checks if the given IP is associated with the given interface.
+func isIpAssociatedWithInterface(souceIP, interfaceName string) (bool, error) {
+ addrs, err := interfaceAddresses(interfaceName)
+ if err != nil {
+ return false, err
+ }
+ for _, addr := range addrs {
+ if ipnet, ok := addr.(*net.IPNet); ok {
+ if ipnet.IP.String() == souceIP {
+ return true, nil
+ }
+ }
+ }
+ return false, nil
+}
+
+// interfaceAddress returns the first IPv4 address of the given interface.
+func interfaceAddress(interfaceName string) (net.IP, error) {
+ addrs, err := interfaceAddresses(interfaceName)
+ if err != nil {
+ return nil, err
+ }
+ var address net.IP
+ for _, addr := range addrs {
+ if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To4() != nil {
+ address = ipnet.IP
+ }
+ }
+ }
+ if address == nil {
+ return nil, fmt.Errorf("no suitable address found for interface: `%s`", interfaceName)
+ }
+ return address, nil
+}
+
+// interfaceAddresses returns all interface addresses.
+func interfaceAddresses(interfaceName string) ([]net.Addr, error) {
+ if interfaceName == "any" {
+ return net.InterfaceAddrs()
+ }
+ ief, err := net.InterfaceByName(interfaceName)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to get interface: `%s`", interfaceName)
+ }
+ addrs, err := ief.Addrs()
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to get interface addresses for: `%s`", interfaceName)
+ }
+ return addrs, nil
+}
+
// Close closes the global shared fastdialer
func Close() {
if Dialer != nil {
diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go
index e9938863c..8d7107897 100644
--- a/v2/pkg/types/types.go
+++ b/v2/pkg/types/types.go
@@ -230,6 +230,10 @@ type Options struct {
DisableRedirects bool
// SNI custom hostname
SNI string
+ // Interface to use for network scan
+ Interface string
+ // SourceIP sets custom source IP address for network requests
+ SourceIP string
// Health Check
HealthCheck bool
// Time to wait between each input read operation before closing the stream
From efdc57c7b26358c6b5e23d27e96b6522eb6184ee Mon Sep 17 00:00:00 2001
From: sandeep
Date: Fri, 26 Aug 2022 14:18:32 +0530
Subject: [PATCH 24/25] version update
---
v2/pkg/catalog/config/config.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v2/pkg/catalog/config/config.go b/v2/pkg/catalog/config/config.go
index 69a034020..840d15fa1 100644
--- a/v2/pkg/catalog/config/config.go
+++ b/v2/pkg/catalog/config/config.go
@@ -28,7 +28,7 @@ type Config struct {
const nucleiConfigFilename = ".templates-config.json"
// Version is the current version of nuclei
-const Version = `2.7.6`
+const Version = `2.7.7`
var customConfigDirectory string
From 8f8ab429fffa2e0e3c76172e8e7c9c489748b2ef Mon Sep 17 00:00:00 2001
From: sandeep
Date: Fri, 26 Aug 2022 14:20:18 +0530
Subject: [PATCH 25/25] readme update
---
README.md | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 161b82e26..bafcf3077 100644
--- a/README.md
+++ b/README.md
@@ -111,19 +111,20 @@ 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
+ -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
@@ -142,7 +143,6 @@ OUTPUT:
CONFIGURATIONS:
-config string path to the nuclei configuration file
- -config-directory string override the default config path ($home/.config)
-fr, -follow-redirects enable following redirects for http templates
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
-dr, -disable-redirects disable redirects for http templates
@@ -161,6 +161,7 @@ CONFIGURATIONS:
-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)
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)
@@ -192,10 +193,10 @@ OPTIMIZATIONS:
-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
+ -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:
@@ -209,6 +210,7 @@ DEBUG:
-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