Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into cloud-bug-fixes

dev
Ice3man 2022-12-28 20:43:12 +05:30
commit ded218a88a
27 changed files with 645 additions and 197 deletions

View File

@ -12,6 +12,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: "Set up Go"
uses: actions/setup-go@v3
@ -36,7 +38,6 @@ jobs:
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git pull
git add SYNTAX-REFERENCE.md nuclei-jsonschema.json
git commit -m "Auto Generate Syntax Docs + JSONSchema [$(date)] :robot:" -a

View File

@ -59,6 +59,23 @@ Nuclei requires **go1.18** to install successfully. Run the following command to
go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
```
<details>
<summary>Brew</summary>
```sh
brew install nuclei
```
</details>
<details>
<summary>Docker</summary>
```sh
docker pull projectdiscovery/nuclei:latest
```
</details>
**More installation [methods can be found here](https://nuclei.projectdiscovery.io/nuclei/get-started/).**
<table>
@ -369,6 +386,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
@ -439,7 +457,13 @@ func main() {
}
store.Load()
input := &inputs.SimpleInputProvider{Inputs: []string{"docs.hackerone.com"}}
inputArgs := []*contextargs.MetaInput{
&contextargs.MetaInput{
Input: "docs.hackerone.com",
},
}
input := &inputs.SimpleInputProvider{Inputs: inputArgs}
_ = engine.Execute(store.Templates(), input)
engine.WorkPool().Wait() // Wait for the scan to finish
}

View File

@ -3519,6 +3519,19 @@ description: |
<div class="dd">
<code>stop-at-first-match</code> <i>bool</i>
</div>
<div class="dt">
StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.
</div>
<hr />
<div class="dd">
<code>matchers</code> <i>[]<a href="#matchersmatcher">matchers.Matcher</a></i>
</div>

View File

@ -576,6 +576,11 @@
"title": "custom user agent for the headless request",
"description": "Custom user agent for the headless request"
},
"stop-at-first-match": {
"type": "boolean",
"title": "stop at first match",
"description": "Stop the execution after a match is found"
},
"matchers": {
"items": {
"$ref": "#/definitions/matchers.Matcher"

View File

@ -93,13 +93,15 @@ func executeNucleiAsCode(templatePath, templateURL string) ([]string, error) {
home, _ := os.UserHomeDir()
catalog := disk.NewCatalog(path.Join(home, "nuclei-templates"))
ratelimiter := ratelimit.New(context.Background(), 150, time.Second)
defer ratelimiter.Stop()
executerOpts := protocols.ExecuterOptions{
Output: outputWriter,
Options: defaultOpts,
Progress: mockProgress,
Catalog: catalog,
IssuesClient: reportingClient,
RateLimiter: ratelimit.New(context.Background(), 150, time.Second),
RateLimiter: ratelimiter,
Interactsh: interactClient,
HostErrorsCache: cache,
Colorizer: aurora.NewAurora(true),

View File

@ -82,6 +82,7 @@ func main() {
// Setup graceful exits
resumeFileName := types.DefaultResumeFilePath()
c := make(chan os.Signal, 1)
defer close(c)
signal.Notify(c, os.Interrupt)
go func() {
for range c {
@ -123,21 +124,21 @@ on extensive configurability, massive extensibility and ease of use.`)
*/
flagSet.CreateGroup("input", "Target",
flagSet.StringSliceVarP(&options.Targets, "target", "u", []string{}, "target URLs/hosts to scan", goflags.StringSliceOptions),
flagSet.StringSliceVarP(&options.Targets, "target", "u", nil, "target URLs/hosts to scan", goflags.StringSliceOptions),
flagSet.StringVarP(&options.TargetsFilePath, "list", "l", "", "path to file containing a list of target URLs/hosts to scan (one per line)"),
flagSet.StringVar(&options.Resume, "resume", "", "resume scan using resume.cfg (clustering will be disabled)"),
flagSet.BoolVarP(&options.ScanAllIPs, "scan-all-ips", "sa", false, "scan all the IP's associated with dns record"),
flagSet.StringSliceVarP(&options.IPVersion, "ip-version", "iv", []string{""}, "IP version to scan of hostname (4,6) - (default 4)", goflags.CommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.IPVersion, "ip-version", "iv", nil, "IP version to scan of hostname (4,6) - (default 4)", goflags.CommaSeparatedStringSliceOptions),
)
flagSet.CreateGroup("templates", "Templates",
flagSet.BoolVarP(&options.NewTemplates, "new-templates", "nt", false, "run only new templates added in latest nuclei-templates release"),
flagSet.StringSliceVarP(&options.NewTemplatesWithVersion, "new-templates-version", "ntv", []string{}, "run new templates added in specific version", goflags.CommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.NewTemplatesWithVersion, "new-templates-version", "ntv", nil, "run new templates added in specific version", goflags.CommaSeparatedStringSliceOptions),
flagSet.BoolVarP(&options.AutomaticScan, "automatic-scan", "as", false, "automatic web scan using wappalyzer technology detection to tags mapping"),
flagSet.StringSliceVarP(&options.Templates, "templates", "t", []string{}, "list of template or template directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.TemplateURLs, "template-url", "tu", []string{}, "list of template urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Workflows, "workflows", "w", []string{}, "list of workflow or workflow directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.WorkflowURLs, "workflow-url", "wu", []string{}, "list of workflow urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Templates, "templates", "t", nil, "list of template or template directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.TemplateURLs, "template-url", "tu", nil, "list of template urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Workflows, "workflows", "w", nil, "list of workflow or workflow directory to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.WorkflowURLs, "workflow-url", "wu", nil, "list of workflow urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.BoolVar(&options.Validate, "validate", false, "validate the passed templates to nuclei"),
flagSet.BoolVarP(&options.NoStrictSyntax, "no-strict-syntax", "nss", false, "disable strict syntax check on templates"),
flagSet.BoolVarP(&options.TemplateDisplay, "template-display", "td", false, "displays the templates content"),
@ -146,15 +147,15 @@ on extensive configurability, massive extensibility and ease of use.`)
)
flagSet.CreateGroup("filters", "Filtering",
flagSet.StringSliceVarP(&options.Authors, "author", "a", []string{}, "templates to run based on authors (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVar(&options.Tags, "tags", []string{}, "templates to run based on tags (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeTags, "exclude-tags", "etags", []string{}, "templates to exclude based on tags (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.IncludeTags, "include-tags", "itags", []string{}, "tags to be executed even if they are excluded either by default or configuration", goflags.FileNormalizedStringSliceOptions), // TODO show default deny list
flagSet.StringSliceVarP(&options.IncludeIds, "template-id", "id", []string{}, "templates to run based on template ids (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeIds, "exclude-id", "eid", []string{}, "templates to exclude based on template ids (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.IncludeTemplates, "include-templates", "it", []string{}, "templates to be executed even if they are excluded either by default or configuration", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludedTemplates, "exclude-templates", "et", []string{}, "template or template directory to exclude (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeMatchers, "exclude-matchers", "em", []string{}, "template matchers to exclude in result", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Authors, "author", "a", nil, "templates to run based on authors (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVar(&options.Tags, "tags", nil, "templates to run based on tags (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeTags, "exclude-tags", "etags", nil, "templates to exclude based on tags (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.IncludeTags, "include-tags", "itags", nil, "tags to be executed even if they are excluded either by default or configuration", goflags.FileNormalizedStringSliceOptions), // TODO show default deny list
flagSet.StringSliceVarP(&options.IncludeIds, "template-id", "id", nil, "templates to run based on template ids (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeIds, "exclude-id", "eid", nil, "templates to exclude based on template ids (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.IncludeTemplates, "include-templates", "it", nil, "templates to be executed even if they are excluded either by default or configuration", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludedTemplates, "exclude-templates", "et", nil, "template or template directory to exclude (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeMatchers, "exclude-matchers", "em", nil, "template matchers to exclude in result", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.VarP(&options.Severities, "severity", "s", fmt.Sprintf("templates to run based on severity. Possible values: %s", severity.GetSupportedSeverities().String())),
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())),
@ -185,8 +186,8 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.IntVarP(&options.MaxRedirects, "max-redirects", "mr", 10, "max number of redirects to follow for http templates"),
flagSet.BoolVarP(&options.DisableRedirects, "disable-redirects", "dr", false, "disable redirects for http templates"),
flagSet.StringVarP(&options.ReportingConfig, "report-config", "rc", "", "nuclei reporting module configuration file"), // TODO merge into the config file or rename to issue-tracking
flagSet.StringSliceVarP(&options.CustomHeaders, "header", "H", []string{}, "custom header/cookie to include in all http request in header:value format (cli, file)", goflags.FileStringSliceOptions),
flagSet.RuntimeMapVarP(&options.Vars, "var", "V", []string{}, "custom vars in key=value format"),
flagSet.StringSliceVarP(&options.CustomHeaders, "header", "H", nil, "custom header/cookie to include in all http request in header:value format (cli, file)", goflags.FileStringSliceOptions),
flagSet.RuntimeMapVarP(&options.Vars, "var", "V", nil, "custom vars in key=value format"),
flagSet.StringVarP(&options.ResolversFile, "resolvers", "r", "", "file containing resolver list for nuclei"),
flagSet.BoolVarP(&options.SystemResolvers, "system-resolvers", "sr", false, "use system DNS resolving as error fallback"),
flagSet.BoolVarP(&options.DisableClustering, "disable-clustering", "dc", false, "disable clustering of requests"),
@ -220,8 +221,8 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.CreateGroup("uncover", "Uncover",
flagSet.BoolVarP(&options.Uncover, "uncover", "uc", false, "enable uncover engine"),
flagSet.StringSliceVarP(&options.UncoverQuery, "uncover-query", "uq", []string{}, "uncover search query", goflags.FileStringSliceOptions),
flagSet.StringSliceVarP(&options.UncoverEngine, "uncover-engine", "ue", []string{}, fmt.Sprintf("uncover search engine (%s) (default shodan)", uncover.GetUncoverSupportedAgents()), goflags.FileStringSliceOptions),
flagSet.StringSliceVarP(&options.UncoverQuery, "uncover-query", "uq", nil, "uncover search query", goflags.FileStringSliceOptions),
flagSet.StringSliceVarP(&options.UncoverEngine, "uncover-engine", "ue", nil, fmt.Sprintf("uncover search engine (%s) (default shodan)", uncover.GetUncoverSupportedAgents()), goflags.FileStringSliceOptions),
flagSet.StringVarP(&options.UncoverField, "uncover-field", "uf", "ip:port", "uncover fields to return (ip,port,host)"),
flagSet.IntVarP(&options.UncoverLimit, "uncover-limit", "ul", 100, "uncover results to return"),
flagSet.IntVarP(&options.UncoverDelay, "uncover-delay", "ucd", 1, "delay between uncover query requests in seconds (0 to disable)"),
@ -245,6 +246,11 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"),
flagSet.BoolVarP(&options.StopAtFirstMatch, "stop-at-first-match", "spm", false, "stop processing HTTP requests after the first match (may break template/workflow logic)"),
flagSet.BoolVar(&options.Stream, "stream", false, "stream mode - start elaborating without sorting the input"),
flagSet.EnumVarP(&options.ScanStrategy, "scan-strategy", "ss", goflags.EnumVariable(0), "strategy to use while scanning(auto/host-spray/template-spray)", goflags.AllowdTypes{
"auto": goflags.EnumVariable(0),
"host-spray": goflags.EnumVariable(1),
"template-spray": goflags.EnumVariable(2),
}),
flagSet.DurationVarP(&options.InputReadTimeout, "input-read-timeout", "irt", time.Duration(3*time.Minute), "timeout on input read"),
flagSet.BoolVarP(&options.DisableHTTPProbe, "no-httpx", "nh", false, "disable httpx probing for non-url input"),
flagSet.BoolVar(&options.DisableStdin, "no-stdin", false, "disable stdin processing"),
@ -262,7 +268,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVar(&options.Debug, "debug", false, "show all requests and responses"),
flagSet.BoolVarP(&options.DebugRequests, "debug-req", "dreq", false, "show all sent requests"),
flagSet.BoolVarP(&options.DebugResponse, "debug-resp", "dresp", false, "show all received responses"),
flagSet.StringSliceVarP(&options.Proxy, "proxy", "p", []string{}, "list of http/socks5 proxy to use (comma separated or file input)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Proxy, "proxy", "p", nil, "list of http/socks5 proxy to use (comma separated or file input)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.BoolVarP(&options.ProxyInternal, "proxy-internal", "pi", false, "proxy all internal requests"),
flagSet.BoolVarP(&options.ListDslSignatures, "list-dsl-function", "ldf", false, "list all supported DSL function signatures"),
flagSet.StringVarP(&options.TraceLogFile, "trace-log", "tlog", "", "file to write sent requests trace log"),

View File

@ -45,7 +45,7 @@ require (
github.com/weppos/publicsuffix-go v0.15.1-0.20220724114530-e087fba66a37
github.com/xanzy/go-gitlab v0.77.0
go.uber.org/atomic v1.10.0
go.uber.org/multierr v1.8.0
go.uber.org/multierr v1.9.0
golang.org/x/net v0.4.0
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
golang.org/x/text v0.5.0
@ -58,10 +58,10 @@ require (
github.com/antchfx/xmlquery v1.3.13
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/aws/aws-sdk-go-v2 v1.17.3
github.com/aws/aws-sdk-go-v2/config v1.18.4
github.com/aws/aws-sdk-go-v2/credentials v1.13.4
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5
github.com/aws/aws-sdk-go-v2/config v1.18.7
github.com/aws/aws-sdk-go-v2/credentials v1.13.7
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.46
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.6
github.com/docker/go-units v0.5.0
github.com/fatih/structs v1.1.0
github.com/go-git/go-git/v5 v5.5.1
@ -74,13 +74,13 @@ require (
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/goflags v0.1.6
github.com/projectdiscovery/nvd v1.0.9
github.com/projectdiscovery/ratelimit v0.0.3
github.com/projectdiscovery/ratelimit v0.0.4-0.20221222024635-17151503fe59
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.0.0
github.com/projectdiscovery/uncover v1.0.1
github.com/projectdiscovery/utils v0.0.4-0.20221214110533-9f95ee986a54
github.com/projectdiscovery/wappalyzergo v0.0.74
github.com/projectdiscovery/wappalyzergo v0.0.75
github.com/stretchr/testify v1.8.1
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.1
@ -88,10 +88,10 @@ require (
require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.3.1 // indirect
github.com/bits-and-blooms/bloom/v3 v3.3.1 // indirect
@ -224,14 +224,14 @@ require (
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/alecthomas/chroma v0.10.0
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.28 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.11 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.7 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect

View File

@ -101,43 +101,42 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
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-v2 v1.17.2/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY=
github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
github.com/aws/aws-sdk-go-v2/config v1.18.4 h1:VZKhr3uAADXHStS/Gf9xSYVmmaluTUfkc0dcbPiDsKE=
github.com/aws/aws-sdk-go-v2/config v1.18.4/go.mod h1:EZxMPLSdGAZ3eAmkqXfYbRppZJTzFTkv8VyEzJhKko4=
github.com/aws/aws-sdk-go-v2/credentials v1.13.4 h1:nEbHIyJy7mCvQ/kzGG7VWHSBpRB4H6sJy3bWierWUtg=
github.com/aws/aws-sdk-go-v2/credentials v1.13.4/go.mod h1:/Cj5w9LRsNTLSwexsohwDME32OzJ6U81Zs33zr2ZWOM=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 h1:tpNOglTZ8kg9T38NpcGBxudqfUAwUzyUnLQ4XSd0CHE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20/go.mod h1:d9xFpWd3qYwdIXM0fvu7deD08vvdRXyc/ueV+0SqaWE=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43 h1:+bkAMTd5OGyHu2nwNOangjEsP65fR0uhMbZJA52sZ64=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43/go.mod h1:sS2tu0VEspKuY5eM1vQgy7P/hpZX8F62o6qsghZExWc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 h1:5WU31cY7m0tG+AiaXuXGoMzo2GBQ1IixtWa8Yywsgco=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26/go.mod h1:2E0LdbJW6lbeU4uxjum99GZzI0ZjDpAb0CoSCM0oeEY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 h1:WW0qSzDWoiWU2FS5DbKpxGilFVlCEJPwx4YtjdfI0Jw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20/go.mod h1:/+6lSiby8TBFpTVXZgKiN/rCfkYXEGvhlM4zCgPpt7w=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 h1:N2eKFw2S+JWRCtTt0IhIX7uoGGQciD4p6ba+SJv4WEU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27/go.mod h1:RdwFVc7PBYWY33fa2+8T1mSqQ7ZEK4ILpM0wfioDC3w=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 h1:5tXbMJ7Jq0iG65oiMg6tCLsHkSaO2xLXa2EmZ29vaTA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17/go.mod h1:twV0fKMQuqLY4klyFH56aXNq3AFiA5LO0/frTczEOFE=
github.com/aws/aws-sdk-go-v2/config v1.18.7 h1:V94lTcix6jouwmAsgQMAEBozVAGJMFhVj+6/++xfe3E=
github.com/aws/aws-sdk-go-v2/config v1.18.7/go.mod h1:OZYsyHFL5PB9UpyS78NElgKs11qI/B5KJau2XOJDXHA=
github.com/aws/aws-sdk-go-v2/credentials v1.13.7 h1:qUUcNS5Z1092XBFT66IJM7mYkMwgZ8fcC8YDIbEwXck=
github.com/aws/aws-sdk-go-v2/credentials v1.13.7/go.mod h1:AdCcbZXHQCjJh6NaH3pFaw8LUeBFn5+88BZGMVGuBT8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 h1:j9wi1kQ8b+e0FBVHxCqCGo4kxDU175hoDHcWAi0sauU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvUyZuaPy4Kv+vEfJWnIrky7RmkBvJg=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.46 h1:OCX1pQ4pcqhsDV7B92HzdLWjHWOQsILvjLinpaUWhcc=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.46/go.mod h1:MxCBOcyNXGJRvfpPiH+L6n/BF9zbowthGSUZdDvQF/c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 h1:KeTxcGdNnQudb46oOl4d90f2I33DF/c6q3RnZAmvQdQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18 h1:H/mF2LNWwX00lD6FlYfKpLLZgUW7oIzCBkig78x4Xok=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18/go.mod h1:T2Ku+STrYQ1zIkL1wMvj8P3wWQaaCMKNdz70MT2FLfE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 h1:77b1GfaSuIok5yB/3HYbG+ypWvOJDQ2rVdq943D17R4=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21/go.mod h1:sPOz31BVdqeeurKEuUpLNSve4tdCNPluE+070HNcEHI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 h1:jlgyHbkZQAgAc7VIxJDmtouH8eNjOk2REVAQfVhdaiQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20/go.mod h1:Xs52xaLBqDEKRcAfX/hgjmD3YQ7c/W+BEyfamlO/W2E=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20 h1:4K6dbmR0mlp3o4Bo78PnpvzHtYAqEeVMguvEenpMGsI=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20/go.mod h1:1XpDcReIEOHsjwNToDKhIAO3qwLo1BnfbtSqWJa8j7g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5 h1:nRSEQj1JergKTVc8RGkhZvOEGgcvo4fWpDPwGDeg2ok=
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5/go.mod h1:wcaJTmjKFDW0s+Se55HBNIds6ghdAGoDDw+SGUdrfAk=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 h1:ActQgdTNQej/RuUJjB9uxYVLDOvRGtUreXF8L3c8wyg=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.26/go.mod h1:uB9tV79ULEZUXc6Ob18A46KSQ0JDlrplPni9XW6Ot60=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 h1:wihKuqYUlA2T/Rx+yu2s6NDAns8B9DgnRooB1PVhY+Q=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9/go.mod h1:2E/3D/mB8/r2J7nK42daoKP/ooCwbf0q1PznNc+DZTU=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 h1:VQFOLQVL3BrKM/NLO/7FiS4vcp5bqK0mGMyk09xLoAY=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.6/go.mod h1:Az3OXXYGyfNwQNsK/31L4R75qFYnO641RZGAoV3uH1c=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22 h1:kv5vRAl00tozRxSnI0IszPWGXsJOyA7hmEUHFYqsyvw=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22/go.mod h1:Od+GU5+Yx41gryN/ZGZzAJMZ9R1yn6lgA0fD5Lo5SkQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 h1:5C6XgTViSb0bunmU57b3CT+MhxULqHH2721FVA+/kDM=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21/go.mod h1:lRToEJsn+DRA9lW4O9L9+/3hjTkUzlzyzHqn8MTds5k=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21 h1:vY5siRXvW5TrOKm2qKEf9tliBfdLxdfy0i02LOcmqUo=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21/go.mod h1:WZvNXT1XuH8dnJM0HvOlvk+RNn7NbAPvA/ACO0QarSc=
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.6 h1:W8pLcSn6Uy0eXgDBUUl8M8Kxv7JCoP68ZKTD04OXLEA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.6/go.mod h1:L2l2/q76teehcW7YEsgsDjqdsDTERJeX3nOMIFlgGUE=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.28 h1:gItLq3zBYyRDPmqAClgzTH8PBjDQGeyptYGHIwtYYNA=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.28/go.mod h1:wo/B7uUm/7zw/dWhBJ4FXuw1sySU5lyIhVg1Bu2yL9A=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.11 h1:KCacyVSs/wlcPGx37hcbT3IGYO8P8Jx+TgSDhAXtQMY=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.11/go.mod h1:TZSH7xLO7+phDtViY/KUp9WGCJMQkLJ/VpgkTFd5gh8=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.7 h1:9Mtq1KM6nD8/+HStvWcvYnixJ5N85DX+P+OY3kI3W2k=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.7/go.mod h1:+lGbb3+1ugwKrNTWcf2RT05Xmp543B06zDFTwiTLp7I=
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
@ -629,8 +628,8 @@ github.com/projectdiscovery/networkpolicy v0.0.3 h1:OZFPkMVY6SJxc1ncuRXB2VlT6xlz
github.com/projectdiscovery/networkpolicy v0.0.3/go.mod h1:DIXwKs3sQyfCoWHKRLQiRrEorSQW4Zrh4ftu7oDVK6w=
github.com/projectdiscovery/nvd v1.0.9 h1:2DdMm7lu3GnCQsyYDEQiQ/LRYDmpEm654kvGQS6jzjE=
github.com/projectdiscovery/nvd v1.0.9/go.mod h1:nGHAo7o6G4V4kscZlm488qKp/ZrZYiBoKqAQrn3X4Og=
github.com/projectdiscovery/ratelimit v0.0.3 h1:6c8QKL3ivOdjXqbP+UA2jsTNHcH0OMHk+4AMkanOkUo=
github.com/projectdiscovery/ratelimit v0.0.3/go.mod h1:WBz8N1P+CyxnfUoGfVCqah4NZ2SreSX7v9dY8wIlK70=
github.com/projectdiscovery/ratelimit v0.0.4-0.20221222024635-17151503fe59 h1:XHi//FUJTo+RRKfLT9Mj6oqkQq9E65uNMhL2RVuG5zA=
github.com/projectdiscovery/ratelimit v0.0.4-0.20221222024635-17151503fe59/go.mod h1:WBz8N1P+CyxnfUoGfVCqah4NZ2SreSX7v9dY8wIlK70=
github.com/projectdiscovery/rawhttp v0.1.4 h1:zdOqU1DUY2dGoyCzBqzHnHVwPyv32j+Hke8KfLRUouI=
github.com/projectdiscovery/rawhttp v0.1.4/go.mod h1:mhSXo96awUUr20VdReDYUKxldsvR5841FRgiaoaxDCY=
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gBVSorSzvmm0bFa7gDV4QNSOWPL/fgZ4kTXBxk=
@ -651,8 +650,8 @@ github.com/projectdiscovery/uncover v1.0.1 h1:bhP+EW4d+e4cAizOWAEz7jeyKZGkDYYTsZ
github.com/projectdiscovery/uncover v1.0.1/go.mod h1:/D9qxgN2iZ/C2M8eo+pNQMnTaMhTZUu40Vat/LgSIxU=
github.com/projectdiscovery/utils v0.0.4-0.20221214110533-9f95ee986a54 h1:/fZvw6gT1fzdmMLMBBw75OrJ0Z6g7dulQrxM9FRp1qU=
github.com/projectdiscovery/utils v0.0.4-0.20221214110533-9f95ee986a54/go.mod h1:PCwA5YuCYWPgHaGiZmr53/SA9iGQmAnw7DSHuhr8VPQ=
github.com/projectdiscovery/wappalyzergo v0.0.74 h1:EHukHzfmcOSP8fTLDkXYEsXHQgtq3OlHT9OFr659sDY=
github.com/projectdiscovery/wappalyzergo v0.0.74/go.mod h1:HvYuW0Be4JCjVds/+XAEaMSqRG9yrI97UmZq0TPk6A0=
github.com/projectdiscovery/wappalyzergo v0.0.75 h1:IRiI4CtMpDfjMDa1FmWinEQsGOk4tqNkr+PLzhvXW18=
github.com/projectdiscovery/wappalyzergo v0.0.75/go.mod h1:HvYuW0Be4JCjVds/+XAEaMSqRG9yrI97UmZq0TPk6A0=
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=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@ -866,8 +865,8 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=

View File

@ -54,6 +54,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/yaml"
yamlwrapper "github.com/projectdiscovery/nuclei/v2/pkg/utils/yaml"
"github.com/projectdiscovery/retryablehttp-go"
stringsutil "github.com/projectdiscovery/utils/strings"
@ -109,7 +110,10 @@ func New(options *types.Options) (*Runner, error) {
// Does not update the templates when validate flag is used
options.NoUpdateTemplates = true
}
// TODO: refactor to pass options reference globally without cycles
parsers.NoStrictSyntax = options.NoStrictSyntax
yaml.StrictSyntax = !options.NoStrictSyntax
// parse the runner.options.GithubTemplateRepo and store the valid repos in runner.customTemplateRepos
runner.customTemplates = customtemplates.ParseCustomTemplates(runner.options)
@ -332,6 +336,9 @@ func (r *Runner) Close() {
if r.pprofServer != nil {
_ = r.pprofServer.Shutdown(context.Background())
}
if r.ratelimiter != nil {
r.ratelimiter.Stop()
}
}
// RunEnumeration sets up the input layer for giving input nuclei.
@ -627,7 +634,7 @@ func (r *Runner) executeTemplatesInput(store *loader.Store, engine *core.Engine)
// tracks global progress and captures stdout/stderr until p.Wait finishes
r.progress.Init(r.hmapInputProvider.Count(), templateCount, totalRequests)
results := engine.ExecuteWithOpts(finalTemplates, r.hmapInputProvider, true)
results := engine.ExecuteScanWithOpts(finalTemplates, r.hmapInputProvider, true)
return results, nil
}

View File

@ -5,6 +5,7 @@ import (
"go.uber.org/atomic"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/core/inputs"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
@ -18,20 +19,13 @@ import (
// All the execution logic for the templates/workflows happens in this part
// of the engine.
func (e *Engine) Execute(templates []*templates.Template, target InputProvider) *atomic.Bool {
return e.ExecuteWithOpts(templates, target, false)
return e.ExecuteScanWithOpts(templates, target, false)
}
// ExecuteWithOpts executes with the full options
func (e *Engine) ExecuteWithOpts(templatesList []*templates.Template, target InputProvider, noCluster bool) *atomic.Bool {
var finalTemplates []*templates.Template
if !noCluster {
finalTemplates, _ = templates.ClusterTemplates(templatesList, e.executerOpts)
} else {
finalTemplates = templatesList
}
// executeTemplateSpray executes scan using template spray strategy where targets are iterated over each template
func (e *Engine) executeTemplateSpray(templatesList []*templates.Template, target InputProvider) *atomic.Bool {
results := &atomic.Bool{}
for _, template := range finalTemplates {
for _, template := range templatesList {
templateType := template.Type()
var wg *sizedwaitgroup.SizedWaitGroup
@ -59,6 +53,53 @@ func (e *Engine) ExecuteWithOpts(templatesList []*templates.Template, target Inp
return results
}
// executeHostSpray executes scan using host spray strategy where templates are iterated over each target
func (e *Engine) executeHostSpray(templatesList []*templates.Template, target InputProvider) *atomic.Bool {
results := &atomic.Bool{}
hostwg := sizedwaitgroup.New(e.options.BulkSize)
target.Scan(func(value *contextargs.MetaInput) bool {
host := inputs.SimpleInputProvider{
Inputs: []*contextargs.MetaInput{
value,
},
}
hostwg.Add()
go func(result *atomic.Bool) {
defer hostwg.Done()
status := e.executeTemplateSpray(templatesList, &host)
results.CompareAndSwap(false, status.Load())
}(results)
return true
})
hostwg.Wait()
return results
}
// ExecuteScanWithOpts executes scan with given scanStatergy
func (e *Engine) ExecuteScanWithOpts(templatesList []*templates.Template, target InputProvider, noCluster bool) *atomic.Bool {
var results *atomic.Bool
var finalTemplates []*templates.Template
if !noCluster {
finalTemplates, _ = templates.ClusterTemplates(templatesList, e.executerOpts)
} else {
finalTemplates = templatesList
}
if e.options.ScanStrategy == "auto" {
// TODO: this is only a placeholder, auto scan strategy should choose scan strategy
// based on no of hosts , templates , stream and other optimization parameters
e.options.ScanStrategy = "template-spray"
}
switch e.options.ScanStrategy {
case "template-spray":
results = e.executeTemplateSpray(finalTemplates, target)
case "host-spray":
results = e.executeHostSpray(finalTemplates, target)
}
return results
}
// processSelfContainedTemplates execute a self-contained template.
func (e *Engine) executeSelfContainedTemplateWithInput(template *templates.Template, results *atomic.Bool) {
match, err := template.Executer.Execute(contextargs.New())

View File

@ -5,7 +5,7 @@ package hybrid
import (
"bufio"
"io"
"net/url"
"net"
"os"
"strings"
"sync"
@ -22,6 +22,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/uncover"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
fileutil "github.com/projectdiscovery/utils/file"
iputil "github.com/projectdiscovery/utils/ip"
readerutil "github.com/projectdiscovery/utils/reader"
@ -169,39 +170,49 @@ func (i *Input) Set(value string) {
if URL == "" {
return
}
// actual hostname
var host string
// parse hostname if url is given
parsedURL, err := url.Parse(value)
if err == nil && parsedURL.Host != "" {
host = parsedURL.Host
host := utils.ParseHostname(value)
if host == "" {
// not a valid url hence scanallips is skipped
gologger.Debug().Msgf("scanAllIps: failed to parse hostname of %v falling back to default", value)
i.setItem(&contextargs.MetaInput{Input: value})
return
} else {
parsedURL = nil
host = value
// case when hostname contains port
hostwithoutport, _, erx := net.SplitHostPort(host)
if erx == nil && hostwithoutport != "" {
// given host contains port
host = hostwithoutport
}
}
if i.ipOptions.ScanAllIPs {
// scan all ips
dnsData, err := protocolstate.Dialer.GetDNSData(host)
if err == nil && (len(dnsData.A)+len(dnsData.AAAA)) > 0 {
var ips []string
if i.ipOptions.IPV4 {
ips = append(ips, dnsData.A...)
}
if i.ipOptions.IPV6 {
ips = append(ips, dnsData.AAAA...)
}
for _, ip := range ips {
if ip == "" {
continue
if err == nil {
if (len(dnsData.A) + len(dnsData.AAAA)) > 0 {
var ips []string
if i.ipOptions.IPV4 {
ips = append(ips, dnsData.A...)
}
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
i.setItem(metaInput)
if i.ipOptions.IPV6 {
ips = append(ips, dnsData.AAAA...)
}
for _, ip := range ips {
if ip == "" {
continue
}
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
i.setItem(metaInput)
}
return
} else {
gologger.Debug().Msgf("scanAllIps: no ip's found reverting to default")
}
return
} else {
// failed to scanallips falling back to defaults
gologger.Debug().Msgf("scanAllIps: dns resolution failed: %v", err)
}
// failed to scanallips falling back to defaults
gologger.Error().Msgf("failed to scan all ips reverting to default %v", err)
}
ips := []string{}
@ -212,7 +223,7 @@ func (i *Input) Set(value string) {
// pick/ prefer 1st
ips = append(ips, dnsData.AAAA[0])
} else {
gologger.Warning().Msgf("target does not have ipv6 address falling back to ipv4 %s\n", err)
gologger.Warning().Msgf("target does not have ipv6 address falling back to ipv4 %v\n", err)
}
}
if i.ipOptions.IPV4 {

View File

@ -51,7 +51,7 @@ func Test_expandCIDRInputValue(t *testing.T) {
type mockDnsHandler struct{}
func (this *mockDnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
func (m *mockDnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
msg := dns.Msg{}
msg.SetReply(r)
switch r.Question[0].Qtype {
@ -85,18 +85,14 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
defaultOpts := types.DefaultOptions()
defaultOpts.InternalResolversList = []string{"127.0.0.1:61234"}
_ = protocolstate.Init(defaultOpts)
tests := []struct {
type testcase struct {
hostname string
ipv4 bool
ipv6 bool
expected []string
}{
}
tests := []testcase{
{
hostname: "scanme.sh",
ipv4: true,
ipv6: true,
expected: []string{"128.199.158.128", "2400:6180:0:d0::91:1001"},
}, {
hostname: "scanme.sh",
ipv4: true,
expected: []string{"128.199.158.128"},
@ -104,12 +100,27 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
hostname: "scanme.sh",
ipv6: true,
expected: []string{"2400:6180:0:d0::91:1001"},
}, {
hostname: "http://scanme.sh",
},
}
// add extra edge cases
urls := []string{
"https://scanme.sh/",
"http://scanme.sh",
"https://scanme.sh:443/",
"https://scanme.sh:443/somepath",
"http://scanme.sh:80/?with=param",
"scanme.sh/home",
"scanme.sh",
}
resolvedIps := []string{"128.199.158.128", "2400:6180:0:d0::91:1001"}
for _, v := range urls {
tests = append(tests, testcase{
hostname: v,
ipv4: true,
ipv6: true,
expected: []string{"128.199.158.128", "2400:6180:0:d0::91:1001"},
},
expected: resolvedIps,
})
}
for _, tt := range tests {
hm, err := hybrid.New(hybrid.DefaultDiskOptions)
@ -134,7 +145,7 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
got = append(got, metainput.CustomIP)
return nil
})
require.ElementsMatch(t, tt.expected, got, "could not get correct ips")
require.ElementsMatchf(t, tt.expected, got, "could not get correct ips for hostname %v", tt.hostname)
input.Close()
}
}

View File

@ -100,7 +100,7 @@ func (h *Helper) convertInputToType(input string, inputType inputType, defaultPo
if hasHost {
return host
}
if isURL {
if isURL && uri != nil {
return uri.Hostname()
}
return input

View File

@ -82,7 +82,7 @@ type ResultEvent struct {
// TemplateID is the ID of the template for the result.
TemplateID string `json:"template-id"`
// TemplatePath is the path of template
TemplatePath string `json:"-"`
TemplatePath string `json:"template-path,omitempty"`
// Info contains information block of the template for the result.
Info model.Info `json:"info,inline"`
// MatcherName is the name of the matcher matched if any.

View File

@ -261,6 +261,18 @@ func (c *Client) Close() bool {
c.interactsh.StopPolling()
c.interactsh.Close()
}
closeCache := func(cc *ccache.Cache) {
if cc != nil {
cc.Clear()
cc.Stop()
}
}
closeCache(c.requests)
closeCache(c.interactions)
closeCache(c.matchedTemplates)
closeCache(c.interactshURLs)
return c.matched
}

View File

@ -107,6 +107,9 @@ func getTargets(uncoverOptions *ucRunner.Options, field string) (chan string, er
} else {
rateLimiter = ratelimit.NewUnlimited(context.Background())
}
if rateLimiter != nil {
defer rateLimiter.Stop()
}
var agents []uncover.Agent
// declare clients
for _, engine := range uncoverOptions.Engine {

View File

@ -2,6 +2,8 @@ package templates
import (
"fmt"
"io"
"net/http"
"reflect"
"github.com/pkg/errors"
@ -35,44 +37,25 @@ func Parse(filePath string, preprocessor Preprocessor, options protocols.Execute
return value.(*Template), err
}
template := &Template{}
data, err := utils.ReadFromPathOrURL(filePath, options.Catalog)
var reader io.ReadCloser
if utils.IsURL(filePath) {
resp, err := http.Get(filePath)
if err != nil {
return nil, err
}
reader = resp.Body
} else {
var err error
reader, err = options.Catalog.OpenFile(filePath)
if err != nil {
return nil, err
}
}
defer reader.Close()
template, err := ParseTemplateFromReader(reader, preprocessor, options)
if err != nil {
return nil, err
}
data = template.expandPreprocessors(data)
if preprocessor != nil {
data = preprocessor.Process(data)
}
if err := yaml.Unmarshal(data, template); err != nil {
return nil, err
}
if utils.IsBlank(template.Info.Name) {
return nil, errors.New("no template name field provided")
}
if template.Info.Authors.IsEmpty() {
return nil, errors.New("no template author field provided")
}
// Setting up variables regarding template metadata
options.TemplateID = template.ID
options.TemplateInfo = template.Info
options.TemplatePath = filePath
options.StopAtFirstMatch = template.StopAtFirstMatch
if template.Variables.Len() > 0 {
options.Variables = template.Variables
}
// If no requests, and it is also not a workflow, return error.
if template.Requests() == 0 {
return nil, fmt.Errorf("no requests defined for %s", template.ID)
}
// Compile the workflow request
if len(template.Workflows) > 0 {
compiled := &template.Workflow
@ -81,24 +64,7 @@ func Parse(filePath string, preprocessor Preprocessor, options protocols.Execute
template.CompiledWorkflow = compiled
template.CompiledWorkflow.Options = &options
}
if err := template.compileProtocolRequests(options); err != nil {
return nil, err
}
if template.Executer != nil {
if err := template.Executer.Compile(); err != nil {
return nil, errors.Wrap(err, "could not compile request")
}
template.TotalRequests = template.Executer.Requests()
}
if template.Executer == nil && template.CompiledWorkflow == nil {
return nil, ErrCreateTemplateExecutor
}
template.Path = filePath
template.parseSelfContainedRequests()
parsedTemplatesCache.Store(filePath, template, err)
return template, nil
}
@ -221,3 +187,60 @@ mainLoop:
template.Executer = executer.NewExecuter([]protocols.Request{&offlinehttp.Request{}}, &options)
}
}
// ParseTemplateFromReader reads the template from reader
// returns the parsed template
func ParseTemplateFromReader(reader io.Reader, preprocessor Preprocessor, options protocols.ExecuterOptions) (*Template, error) {
template := &Template{}
data, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
data = template.expandPreprocessors(data)
if preprocessor != nil {
data = preprocessor.Process(data)
}
if err := yaml.Unmarshal(data, template); err != nil {
return nil, err
}
if utils.IsBlank(template.Info.Name) {
return nil, errors.New("no template name field provided")
}
if template.Info.Authors.IsEmpty() {
return nil, errors.New("no template author field provided")
}
// Setting up variables regarding template metadata
options.TemplateID = template.ID
options.TemplateInfo = template.Info
options.StopAtFirstMatch = template.StopAtFirstMatch
if template.Variables.Len() > 0 {
options.Variables = template.Variables
}
// If no requests, and it is also not a workflow, return error.
if template.Requests() == 0 {
return nil, fmt.Errorf("no requests defined for %s", template.ID)
}
if err := template.compileProtocolRequests(options); err != nil {
return nil, err
}
if template.Executer != nil {
if err := template.Executer.Compile(); err != nil {
return nil, errors.Wrap(err, "could not compile request")
}
template.TotalRequests = template.Executer.Requests()
}
if template.Executer == nil && template.CompiledWorkflow == nil {
return nil, ErrCreateTemplateExecutor
}
template.parseSelfContainedRequests()
return template, nil
}

View File

@ -0,0 +1,184 @@
package templates_test
import (
"context"
"log"
"testing"
"time"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v2/pkg/model"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice"
"github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers"
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
"github.com/projectdiscovery/nuclei/v2/pkg/progress"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/variables"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/ssl"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
"github.com/projectdiscovery/nuclei/v2/pkg/workflows"
"github.com/projectdiscovery/ratelimit"
"github.com/stretchr/testify/require"
)
var executerOpts protocols.ExecuterOptions
func setup() {
options := testutils.DefaultOptions
testutils.Init(options)
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
executerOpts = protocols.ExecuterOptions{
Output: testutils.NewMockOutputWriter(),
Options: options,
Progress: progressImpl,
ProjectFile: nil,
IssuesClient: nil,
Browser: nil,
Catalog: disk.NewCatalog(options.TemplatesDirectory),
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
}
workflowLoader, err := parsers.NewLoader(&executerOpts)
if err != nil {
log.Fatalf("Could not create workflow loader: %s\n", err)
}
executerOpts.WorkflowLoader = workflowLoader
}
func Test_ParseFromURL(t *testing.T) {
filePath := "https://api.nuclei.sh/api/v1/templates/raw/ssl/tls-version.yaml"
expectedTemplate := &templates.Template{
ID: "tls-version",
Info: model.Info{
Authors: stringslice.StringSlice{Value: []string{"pdteam"}},
SeverityHolder: severity.Holder{Severity: severity.Info},
Name: "TLS Version",
Tags: stringslice.StringSlice{Value: []string{"ssl"}},
},
RequestsSSL: []*ssl.Request{
{
Address: "{{Host}}:{{Port}}",
Operators: operators.Operators{
Extractors: []*extractors.Extractor{
{
Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.JSONExtractor},
JSON: []string{".tls_version"},
},
},
},
}},
TotalRequests: 1,
Executer: nil,
Path: "https://api.nuclei.sh/api/v1/templates/raw/ssl/tls-version.yaml",
}
setup()
got, err := templates.Parse(filePath, nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.Equal(t, expectedTemplate.ID, got.ID)
require.Equal(t, expectedTemplate.Info, got.Info)
require.Equal(t, expectedTemplate.TotalRequests, got.TotalRequests)
require.Equal(t, expectedTemplate.Path, got.Path)
require.Equal(t, expectedTemplate.RequestsSSL[0].Address, got.RequestsSSL[0].Address)
require.Equal(t, expectedTemplate.RequestsSSL[0].Extractors[0].Type, got.RequestsSSL[0].Extractors[0].Type)
require.Equal(t, expectedTemplate.RequestsSSL[0].Extractors[0].JSON, got.RequestsSSL[0].Extractors[0].JSON)
require.Equal(t, len(expectedTemplate.RequestsSSL), len(got.RequestsSSL))
}
func Test_ParseFromFile(t *testing.T) {
filePath := "tests/match-1.yaml"
expectedTemplate := &templates.Template{
ID: "basic-get",
Info: model.Info{
Name: "Basic GET Request",
Authors: stringslice.StringSlice{Value: []string{"pdteam"}},
SeverityHolder: severity.Holder{Severity: severity.Info},
},
RequestsHTTP: []*http.Request{{
Operators: operators.Operators{
Matchers: []*matchers.Matcher{{
Type: matchers.MatcherTypeHolder{
MatcherType: matchers.WordsMatcher,
},
Words: []string{"This is test matcher text"},
}},
},
Path: []string{"{{BaseURL}}"},
AttackType: generators.AttackTypeHolder{},
Method: http.HTTPMethodTypeHolder{
MethodType: http.HTTPGet,
},
}},
TotalRequests: 1,
Executer: nil,
Path: "tests/match-1.yaml",
}
setup()
got, err := templates.Parse(filePath, nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.Equal(t, expectedTemplate.ID, got.ID)
require.Equal(t, expectedTemplate.Info, got.Info)
require.Equal(t, expectedTemplate.TotalRequests, got.TotalRequests)
require.Equal(t, expectedTemplate.Path, got.Path)
require.Equal(t, expectedTemplate.RequestsHTTP[0].Path, got.RequestsHTTP[0].Path)
require.Equal(t, expectedTemplate.RequestsHTTP[0].Operators.Matchers[0].Words, got.RequestsHTTP[0].Operators.Matchers[0].Words)
require.Equal(t, len(expectedTemplate.RequestsHTTP), len(got.RequestsHTTP))
// Test cache
got, err = templates.Parse(filePath, nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.Equal(t, expectedTemplate.ID, got.ID)
}
func Test_ParseWorkflow(t *testing.T) {
filePath := "tests/workflow.yaml"
expectedTemplate := &templates.Template{
ID: "workflow-example",
Info: model.Info{
Name: "Test Workflow Template",
Authors: stringslice.StringSlice{Value: []string{"pdteam"}},
SeverityHolder: severity.Holder{Severity: severity.Info},
},
Workflow: workflows.Workflow{
Workflows: []*workflows.WorkflowTemplate{{Template: "tests/match-1.yaml"}, {Template: "tests/match-1.yaml"}},
Options: &protocols.ExecuterOptions{},
},
CompiledWorkflow: &workflows.Workflow{},
SelfContained: false,
StopAtFirstMatch: false,
Signature: http.SignatureTypeHolder{},
Variables: variables.Variable{},
TotalRequests: 0,
Executer: nil,
Path: "tests/workflow.yaml",
}
setup()
got, err := templates.Parse(filePath, nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.Equal(t, expectedTemplate.ID, got.ID)
require.Equal(t, expectedTemplate.Info, got.Info)
require.Equal(t, expectedTemplate.TotalRequests, got.TotalRequests)
require.Equal(t, expectedTemplate.Path, got.Path)
require.Equal(t, expectedTemplate.Workflow.Workflows[0].Template, got.Workflow.Workflows[0].Template)
require.Equal(t, len(expectedTemplate.Workflows), len(got.Workflows))
}
func Test_WrongTemplate(t *testing.T) {
setup()
filePath := "tests/no-author.yaml"
got, err := templates.Parse(filePath, nil, executerOpts)
require.Nil(t, got, "could not parse template")
require.ErrorContains(t, err, "no template author field provided")
filePath = "tests/no-req.yaml"
got, err = templates.Parse(filePath, nil, executerOpts)
require.Nil(t, got, "could not parse template")
require.ErrorContains(t, err, "no requests defined ")
}

View File

@ -1542,7 +1542,7 @@ func init() {
Value: "Headless response received from client (default)",
},
}
HEADLESSRequestDoc.Fields = make([]encoder.Doc, 9)
HEADLESSRequestDoc.Fields = make([]encoder.Doc, 10)
HEADLESSRequestDoc.Fields[0].Name = "id"
HEADLESSRequestDoc.Fields[0].Type = "string"
HEADLESSRequestDoc.Fields[0].Note = ""
@ -1573,22 +1573,27 @@ func init() {
HEADLESSRequestDoc.Fields[5].Note = ""
HEADLESSRequestDoc.Fields[5].Description = "description: |\n If UserAgent is set to custom, customUserAgent is the custom user-agent to use for the request."
HEADLESSRequestDoc.Fields[5].Comments[encoder.LineComment] = " description: |"
HEADLESSRequestDoc.Fields[6].Name = "matchers"
HEADLESSRequestDoc.Fields[6].Type = "[]matchers.Matcher"
HEADLESSRequestDoc.Fields[6].Name = "stop-at-first-match"
HEADLESSRequestDoc.Fields[6].Type = "bool"
HEADLESSRequestDoc.Fields[6].Note = ""
HEADLESSRequestDoc.Fields[6].Description = "Matchers contains the detection mechanism for the request to identify\nwhether the request was successful by doing pattern matching\non request/responses.\n\nMultiple matchers can be combined with `matcher-condition` flag\nwhich accepts either `and` or `or` as argument."
HEADLESSRequestDoc.Fields[6].Comments[encoder.LineComment] = "Matchers contains the detection mechanism for the request to identify"
HEADLESSRequestDoc.Fields[7].Name = "extractors"
HEADLESSRequestDoc.Fields[7].Type = "[]extractors.Extractor"
HEADLESSRequestDoc.Fields[6].Description = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HEADLESSRequestDoc.Fields[6].Comments[encoder.LineComment] = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HEADLESSRequestDoc.Fields[7].Name = "matchers"
HEADLESSRequestDoc.Fields[7].Type = "[]matchers.Matcher"
HEADLESSRequestDoc.Fields[7].Note = ""
HEADLESSRequestDoc.Fields[7].Description = "Extractors contains the extraction mechanism for the request to identify\nand extract parts of the response."
HEADLESSRequestDoc.Fields[7].Comments[encoder.LineComment] = "Extractors contains the extraction mechanism for the request to identify"
HEADLESSRequestDoc.Fields[8].Name = "matchers-condition"
HEADLESSRequestDoc.Fields[8].Type = "string"
HEADLESSRequestDoc.Fields[7].Description = "Matchers contains the detection mechanism for the request to identify\nwhether the request was successful by doing pattern matching\non request/responses.\n\nMultiple matchers can be combined with `matcher-condition` flag\nwhich accepts either `and` or `or` as argument."
HEADLESSRequestDoc.Fields[7].Comments[encoder.LineComment] = "Matchers contains the detection mechanism for the request to identify"
HEADLESSRequestDoc.Fields[8].Name = "extractors"
HEADLESSRequestDoc.Fields[8].Type = "[]extractors.Extractor"
HEADLESSRequestDoc.Fields[8].Note = ""
HEADLESSRequestDoc.Fields[8].Description = "MatchersCondition is the condition between the matchers. Default is OR."
HEADLESSRequestDoc.Fields[8].Comments[encoder.LineComment] = "MatchersCondition is the condition between the matchers. Default is OR."
HEADLESSRequestDoc.Fields[8].Values = []string{
HEADLESSRequestDoc.Fields[8].Description = "Extractors contains the extraction mechanism for the request to identify\nand extract parts of the response."
HEADLESSRequestDoc.Fields[8].Comments[encoder.LineComment] = "Extractors contains the extraction mechanism for the request to identify"
HEADLESSRequestDoc.Fields[9].Name = "matchers-condition"
HEADLESSRequestDoc.Fields[9].Type = "string"
HEADLESSRequestDoc.Fields[9].Note = ""
HEADLESSRequestDoc.Fields[9].Description = "MatchersCondition is the condition between the matchers. Default is OR."
HEADLESSRequestDoc.Fields[9].Comments[encoder.LineComment] = "MatchersCondition is the condition between the matchers. Default is OR."
HEADLESSRequestDoc.Fields[9].Values = []string{
"and",
"or",
}

View File

@ -0,0 +1,15 @@
id: basic-get
info:
name: Basic GET Request
author: pdteam
severity: info
requests:
- method: GET
path:
- "{{BaseURL}}"
matchers:
- type: word
words:
- "This is test matcher text"

View File

@ -0,0 +1,14 @@
id: basic-get
info:
name: Basic GET Request
severity: info
requests:
- method: GET
path:
- "{{BaseURL}}"
matchers:
- type: word
words:
- "This is test matcher text"

View File

@ -0,0 +1,9 @@
id: basic-get
info:
name: Basic GET Request
author: pdteam
severity: info
requests:

View File

@ -0,0 +1,10 @@
id: workflow-example
info:
name: Test Workflow Template
author: pdteam
severity: info
workflows:
- template: tests/match-1.yaml
- template: tests/match-1.yaml

View File

@ -336,6 +336,8 @@ type Options struct {
AwsBucketName string
// AWS Region name where aws s3 bucket is located
AwsRegion string
// Scan Strategy (auto,hosts-spray,templates-spray)
ScanStrategy string
}
func (options *Options) AddVarPayload(key string, value interface{}) {

View File

@ -77,3 +77,24 @@ func StringSliceContains(slice []string, item string) bool {
}
return false
}
// ParseHostname returns hostname
func ParseHostname(inputURL string) string {
/*
currently if URL is scanme.sh/path or scanme.sh:443 i.e without protocol then
url.Parse considers this as valid url but fails to parse hostname
this can be handled by adding schema
*/
input, err := url.Parse(inputURL)
if err != nil {
return ""
}
if input.Host == "" {
newinput, err := url.Parse("https://" + inputURL)
if err != nil {
return ""
}
return newinput.Host
}
return input.Host
}

View File

@ -19,3 +19,24 @@ func TestUnwrapError(t *testing.T) {
errThree := fmt.Errorf("error with error: %w", errTwo)
require.Equal(t, errOne, UnwrapError(errThree))
}
func TestParseURL(t *testing.T) {
testcases := []struct {
URL string
Hostname string
}{
{"https://scanme.sh:443", "scanme.sh:443"},
{"http://scanme.sh/path", "scanme.sh"},
{"scanme.sh:443/path", "scanme.sh:443"},
{"scanme.sh/path", "scanme.sh"},
}
for _, v := range testcases {
urlx := ParseHostname(v.URL)
if urlx == "" {
t.Errorf("failed to hostname of url %v", v)
}
if urlx != v.Hostname {
t.Errorf("hostname mismatch expected scanme.sh got %v", urlx)
}
}
}

View File

@ -2,6 +2,7 @@ package yaml
import (
"bytes"
"errors"
"os"
"regexp"
"strings"
@ -12,10 +13,18 @@ import (
var reImportsPattern = regexp.MustCompile(`(?m)# !include:(.+.yaml)`)
// StrictSyntax determines if pre-processing directives should be observed
var StrictSyntax bool
// PreProcess all include directives
func PreProcess(data []byte) ([]byte, error) {
// find all matches like !include:path\n
importMatches := reImportsPattern.FindAllSubmatch(data, -1)
hasImportDirectives := len(importMatches) > 0
if hasImportDirectives && StrictSyntax {
return data, errors.New("include directive preprocessing is disabled")
}
var replaceItems []string