Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

disable non default templates as default #5370

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/integration-test/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ type codePreCondition struct{}

// Execute executes a test case and returns an error if occurred
func (h *codePreCondition) Execute(filePath string) error {
results, err := testutils.RunNucleiArgsWithEnvAndGetResults(debug, getEnvValues(), "-t", filePath, "-u", "input", "-code")
results, err := testutils.RunNucleiArgsWithEnvAndGetResults(debug, getEnvValues(), "-t", filePath, "-u", "input", "-code", "-var", "foo=bar")
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/integration-test/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ func (h *httpRequestSelfContained) Execute(filePath string) error {
}()
defer server.Close()

results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-var foo=bar")
if err != nil {
return err
}
Expand Down Expand Up @@ -988,7 +988,7 @@ func (h *httpRequestSelfContainedWithParams) Execute(filePath string) error {
}()
defer server.Close()

results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-var foo=bar")
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/integration-test/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (h *networkRequestSelContained) Execute(filePath string) error {
_, _ = conn.Write([]byte("Authentication successful"))
})
defer ts.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-var foo=bar")
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ require (
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect
github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect
github.com/refraction-networking/utls v1.6.6 // indirect
github.com/samber/lo v1.44.0 // indirect
github.com/sashabaranov/go-openai v1.15.3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/samber/lo v1.44.0 h1:5il56KxRE+GHsm1IR+sZ/6J42NODigFiqCWpSc2dybA=
github.com/samber/lo v1.44.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sashabaranov/go-openai v1.15.3 h1:rzoNK9n+Cak+PM6OQ9puxDmFllxfnVea9StlmhglXqA=
github.com/sashabaranov/go-openai v1.15.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
Expand Down
3 changes: 3 additions & 0 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ func (r *Runner) RunEnumeration() error {
// if input type is not list (implicitly enable fuzzing)
r.options.DAST = true
}

store, err := loader.New(loaderConfig)
if err != nil {
return errors.Wrap(err, "Could not create loader.")
Expand Down Expand Up @@ -727,6 +728,8 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
stats.DisplayAsWarning(httpProtocol.SetThreadToCountZero)
stats.ForceDisplayWarning(templates.SkippedUnsignedStats)
stats.ForceDisplayWarning(templates.SkippedRequestSignatureStats)
stats.ForceDisplayWarning(templates.SkippedSelfContainedStats)
stats.ForceDisplayWarning(templates.SkippedFileStats)

cfg := config.DefaultConfig

Expand Down
70 changes: 70 additions & 0 deletions pkg/catalog/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import (
"io"
"net/url"
"os"
"regexp"
"sort"
"strings"
"sync"

"github.com/Knetic/govaluate"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader/filter"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
Expand All @@ -24,9 +27,11 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
"github.com/projectdiscovery/retryablehttp-go"
errorutil "github.com/projectdiscovery/utils/errors"
fileutil "github.com/projectdiscovery/utils/file"
sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
"github.com/samber/lo"
)

const (
Expand Down Expand Up @@ -465,6 +470,22 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
stats.Increment(templates.SkippedUnsignedStats)
return
}

if parsed.SelfContained &&
store.config.ExecutorOptions.Options.Vars.IsEmpty() && !store.config.ExecutorOptions.Options.EnvironmentVariables &&
templateContainsUnresolvedVariables(templatePath) {
stats.Increment(templates.SkippedSelfContainedStats)
return
}

if parsed.HasFileProtocol() &&
lo.NoneBy(store.config.ExecutorOptions.Options.Targets, func(target string) bool {
return fileutil.FileOrFolderExists(target)
}) {
stats.Increment(templates.SkippedFileStats)
return
}

Comment on lines +473 to +488
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we should compute this check here , the stats definetly belong here but checking everytime if target is a file for every template might increase latency on small hosts/boxes . i think it would be better if we precalcuate and put it in types.Options ( we do this for headless,DAST and other filtering ) so we could also add 2 options

HasGlobalVars bool
HasFileInput bool

or something similar

another reason for this is that nuclei supports target from various flags -u , -l and even input mode and this logic currently only checks for values of -u and not -l

// if template has request signature like aws then only signed and verified templates are allowed
if parsed.UsesRequestSignature() && !parsed.Verified {
stats.Increment(templates.SkippedRequestSignatureStats)
Expand Down Expand Up @@ -528,6 +549,55 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
return loadedTemplates.Slice
}

var (
numericalExpressionRegex = regexp.MustCompile(`^[0-9+\-/\W]+$`)
unresolvedVariablesRegex = regexp.MustCompile(`(?:%7[B|b]|\{){2}([^}]+)(?:%7[D|d]|\}){2}["'\)\}]*`)
)

// copy of the original function from pkg/protocols/common/expressions/variables.go:ContainsUnresolvedVariables
func templateContainsUnresolvedVariables(templatePath string) bool {
data, err := os.ReadFile(templatePath)
if err != nil {
return false
}

matches := unresolvedVariablesRegex.FindAllStringSubmatch(string(data), -1)
if len(matches) == 0 {
return false
}

var unresolvedVariables []string
for _, match := range matches {
if len(match) < 2 {
continue
}

// Skip if the match is an expression
if numericalExpressionRegex.MatchString(match[1]) {
continue
}
// or if it contains only literals (can be solved from expression engine)
if hasLiteralsOnly(match[1]) {
continue
}
unresolvedVariables = append(unresolvedVariables, match[1])
}

return len(unresolvedVariables) > 0
}

func hasLiteralsOnly(data string) bool {
expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions)
if err != nil {
return false
}
if expr != nil {
_, err = expr.Evaluate(nil)
return err == nil
}
Comment on lines +552 to +597
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is duplicated i think we can move it to pkg/utils because to avoid any inconsistencies in future and we can reuse it for other purpose as well

return true
}

// IsHTTPBasedProtocolUsed returns true if http/headless protocol is being used for
// any templates.
func IsHTTPBasedProtocolUsed(store *Store) bool {
Expand Down
2 changes: 2 additions & 0 deletions pkg/templates/parser_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ const (
ExludedDastTmplStats = "fuzz-flag-missing-warnings"
SkippedUnsignedStats = "skipped-unsigned-stats" // tracks loading of unsigned templates
SkippedRequestSignatureStats = "skipped-request-signature-stats"
SkippedSelfContainedStats = "skipped-self-contained-stats"
SkippedFileStats = "skipped-file-stats"
)
2 changes: 2 additions & 0 deletions pkg/templates/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ func init() {
stats.NewEntry(ExludedDastTmplStats, "Excluded %d dast template[s] (disabled as default), use -dast option to run dast templates.")
stats.NewEntry(SkippedUnsignedStats, "Skipping %d unsigned template[s]")
stats.NewEntry(SkippedRequestSignatureStats, "Skipping %d templates, HTTP Request signatures can only be used in Signed & Verified templates.")
stats.NewEntry(SkippedSelfContainedStats, "Skipping %d self-contained template[s], use -var or -env-vars flag to run them")
stats.NewEntry(SkippedFileStats, "Skipping %d file template[s], use file or directory as an input to run file templates")
}
5 changes: 5 additions & 0 deletions pkg/templates/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ func (template *Template) HasCodeProtocol() bool {
return len(template.RequestsCode) > 0
}

// HasFileProtocol returns true if the template has a file protocol section
func (template *Template) HasFileProtocol() bool {
return len(template.RequestsFile) > 0
}

// validateAllRequestIDs check if that protocol already has given id if not
// then is is manually set to proto_index
func (template *Template) validateAllRequestIDs() {
Expand Down
Loading