mirror of https://github.com/daffainfo/nuclei.git
Added check for unresolved variables
parent
eb2dee22f1
commit
ce13bf34d0
|
@ -0,0 +1,32 @@
|
|||
package expressions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var unresolvedVariablesRegex = regexp.MustCompile(`\{\{(.+)\}\}`)
|
||||
|
||||
// ContainsUnresolvedVariables returns an error with variable names if the passed
|
||||
// input contains unresolved {{<pattern-here>}} variables.
|
||||
func ContainsUnresolvedVariables(data string) error {
|
||||
matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)
|
||||
if len(matches) == 0 {
|
||||
return nil
|
||||
}
|
||||
errorString := &strings.Builder{}
|
||||
errorString.WriteString("unresolved variables found: ")
|
||||
|
||||
for i, match := range matches {
|
||||
if len(match) < 2 {
|
||||
continue
|
||||
}
|
||||
errorString.WriteString(match[1])
|
||||
if i != len(matches)-1 {
|
||||
errorString.WriteString(",")
|
||||
}
|
||||
}
|
||||
errorMessage := errorString.String()
|
||||
return errors.New(errorMessage)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package expressions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUnresolvedVariablesCheck(t *testing.T) {
|
||||
tests := []struct {
|
||||
data string
|
||||
err error
|
||||
}{
|
||||
{"{{test}}", errors.New("unresolved variables found: test")},
|
||||
{"{{test}}/{{another}}", errors.New("unresolved variables found: test,another")},
|
||||
{"test", nil},
|
||||
}
|
||||
for _, test := range tests {
|
||||
err := ContainsUnresolvedVariables(test.data)
|
||||
require.Equal(t, test.err, err, "could not get unresolved variables")
|
||||
}
|
||||
}
|
|
@ -167,6 +167,9 @@ type Request struct {
|
|||
// description: |
|
||||
// StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.
|
||||
StopAtFirstMatch bool `yaml:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop the execution after a match is found"`
|
||||
// description: |
|
||||
// SkipVariablesCheck skips the check for unresolved variables in request
|
||||
SkipVariablesCheck bool `yaml:"skip-variables-check,omitempty" jsonschema:"title=skip variable checks,description=Skips the check for unresolved variables in request"`
|
||||
}
|
||||
|
||||
// GetID returns the unique ID of the request if any.
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||
"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/interactsh"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/tostring"
|
||||
|
@ -272,6 +273,27 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, previ
|
|||
err error
|
||||
)
|
||||
|
||||
// For race conditions we can't dump the request body at this point as it's already waiting the open-gate event, already handled with a similar code within the race function
|
||||
if !request.original.Race {
|
||||
var dumpError error
|
||||
dumpedRequest, dumpError = dump(request, reqURL)
|
||||
if dumpError != nil {
|
||||
return dumpError
|
||||
}
|
||||
dumpedRequestString := string(dumpedRequest)
|
||||
|
||||
// Check if are there any unresolved variables. If yes, skip unless overriden by user.
|
||||
if varErr := expressions.ContainsUnresolvedVariables(dumpedRequestString); varErr != nil && !r.SkipVariablesCheck {
|
||||
gologger.Warning().Msgf("Could not make http request for %s: %v\n", reqURL, varErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.options.Options.Debug || r.options.Options.DebugRequests {
|
||||
gologger.Info().Msgf("[%s] Dumped HTTP request for %s\n\n", r.options.TemplateID, reqURL)
|
||||
gologger.Print().Msgf("%s")
|
||||
}
|
||||
}
|
||||
|
||||
var formedURL string
|
||||
var hostname string
|
||||
timeStart := time.Now()
|
||||
|
@ -310,20 +332,6 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, previ
|
|||
resp, err = r.httpClient.Do(request.request)
|
||||
}
|
||||
}
|
||||
|
||||
// For race conditions we can't dump the request body at this point as it's already waiting the open-gate event, already handled with a similar code within the race function
|
||||
if !request.original.Race {
|
||||
var dumpError error
|
||||
dumpedRequest, dumpError = dump(request, reqURL)
|
||||
if dumpError != nil {
|
||||
return dumpError
|
||||
}
|
||||
|
||||
if r.options.Options.Debug || r.options.Options.DebugRequests {
|
||||
gologger.Info().Msgf("[%s] Dumped HTTP request for %s\n\n", r.options.TemplateID, reqURL)
|
||||
gologger.Print().Msgf("%s", string(dumpedRequest))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// rawhttp doesn't support draining response bodies.
|
||||
if resp != nil && resp.Body != nil && request.rawRequest == nil {
|
||||
|
|
|
@ -139,6 +139,10 @@ func (r *Request) executeRequestWithPayloads(actualAddress, address, input strin
|
|||
}
|
||||
reqBuilder.Write(finalData)
|
||||
|
||||
if varErr := expressions.ContainsUnresolvedVariables(string(finalData)); varErr != nil {
|
||||
gologger.Warning().Msgf("Could not make network request for %s: %v\n", actualAddress, varErr)
|
||||
return nil
|
||||
}
|
||||
if _, err := conn.Write(finalData); err != nil {
|
||||
r.options.Output.Request(r.options.TemplateID, address, "network", err)
|
||||
r.options.Progress.IncrementFailedRequestsBy(1)
|
||||
|
|
Loading…
Reference in New Issue