mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 19:55:26 +00:00
header fuzzing support in http templates (#4114)
* Add headersPartType for fuzzing * fix nil pointer dereference for headless mode * minor changes+ add integration test * update template in fuzz-header-multiple --------- Co-authored-by: 0x123456789 <0x123456789> Co-authored-by: Tarun Koyalwar <tarun@projectdiscovery.io>
This commit is contained in:
parent
bafde6c633
commit
c377221a78
49
integration_tests/fuzz/fuzz-header-basic.yaml
Normal file
49
integration_tests/fuzz/fuzz-header-basic.yaml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
id: fuzz-header-basic
|
||||||
|
|
||||||
|
info:
|
||||||
|
name: fuzz header basic
|
||||||
|
author: pdteam
|
||||||
|
severity: info
|
||||||
|
description: |
|
||||||
|
In this template we check for any reflection when fuzzing Origin header
|
||||||
|
|
||||||
|
variables:
|
||||||
|
first: "{{rand_int(10000, 99999)}}"
|
||||||
|
|
||||||
|
http:
|
||||||
|
- raw:
|
||||||
|
- |
|
||||||
|
GET /?x=aaa&y=bbb HTTP/1.1
|
||||||
|
Host: {{Hostname}}
|
||||||
|
Origin: https://example.com
|
||||||
|
X-Fuzz-Header: 1337
|
||||||
|
Cookie: z=aaa; bb=aaa
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
|
||||||
|
Accept-Language: en-US,en;q=0.9
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
payloads:
|
||||||
|
reflection:
|
||||||
|
- "'\"><{{first}}"
|
||||||
|
|
||||||
|
fuzzing:
|
||||||
|
- part: headers
|
||||||
|
type: replace
|
||||||
|
mode: single
|
||||||
|
keys: ["Origin"]
|
||||||
|
fuzz:
|
||||||
|
- "{{reflection}}"
|
||||||
|
|
||||||
|
stop-at-first-match: true
|
||||||
|
matchers-condition: and
|
||||||
|
matchers:
|
||||||
|
- type: word
|
||||||
|
part: body
|
||||||
|
words:
|
||||||
|
- "{{reflection}}"
|
||||||
|
|
||||||
|
- type: word
|
||||||
|
part: header
|
||||||
|
words:
|
||||||
|
- "text/html"
|
||||||
41
integration_tests/fuzz/fuzz-header-multiple.yaml
Normal file
41
integration_tests/fuzz/fuzz-header-multiple.yaml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
id: fuzz-header-multiple
|
||||||
|
|
||||||
|
info:
|
||||||
|
name: fuzz header multiple
|
||||||
|
author: pdteam
|
||||||
|
severity: info
|
||||||
|
description: |
|
||||||
|
In this template we fuzz multiple headers with single payload
|
||||||
|
|
||||||
|
http:
|
||||||
|
- raw:
|
||||||
|
- |
|
||||||
|
GET /?x=aaa&y=bbb HTTP/1.1
|
||||||
|
Host: {{Hostname}}
|
||||||
|
Origin: https://example.com
|
||||||
|
X-Forwared-For: 1337
|
||||||
|
Cookie: z=aaa; bb=aaa
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
|
||||||
|
Accept-Language: en-US,en;q=0.9
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
payloads:
|
||||||
|
reflection:
|
||||||
|
- "secret.local"
|
||||||
|
|
||||||
|
fuzzing:
|
||||||
|
- part: headers
|
||||||
|
type: replace
|
||||||
|
mode: multiple
|
||||||
|
keys: ["Origin", "X-Forwared-For"]
|
||||||
|
fuzz:
|
||||||
|
- "{{reflection}}"
|
||||||
|
|
||||||
|
stop-at-first-match: true
|
||||||
|
matchers-condition: and
|
||||||
|
matchers:
|
||||||
|
- type: word
|
||||||
|
part: body
|
||||||
|
words:
|
||||||
|
- "admin"
|
||||||
@ -17,6 +17,8 @@ var fuzzingTestCases = []TestCaseInfo{
|
|||||||
{Path: "fuzz/fuzz-type.yaml", TestCase: &fuzzTypeOverride{}},
|
{Path: "fuzz/fuzz-type.yaml", TestCase: &fuzzTypeOverride{}},
|
||||||
{Path: "fuzz/fuzz-query.yaml", TestCase: &httpFuzzQuery{}},
|
{Path: "fuzz/fuzz-query.yaml", TestCase: &httpFuzzQuery{}},
|
||||||
{Path: "fuzz/fuzz-headless.yaml", TestCase: &HeadlessFuzzingQuery{}},
|
{Path: "fuzz/fuzz-headless.yaml", TestCase: &HeadlessFuzzingQuery{}},
|
||||||
|
{Path: "fuzz/fuzz-header-basic.yaml", TestCase: &FuzzHeaderBasic{}},
|
||||||
|
{Path: "fuzz/fuzz-header-multiple.yaml", TestCase: &FuzzHeaderMultiple{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpFuzzQuery struct{}
|
type httpFuzzQuery struct{}
|
||||||
@ -147,3 +149,52 @@ func (h *HeadlessFuzzingQuery) Execute(filePath string) error {
|
|||||||
}
|
}
|
||||||
return expectResultsCount(got, 2)
|
return expectResultsCount(got, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FuzzHeaderBasic struct{}
|
||||||
|
|
||||||
|
// Execute executes a test case and returns an error if occurred
|
||||||
|
func (h *FuzzHeaderBasic) Execute(filePath string) error {
|
||||||
|
router := httprouter.New()
|
||||||
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
host := r.Header.Get("Origin")
|
||||||
|
// redirect to different domain
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, "<html><body><a href="+host+">Click Here</a></body></html>")
|
||||||
|
})
|
||||||
|
ts := httptest.NewTLSServer(router)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return expectResultsCount(got, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FuzzHeaderMultiple struct{}
|
||||||
|
|
||||||
|
// Execute executes a test case and returns an error if occurred
|
||||||
|
func (h *FuzzHeaderMultiple) Execute(filePath string) error {
|
||||||
|
router := httprouter.New()
|
||||||
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
host1 := r.Header.Get("Origin")
|
||||||
|
host2 := r.Header.Get("X-Forwared-For")
|
||||||
|
|
||||||
|
fmt.Printf("host1: %s, host2: %s\n", host1, host2)
|
||||||
|
if host1 == host2 && host2 == "secret.local" {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, "welcome! to secret admin panel")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// redirect to different domain
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
})
|
||||||
|
ts := httptest.NewTLSServer(router)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return expectResultsCount(got, 1)
|
||||||
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
||||||
"github.com/projectdiscovery/retryablehttp-go"
|
"github.com/projectdiscovery/retryablehttp-go"
|
||||||
urlutil "github.com/projectdiscovery/utils/url"
|
errorutil "github.com/projectdiscovery/utils/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecuteRuleInput is the input for rule Execute function
|
// ExecuteRuleInput is the input for rule Execute function
|
||||||
@ -42,8 +42,11 @@ type GeneratedRequest struct {
|
|||||||
// Input is not thread safe and should not be shared between concurrent
|
// Input is not thread safe and should not be shared between concurrent
|
||||||
// goroutines.
|
// goroutines.
|
||||||
func (rule *Rule) Execute(input *ExecuteRuleInput) error {
|
func (rule *Rule) Execute(input *ExecuteRuleInput) error {
|
||||||
if !rule.isExecutable(input.Input) {
|
if input.BaseRequest == nil {
|
||||||
return nil
|
return errorutil.NewWithTag("fuzz", "base request is nil for rule %v", rule)
|
||||||
|
}
|
||||||
|
if !rule.isExecutable(input.BaseRequest) {
|
||||||
|
return errorutil.NewWithTag("fuzz", "rule is not executable on %v", input.BaseRequest.URL.String())
|
||||||
}
|
}
|
||||||
baseValues := input.Values
|
baseValues := input.Values
|
||||||
if rule.generator == nil {
|
if rule.generator == nil {
|
||||||
@ -70,12 +73,11 @@ func (rule *Rule) Execute(input *ExecuteRuleInput) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// isExecutable returns true if the rule can be executed based on provided input
|
// isExecutable returns true if the rule can be executed based on provided input
|
||||||
func (rule *Rule) isExecutable(input *contextargs.Context) bool {
|
func (rule *Rule) isExecutable(req *retryablehttp.Request) bool {
|
||||||
parsed, err := urlutil.Parse(input.MetaInput.Input)
|
if !req.Query().IsEmpty() && rule.partType == queryPartType {
|
||||||
if err != nil {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
if !parsed.Query().IsEmpty() && rule.partType == queryPartType {
|
if len(req.Header) > 0 && rule.partType == headersPartType {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package fuzz
|
package fuzz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/projectdiscovery/retryablehttp-go"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,11 +12,15 @@ func TestRuleIsExecutable(t *testing.T) {
|
|||||||
err := rule.Compile(nil, nil)
|
err := rule.Compile(nil, nil)
|
||||||
require.NoError(t, err, "could not compile rule")
|
require.NoError(t, err, "could not compile rule")
|
||||||
|
|
||||||
input := contextargs.NewWithInput("https://example.com/?url=localhost")
|
req, err := retryablehttp.NewRequest("GET", "https://example.com/?url=localhost", nil)
|
||||||
result := rule.isExecutable(input)
|
require.NoError(t, err, "could not build request")
|
||||||
|
|
||||||
|
result := rule.isExecutable(req)
|
||||||
require.True(t, result, "could not get correct result")
|
require.True(t, result, "could not get correct result")
|
||||||
|
|
||||||
input = contextargs.NewWithInput("https://example.com/")
|
req, err = retryablehttp.NewRequest("GET", "https://example.com/", nil)
|
||||||
result = rule.isExecutable(input)
|
require.NoError(t, err, "could not build request")
|
||||||
|
|
||||||
|
result = rule.isExecutable(req)
|
||||||
require.False(t, result, "could not get correct result")
|
require.False(t, result, "could not get correct result")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,10 +99,12 @@ type partType int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
queryPartType partType = iota + 1
|
queryPartType partType = iota + 1
|
||||||
|
headersPartType
|
||||||
)
|
)
|
||||||
|
|
||||||
var stringToPartType = map[string]partType{
|
var stringToPartType = map[string]partType{
|
||||||
"query": queryPartType,
|
"query": queryPartType,
|
||||||
|
"headers": headersPartType,
|
||||||
}
|
}
|
||||||
|
|
||||||
// modeType is the mode of rule enum declaration
|
// modeType is the mode of rule enum declaration
|
||||||
|
|||||||
@ -2,9 +2,13 @@ package fuzz
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/projectdiscovery/gologger"
|
||||||
|
|
||||||
"github.com/corpix/uarand"
|
"github.com/corpix/uarand"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions"
|
"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/generators"
|
||||||
@ -19,6 +23,46 @@ func (rule *Rule) executePartRule(input *ExecuteRuleInput, payload string) error
|
|||||||
switch rule.partType {
|
switch rule.partType {
|
||||||
case queryPartType:
|
case queryPartType:
|
||||||
return rule.executeQueryPartRule(input, payload)
|
return rule.executeQueryPartRule(input, payload)
|
||||||
|
case headersPartType:
|
||||||
|
return rule.executeHeadersPartRule(input, payload)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeHeadersPartRule executes headers part rules
|
||||||
|
func (rule *Rule) executeHeadersPartRule(input *ExecuteRuleInput, payload string) error {
|
||||||
|
// clone the request to avoid modifying the original
|
||||||
|
originalRequest := input.BaseRequest
|
||||||
|
req := originalRequest.Clone(context.TODO())
|
||||||
|
// Also clone headers
|
||||||
|
headers := req.Header.Clone()
|
||||||
|
|
||||||
|
for key, values := range originalRequest.Header {
|
||||||
|
cloned := sliceutil.Clone(values)
|
||||||
|
for i, value := range values {
|
||||||
|
if !rule.matchKeyOrValue(key, value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var evaluated string
|
||||||
|
evaluated, input.InteractURLs = rule.executeEvaluate(input, key, value, payload, input.InteractURLs)
|
||||||
|
cloned[i] = evaluated
|
||||||
|
|
||||||
|
if rule.modeType == singleModeType {
|
||||||
|
headers[key] = cloned
|
||||||
|
if err := rule.buildHeadersInput(input, headers, input.InteractURLs); err != nil && err != io.EOF {
|
||||||
|
gologger.Error().Msgf("Could not build request for headers part rule %v: %s\n", rule, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cloned[i] = value // change back to previous value for headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headers[key] = cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
if rule.modeType == multipleModeType {
|
||||||
|
if err := rule.buildHeadersInput(input, headers, input.InteractURLs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -67,6 +111,29 @@ func (rule *Rule) executeQueryPartRule(input *ExecuteRuleInput, payload string)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildHeadersInput returns created request for a Headers Input
|
||||||
|
func (rule *Rule) buildHeadersInput(input *ExecuteRuleInput, headers http.Header, interactURLs []string) error {
|
||||||
|
var req *retryablehttp.Request
|
||||||
|
if input.BaseRequest == nil {
|
||||||
|
return errors.New("Base request cannot be nil when fuzzing headers")
|
||||||
|
} else {
|
||||||
|
req = input.BaseRequest.Clone(context.TODO())
|
||||||
|
req.Header = headers
|
||||||
|
// update host of request and not URL
|
||||||
|
// URL.Host is used to dial the connection
|
||||||
|
req.Request.Host = req.Header.Get("Host")
|
||||||
|
}
|
||||||
|
request := GeneratedRequest{
|
||||||
|
Request: req,
|
||||||
|
InteractURLs: interactURLs,
|
||||||
|
DynamicValues: input.Values,
|
||||||
|
}
|
||||||
|
if !input.Callback(request) {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// buildQueryInput returns created request for a Query Input
|
// buildQueryInput returns created request for a Query Input
|
||||||
func (rule *Rule) buildQueryInput(input *ExecuteRuleInput, parsed *urlutil.URL, interactURLs []string) error {
|
func (rule *Rule) buildQueryInput(input *ExecuteRuleInput, parsed *urlutil.URL, interactURLs []string) error {
|
||||||
var req *retryablehttp.Request
|
var req *retryablehttp.Request
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package fuzz
|
package fuzz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/projectdiscovery/retryablehttp-go"
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||||
@ -9,6 +11,68 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestExecuteHeadersPartRule(t *testing.T) {
|
||||||
|
options := &protocols.ExecutorOptions{
|
||||||
|
Interactsh: &interactsh.Client{},
|
||||||
|
}
|
||||||
|
req, err := retryablehttp.NewRequest("GET", "http://localhost:8080/", nil)
|
||||||
|
require.NoError(t, err, "can't build request")
|
||||||
|
|
||||||
|
req.Header.Set("X-Custom-Foo", "foo")
|
||||||
|
req.Header.Set("X-Custom-Bar", "bar")
|
||||||
|
|
||||||
|
t.Run("single", func(t *testing.T) {
|
||||||
|
rule := &Rule{
|
||||||
|
ruleType: postfixRuleType,
|
||||||
|
partType: headersPartType,
|
||||||
|
modeType: singleModeType,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
var generatedHeaders []http.Header
|
||||||
|
err := rule.executeHeadersPartRule(&ExecuteRuleInput{
|
||||||
|
Input: contextargs.New(),
|
||||||
|
BaseRequest: req,
|
||||||
|
Callback: func(gr GeneratedRequest) bool {
|
||||||
|
generatedHeaders = append(generatedHeaders, gr.Request.Header.Clone())
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}, "1337'")
|
||||||
|
require.NoError(t, err, "could not execute part rule")
|
||||||
|
require.ElementsMatch(t, []http.Header{
|
||||||
|
{
|
||||||
|
"X-Custom-Foo": {"foo1337'"},
|
||||||
|
"X-Custom-Bar": {"bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"X-Custom-Foo": {"foo"},
|
||||||
|
"X-Custom-Bar": {"bar1337'"},
|
||||||
|
},
|
||||||
|
}, generatedHeaders, "could not get generated headers")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple", func(t *testing.T) {
|
||||||
|
rule := &Rule{
|
||||||
|
ruleType: postfixRuleType,
|
||||||
|
partType: headersPartType,
|
||||||
|
modeType: multipleModeType,
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
var generatedHeaders http.Header
|
||||||
|
err := rule.executeHeadersPartRule(&ExecuteRuleInput{
|
||||||
|
Input: contextargs.New(),
|
||||||
|
BaseRequest: req,
|
||||||
|
Callback: func(gr GeneratedRequest) bool {
|
||||||
|
generatedHeaders = gr.Request.Header.Clone()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}, "1337'")
|
||||||
|
require.NoError(t, err, "could not execute part rule")
|
||||||
|
require.Equal(t, http.Header{
|
||||||
|
"X-Custom-Foo": {"foo1337'"},
|
||||||
|
"X-Custom-Bar": {"bar1337'"},
|
||||||
|
}, generatedHeaders, "could not get generated headers")
|
||||||
|
})
|
||||||
|
}
|
||||||
func TestExecuteQueryPartRule(t *testing.T) {
|
func TestExecuteQueryPartRule(t *testing.T) {
|
||||||
URL := "http://localhost:8080/?url=localhost&mode=multiple&file=passwdfile"
|
URL := "http://localhost:8080/?url=localhost&mode=multiple&file=passwdfile"
|
||||||
options := &protocols.ExecutorOptions{
|
options := &protocols.ExecutorOptions{
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/projectdiscovery/retryablehttp-go"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
@ -211,12 +213,16 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, payloads
|
|||||||
if _, err := urlutil.Parse(input.MetaInput.Input); err != nil {
|
if _, err := urlutil.Parse(input.MetaInput.Input); err != nil {
|
||||||
return errors.Wrap(err, "could not parse url")
|
return errors.Wrap(err, "could not parse url")
|
||||||
}
|
}
|
||||||
|
baseRequest, err := retryablehttp.NewRequest("GET", input.MetaInput.Input, nil)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not create base request")
|
||||||
|
}
|
||||||
for _, rule := range request.Fuzzing {
|
for _, rule := range request.Fuzzing {
|
||||||
err := rule.Execute(&fuzz.ExecuteRuleInput{
|
err := rule.Execute(&fuzz.ExecuteRuleInput{
|
||||||
Input: input,
|
Input: input,
|
||||||
Callback: fuzzRequestCallback,
|
Callback: fuzzRequestCallback,
|
||||||
Values: payloads,
|
Values: payloads,
|
||||||
BaseRequest: nil,
|
BaseRequest: baseRequest,
|
||||||
})
|
})
|
||||||
if err == types.ErrNoMoreRequests {
|
if err == types.ErrNoMoreRequests {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -232,8 +232,12 @@ func (request *Request) executeTurboHTTP(input *contextargs.Context, dynamicValu
|
|||||||
|
|
||||||
// executeFuzzingRule executes fuzzing request for a URL
|
// executeFuzzingRule executes fuzzing request for a URL
|
||||||
func (request *Request) executeFuzzingRule(input *contextargs.Context, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
func (request *Request) executeFuzzingRule(input *contextargs.Context, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
||||||
if _, err := urlutil.Parse(input.MetaInput.Input); err != nil {
|
// If request is self-contained we don't need to parse any input.
|
||||||
return errors.Wrap(err, "could not parse url")
|
if !request.SelfContained {
|
||||||
|
// If it's not self-contained we parse user provided input
|
||||||
|
if _, err := urlutil.Parse(input.MetaInput.Input); err != nil {
|
||||||
|
return errors.Wrap(err, "could not parse url")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fuzzRequestCallback := func(gr fuzz.GeneratedRequest) bool {
|
fuzzRequestCallback := func(gr fuzz.GeneratedRequest) bool {
|
||||||
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
|
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
|
||||||
@ -276,6 +280,7 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, previous
|
|||||||
if request.options.HostErrorsCache != nil {
|
if request.options.HostErrorsCache != nil {
|
||||||
request.options.HostErrorsCache.MarkFailed(input.MetaInput.Input, requestErr)
|
request.options.HostErrorsCache.MarkFailed(input.MetaInput.Input, requestErr)
|
||||||
}
|
}
|
||||||
|
gologger.Verbose().Msgf("[%s] Error occurred in request: %s\n", request.options.TemplateID, requestErr)
|
||||||
}
|
}
|
||||||
request.options.Progress.IncrementRequests()
|
request.options.Progress.IncrementRequests()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user