Added check for unresolved variables

dev
Ice3man543 2021-10-07 01:40:49 +05:30
parent eb2dee22f1
commit ce13bf34d0
5 changed files with 84 additions and 14 deletions

View File

@ -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)
}

View File

@ -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")
}
}

View File

@ -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.

View File

@ -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 {

View File

@ -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)