mirror of https://github.com/daffainfo/nuclei.git
Merge from dev
commit
213853c45d
|
@ -109,7 +109,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||||
flagSet.IntVar(&options.InteractionsCacheSize, "interactions-cache-size", 5000, "number of requests to keep in the interactions cache"),
|
flagSet.IntVar(&options.InteractionsCacheSize, "interactions-cache-size", 5000, "number of requests to keep in the interactions cache"),
|
||||||
flagSet.IntVar(&options.InteractionsEviction, "interactions-eviction", 60, "number of seconds to wait before evicting requests from cache"),
|
flagSet.IntVar(&options.InteractionsEviction, "interactions-eviction", 60, "number of seconds to wait before evicting requests from cache"),
|
||||||
flagSet.IntVar(&options.InteractionsPollDuration, "interactions-poll-duration", 5, "number of seconds to wait before each interaction poll request"),
|
flagSet.IntVar(&options.InteractionsPollDuration, "interactions-poll-duration", 5, "number of seconds to wait before each interaction poll request"),
|
||||||
flagSet.IntVar(&options.InteractionsColldownPeriod, "interactions-cooldown-period", 5, "extra time for interaction polling before exiting"),
|
flagSet.IntVar(&options.InteractionsCooldownPeriod, "interactions-cooldown-period", 5, "extra time for interaction polling before exiting"),
|
||||||
flagSet.BoolVarP(&options.NoInteractsh, "no-interactsh", "ni", false, "disable interactsh server for OAST testing, exclude OAST based templates"),
|
flagSet.BoolVarP(&options.NoInteractsh, "no-interactsh", "ni", false, "disable interactsh server for OAST testing, exclude OAST based templates"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ func New(options *types.Options) (*Runner, error) {
|
||||||
opts.Authorization = options.InteractshToken
|
opts.Authorization = options.InteractshToken
|
||||||
opts.CacheSize = int64(options.InteractionsCacheSize)
|
opts.CacheSize = int64(options.InteractionsCacheSize)
|
||||||
opts.Eviction = time.Duration(options.InteractionsEviction) * time.Second
|
opts.Eviction = time.Duration(options.InteractionsEviction) * time.Second
|
||||||
opts.ColldownPeriod = time.Duration(options.InteractionsColldownPeriod) * time.Second
|
opts.ColldownPeriod = time.Duration(options.InteractionsCooldownPeriod) * time.Second
|
||||||
opts.PollDuration = time.Duration(options.InteractionsPollDuration) * time.Second
|
opts.PollDuration = time.Duration(options.InteractionsPollDuration) * time.Second
|
||||||
|
|
||||||
interactshClient, err := interactsh.New(opts)
|
interactshClient, err := interactsh.New(opts)
|
||||||
|
|
|
@ -220,12 +220,14 @@ func (c *Client) Close() bool {
|
||||||
//
|
//
|
||||||
// It accepts data to replace as well as the URL to replace placeholders
|
// It accepts data to replace as well as the URL to replace placeholders
|
||||||
// with generated uniquely for each request.
|
// with generated uniquely for each request.
|
||||||
func (c *Client) ReplaceMarkers(data, interactshURL string) string {
|
func (c *Client) ReplaceMarkers(data string, interactshURLs []string) (string, []string) {
|
||||||
if !strings.Contains(data, interactshURLMarker) {
|
|
||||||
return data
|
for strings.Contains(data, interactshURLMarker) {
|
||||||
|
url := c.URL()
|
||||||
|
interactshURLs = append(interactshURLs, url)
|
||||||
|
data = strings.Replace(data, interactshURLMarker, url, 1)
|
||||||
}
|
}
|
||||||
replaced := strings.NewReplacer("{{interactsh-url}}", interactshURL).Replace(data)
|
return data, interactshURLs
|
||||||
return replaced
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeResultEventFunc is a result making function for nuclei
|
// MakeResultEventFunc is a result making function for nuclei
|
||||||
|
@ -241,7 +243,8 @@ type RequestData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestEvent is the event for a network request sent by nuclei.
|
// RequestEvent is the event for a network request sent by nuclei.
|
||||||
func (c *Client) RequestEvent(interactshURL string, data *RequestData) {
|
func (c *Client) RequestEvent(interactshURLs []string, data *RequestData) {
|
||||||
|
for _, interactshURL := range interactshURLs {
|
||||||
id := strings.TrimSuffix(interactshURL, c.dotHostname)
|
id := strings.TrimSuffix(interactshURL, c.dotHostname)
|
||||||
|
|
||||||
interaction := c.interactions.Get(id)
|
interaction := c.interactions.Get(id)
|
||||||
|
@ -252,21 +255,19 @@ func (c *Client) RequestEvent(interactshURL string, data *RequestData) {
|
||||||
c.requests.Set(id, data, c.eviction)
|
c.requests.Set(id, data, c.eviction)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
matched := false
|
|
||||||
for _, interaction := range interactions {
|
for _, interaction := range interactions {
|
||||||
if c.processInteractionForRequest(interaction, data) {
|
if c.processInteractionForRequest(interaction, data) {
|
||||||
matched = true
|
c.interactions.Delete(id)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matched {
|
|
||||||
c.interactions.Delete(id)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
c.requests.Set(id, data, c.eviction)
|
c.requests.Set(id, data, c.eviction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// HasMatchers returns true if an operator has interactsh part
|
// HasMatchers returns true if an operator has interactsh part
|
||||||
// matchers or extractors.
|
// matchers or extractors.
|
||||||
//
|
//
|
||||||
|
|
|
@ -38,6 +38,7 @@ type generatedRequest struct {
|
||||||
pipelinedClient *rawhttp.PipelineClient
|
pipelinedClient *rawhttp.PipelineClient
|
||||||
request *retryablehttp.Request
|
request *retryablehttp.Request
|
||||||
dynamicValues map[string]interface{}
|
dynamicValues map[string]interface{}
|
||||||
|
interactshURLs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *generatedRequest) URL() string {
|
func (g *generatedRequest) URL() string {
|
||||||
|
@ -52,9 +53,9 @@ func (g *generatedRequest) URL() string {
|
||||||
|
|
||||||
// Make creates a http request for the provided input.
|
// Make creates a http request for the provided input.
|
||||||
// It returns io.EOF as error when all the requests have been exhausted.
|
// It returns io.EOF as error when all the requests have been exhausted.
|
||||||
func (r *requestGenerator) Make(baseURL string, dynamicValues map[string]interface{}, interactURL string) (*generatedRequest, error) {
|
func (r *requestGenerator) Make(baseURL string, dynamicValues map[string]interface{}) (*generatedRequest, error) {
|
||||||
if r.request.SelfContained {
|
if r.request.SelfContained {
|
||||||
return r.makeSelfContainedRequest(dynamicValues, interactURL)
|
return r.makeSelfContainedRequest(dynamicValues)
|
||||||
}
|
}
|
||||||
// We get the next payload for the request.
|
// We get the next payload for the request.
|
||||||
data, payloads, ok := r.nextValue()
|
data, payloads, ok := r.nextValue()
|
||||||
|
@ -63,12 +64,10 @@ func (r *requestGenerator) Make(baseURL string, dynamicValues map[string]interfa
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
if interactURL != "" {
|
data, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(data, r.interactshURLs)
|
||||||
data = r.options.Interactsh.ReplaceMarkers(data, interactURL)
|
|
||||||
|
|
||||||
for payloadName, payloadValue := range payloads {
|
for payloadName, payloadValue := range payloads {
|
||||||
payloads[payloadName] = r.options.Interactsh.ReplaceMarkers(types.ToString(payloadValue), interactURL)
|
payloads[payloadName], r.interactshURLs = r.options.Interactsh.ReplaceMarkers(types.ToString(payloadValue), r.interactshURLs)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed, err := url.Parse(baseURL)
|
parsed, err := url.Parse(baseURL)
|
||||||
|
@ -98,12 +97,12 @@ func (r *requestGenerator) Make(baseURL string, dynamicValues map[string]interfa
|
||||||
// If data contains \n it's a raw request, process it like raw. Else
|
// If data contains \n it's a raw request, process it like raw. Else
|
||||||
// continue with the template based request flow.
|
// continue with the template based request flow.
|
||||||
if isRawRequest {
|
if isRawRequest {
|
||||||
return r.makeHTTPRequestFromRaw(ctx, parsed.String(), data, values, payloads, interactURL)
|
return r.makeHTTPRequestFromRaw(ctx, parsed.String(), data, values, payloads)
|
||||||
}
|
}
|
||||||
return r.makeHTTPRequestFromModel(ctx, data, values, payloads, interactURL)
|
return r.makeHTTPRequestFromModel(ctx, data, values, payloads)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *requestGenerator) makeSelfContainedRequest(dynamicValues map[string]interface{}, interactURL string) (*generatedRequest, error) {
|
func (r *requestGenerator) makeSelfContainedRequest(dynamicValues map[string]interface{}) (*generatedRequest, error) {
|
||||||
// We get the next payload for the request.
|
// We get the next payload for the request.
|
||||||
data, payloads, ok := r.nextValue()
|
data, payloads, ok := r.nextValue()
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -136,13 +135,13 @@ func (r *requestGenerator) makeSelfContainedRequest(dynamicValues map[string]int
|
||||||
generators.BuildPayloadFromOptions(r.request.options.Options),
|
generators.BuildPayloadFromOptions(r.request.options.Options),
|
||||||
)
|
)
|
||||||
|
|
||||||
return r.makeHTTPRequestFromRaw(ctx, parsed.String(), data, values, payloads, interactURL)
|
return r.makeHTTPRequestFromRaw(ctx, parsed.String(), data, values, payloads)
|
||||||
}
|
}
|
||||||
values := generators.MergeMaps(
|
values := generators.MergeMaps(
|
||||||
dynamicValues,
|
dynamicValues,
|
||||||
generators.BuildPayloadFromOptions(r.request.options.Options),
|
generators.BuildPayloadFromOptions(r.request.options.Options),
|
||||||
)
|
)
|
||||||
return r.makeHTTPRequestFromModel(ctx, data, values, payloads, interactURL)
|
return r.makeHTTPRequestFromModel(ctx, data, values, payloads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Total returns the total number of requests for the generator
|
// Total returns the total number of requests for the generator
|
||||||
|
@ -171,10 +170,8 @@ func baseURLWithTemplatePrefs(data string, parsed *url.URL) (string, *url.URL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeHTTPRequestFromModel creates a *http.Request from a request template
|
// MakeHTTPRequestFromModel creates a *http.Request from a request template
|
||||||
func (r *requestGenerator) makeHTTPRequestFromModel(ctx context.Context, data string, values, generatorValues map[string]interface{}, interactURL string) (*generatedRequest, error) {
|
func (r *requestGenerator) makeHTTPRequestFromModel(ctx context.Context, data string, values, generatorValues map[string]interface{}) (*generatedRequest, error) {
|
||||||
if interactURL != "" {
|
data, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(data, r.interactshURLs)
|
||||||
data = r.options.Interactsh.ReplaceMarkers(data, interactURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine the template payloads along with base
|
// Combine the template payloads along with base
|
||||||
// request values.
|
// request values.
|
||||||
|
@ -198,18 +195,16 @@ func (r *requestGenerator) makeHTTPRequestFromModel(ctx context.Context, data st
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
request, err := r.fillRequest(req, finalValues, interactURL)
|
request, err := r.fillRequest(req, finalValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues}, nil
|
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues, interactshURLs: r.interactshURLs}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeHTTPRequestFromRaw creates a *http.Request from a raw request
|
// makeHTTPRequestFromRaw creates a *http.Request from a raw request
|
||||||
func (r *requestGenerator) makeHTTPRequestFromRaw(ctx context.Context, baseURL, data string, values, payloads map[string]interface{}, interactURL string) (*generatedRequest, error) {
|
func (r *requestGenerator) makeHTTPRequestFromRaw(ctx context.Context, baseURL, data string, values, payloads map[string]interface{}) (*generatedRequest, error) {
|
||||||
if interactURL != "" {
|
data, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(data, r.interactshURLs)
|
||||||
data = r.options.Interactsh.ReplaceMarkers(data, interactURL)
|
|
||||||
}
|
|
||||||
return r.handleRawWithPayloads(ctx, data, baseURL, values, payloads)
|
return r.handleRawWithPayloads(ctx, data, baseURL, values, payloads)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,21 +253,19 @@ func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest
|
||||||
req.Host = value
|
req.Host = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request, err := r.fillRequest(req, finalValues, "")
|
request, err := r.fillRequest(req, finalValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues}, nil
|
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues, interactshURLs: r.interactshURLs}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillRequest fills various headers in the request with values
|
// fillRequest fills various headers in the request with values
|
||||||
func (r *requestGenerator) fillRequest(req *http.Request, values map[string]interface{}, interactURL string) (*retryablehttp.Request, error) {
|
func (r *requestGenerator) fillRequest(req *http.Request, values map[string]interface{}) (*retryablehttp.Request, error) {
|
||||||
// Set the header values requested
|
// Set the header values requested
|
||||||
for header, value := range r.request.Headers {
|
for header, value := range r.request.Headers {
|
||||||
if interactURL != "" {
|
value, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(value, r.interactshURLs)
|
||||||
value = r.options.Interactsh.ReplaceMarkers(value, interactURL)
|
|
||||||
}
|
|
||||||
value, err := expressions.Evaluate(value, values)
|
value, err := expressions.Evaluate(value, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||||
|
@ -290,10 +283,8 @@ func (r *requestGenerator) fillRequest(req *http.Request, values map[string]inte
|
||||||
|
|
||||||
// Check if the user requested a request body
|
// Check if the user requested a request body
|
||||||
if r.request.Body != "" {
|
if r.request.Body != "" {
|
||||||
body := r.request.Body
|
var body string
|
||||||
if interactURL != "" {
|
body, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(r.request.Body, r.interactshURLs)
|
||||||
body = r.options.Interactsh.ReplaceMarkers(body, interactURL)
|
|
||||||
}
|
|
||||||
body, err := expressions.Evaluate(body, values)
|
body, err := expressions.Evaluate(body, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
return nil, errors.Wrap(err, "could not evaluate helper expressions")
|
||||||
|
|
|
@ -3,13 +3,14 @@ package http
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/model"
|
"github.com/projectdiscovery/nuclei/v2/pkg/model"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
||||||
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBaseURLWithTemplatePrefs(t *testing.T) {
|
func TestBaseURLWithTemplatePrefs(t *testing.T) {
|
||||||
|
@ -85,7 +86,7 @@ func TestMakeRequestFromModal(t *testing.T) {
|
||||||
require.Nil(t, err, "could not compile http request")
|
require.Nil(t, err, "could not compile http request")
|
||||||
|
|
||||||
generator := request.newGenerator()
|
generator := request.newGenerator()
|
||||||
req, err := generator.Make("https://example.com", map[string]interface{}{}, "")
|
req, err := generator.Make("https://example.com", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
|
|
||||||
bodyBytes, _ := req.request.BodyBytes()
|
bodyBytes, _ := req.request.BodyBytes()
|
||||||
|
@ -112,12 +113,12 @@ func TestMakeRequestFromModalTrimSuffixSlash(t *testing.T) {
|
||||||
require.Nil(t, err, "could not compile http request")
|
require.Nil(t, err, "could not compile http request")
|
||||||
|
|
||||||
generator := request.newGenerator()
|
generator := request.newGenerator()
|
||||||
req, err := generator.Make("https://example.com/test.php", map[string]interface{}{}, "")
|
req, err := generator.Make("https://example.com/test.php", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
require.Equal(t, "https://example.com/test.php?query=example", req.request.URL.String(), "could not get correct request path")
|
require.Equal(t, "https://example.com/test.php?query=example", req.request.URL.String(), "could not get correct request path")
|
||||||
|
|
||||||
generator = request.newGenerator()
|
generator = request.newGenerator()
|
||||||
req, err = generator.Make("https://example.com/test/", map[string]interface{}{}, "")
|
req, err = generator.Make("https://example.com/test/", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
require.Equal(t, "https://example.com/test/?query=example", req.request.URL.String(), "could not get correct request path")
|
require.Equal(t, "https://example.com/test/?query=example", req.request.URL.String(), "could not get correct request path")
|
||||||
}
|
}
|
||||||
|
@ -150,12 +151,12 @@ Accept-Encoding: gzip`},
|
||||||
require.Nil(t, err, "could not compile http request")
|
require.Nil(t, err, "could not compile http request")
|
||||||
|
|
||||||
generator := request.newGenerator()
|
generator := request.newGenerator()
|
||||||
req, err := generator.Make("https://example.com", map[string]interface{}{}, "")
|
req, err := generator.Make("https://example.com", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
authorization := req.request.Header.Get("Authorization")
|
authorization := req.request.Header.Get("Authorization")
|
||||||
require.Equal(t, "Basic admin:admin", authorization, "could not get correct authorization headers from raw")
|
require.Equal(t, "Basic admin:admin", authorization, "could not get correct authorization headers from raw")
|
||||||
|
|
||||||
req, err = generator.Make("https://example.com", map[string]interface{}{}, "")
|
req, err = generator.Make("https://example.com", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
authorization = req.request.Header.Get("Authorization")
|
authorization = req.request.Header.Get("Authorization")
|
||||||
require.Equal(t, "Basic admin:guest", authorization, "could not get correct authorization headers from raw")
|
require.Equal(t, "Basic admin:guest", authorization, "could not get correct authorization headers from raw")
|
||||||
|
@ -189,13 +190,66 @@ Accept-Encoding: gzip`},
|
||||||
require.Nil(t, err, "could not compile http request")
|
require.Nil(t, err, "could not compile http request")
|
||||||
|
|
||||||
generator := request.newGenerator()
|
generator := request.newGenerator()
|
||||||
req, err := generator.Make("https://example.com", map[string]interface{}{}, "")
|
req, err := generator.Make("https://example.com", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
authorization := req.request.Header.Get("Authorization")
|
authorization := req.request.Header.Get("Authorization")
|
||||||
require.Equal(t, "Basic YWRtaW46YWRtaW4=", authorization, "could not get correct authorization headers from raw")
|
require.Equal(t, "Basic YWRtaW46YWRtaW4=", authorization, "could not get correct authorization headers from raw")
|
||||||
|
|
||||||
req, err = generator.Make("https://example.com", map[string]interface{}{}, "")
|
req, err = generator.Make("https://example.com", map[string]interface{}{})
|
||||||
require.Nil(t, err, "could not make http request")
|
require.Nil(t, err, "could not make http request")
|
||||||
authorization = req.request.Header.Get("Authorization")
|
authorization = req.request.Header.Get("Authorization")
|
||||||
require.Equal(t, "Basic YWRtaW46Z3Vlc3Q=", authorization, "could not get correct authorization headers from raw")
|
require.Equal(t, "Basic YWRtaW46Z3Vlc3Q=", authorization, "could not get correct authorization headers from raw")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMakeRequestFromModelUniqueInteractsh(t *testing.T) {
|
||||||
|
|
||||||
|
options := testutils.DefaultOptions
|
||||||
|
|
||||||
|
testutils.Init(options)
|
||||||
|
templateID := "testing-unique-interactsh"
|
||||||
|
request := &Request{
|
||||||
|
ID: templateID,
|
||||||
|
Name: "testing",
|
||||||
|
Path: []string{"{{BaseURL}}/?u=http://{{interactsh-url}}/&href=http://{{interactsh-url}}/&action=http://{{interactsh-url}}/&host={{interactsh-url}}"},
|
||||||
|
Method: "GET",
|
||||||
|
}
|
||||||
|
executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
|
||||||
|
ID: templateID,
|
||||||
|
Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
|
||||||
|
})
|
||||||
|
err := request.Compile(executerOpts)
|
||||||
|
require.Nil(t, err, "could not compile http request")
|
||||||
|
|
||||||
|
generator := request.newGenerator()
|
||||||
|
|
||||||
|
generator.options.Interactsh, err = interactsh.New(&interactsh.Options{
|
||||||
|
ServerURL: options.InteractshURL,
|
||||||
|
CacheSize: int64(options.InteractionsCacheSize),
|
||||||
|
Eviction: time.Duration(options.InteractionsEviction) * time.Second,
|
||||||
|
ColldownPeriod: time.Duration(options.InteractionsCooldownPeriod) * time.Second,
|
||||||
|
PollDuration: time.Duration(options.InteractionsPollDuration) * time.Second,
|
||||||
|
})
|
||||||
|
require.Nil(t, err, "could not create interactsh client")
|
||||||
|
|
||||||
|
got, err := generator.Make("https://example.com", map[string]interface{}{})
|
||||||
|
require.Nil(t, err, "could not make http request")
|
||||||
|
|
||||||
|
// check if all the interactsh markers are replaced with unique urls
|
||||||
|
require.NotContains(t, got.request.URL.String(), "{{interactsh-url}}", "could not get correct interactsh url")
|
||||||
|
// check the length of returned urls
|
||||||
|
require.Equal(t, len(got.interactshURLs), 4, "could not get correct interactsh url")
|
||||||
|
// check if the interactsh urls are unique
|
||||||
|
require.True(t, areUnique(got.interactshURLs), "interactsh urls are not unique")
|
||||||
|
}
|
||||||
|
|
||||||
|
// areUnique checks if the elements of string slice are unique
|
||||||
|
func areUnique(elements []string) bool {
|
||||||
|
encountered := map[string]bool{}
|
||||||
|
for v := range elements {
|
||||||
|
if encountered[elements[v]] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
encountered[elements[v]] = true
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (request *Request) executeRaceRequest(reqURL string, previous output.Intern
|
||||||
// Requests within race condition should be dumped once and the output prefilled to allow DSL language to work
|
// Requests within race condition should be dumped once and the output prefilled to allow DSL language to work
|
||||||
// This will introduce a delay and will populate in hacky way the field "request" of outputEvent
|
// This will introduce a delay and will populate in hacky way the field "request" of outputEvent
|
||||||
generator := request.newGenerator()
|
generator := request.newGenerator()
|
||||||
requestForDump, err := generator.Make(reqURL, nil, "")
|
requestForDump, err := generator.Make(reqURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ func (request *Request) executeRaceRequest(reqURL string, previous output.Intern
|
||||||
// Pre-Generate requests
|
// Pre-Generate requests
|
||||||
for i := 0; i < request.RaceNumberRequests; i++ {
|
for i := 0; i < request.RaceNumberRequests; i++ {
|
||||||
generator := request.newGenerator()
|
generator := request.newGenerator()
|
||||||
generatedRequest, err := generator.Make(reqURL, nil, "")
|
generatedRequest, err := generator.Make(reqURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ func (request *Request) executeParallelHTTP(reqURL string, dynamicValues output.
|
||||||
var requestErr error
|
var requestErr error
|
||||||
mutex := &sync.Mutex{}
|
mutex := &sync.Mutex{}
|
||||||
for {
|
for {
|
||||||
generatedHttpRequest, err := generator.Make(reqURL, dynamicValues, "")
|
generatedHttpRequest, err := generator.Make(reqURL, dynamicValues)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ func (request *Request) executeTurboHTTP(reqURL string, dynamicValues, previous
|
||||||
var requestErr error
|
var requestErr error
|
||||||
mutex := &sync.Mutex{}
|
mutex := &sync.Mutex{}
|
||||||
for {
|
for {
|
||||||
generatedHttpRequest, err := generator.Make(reqURL, dynamicValues, "")
|
generatedHttpRequest, err := generator.Make(reqURL, dynamicValues)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -221,11 +221,7 @@ func (request *Request) ExecuteWithResults(reqURL string, dynamicValues, previou
|
||||||
for {
|
for {
|
||||||
hasInteractMarkers := interactsh.HasMatchers(request.CompiledOperators)
|
hasInteractMarkers := interactsh.HasMatchers(request.CompiledOperators)
|
||||||
|
|
||||||
var interactURL string
|
generatedHttpRequest, err := generator.Make(reqURL, dynamicValues)
|
||||||
if request.options.Interactsh != nil && hasInteractMarkers {
|
|
||||||
interactURL = request.options.Interactsh.URL()
|
|
||||||
}
|
|
||||||
generatedHttpRequest, err := generator.Make(reqURL, dynamicValues, interactURL)
|
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -251,7 +247,7 @@ func (request *Request) ExecuteWithResults(reqURL string, dynamicValues, previou
|
||||||
dynamicValues = generators.MergeMaps(dynamicValues, event.OperatorsResult.DynamicValues)
|
dynamicValues = generators.MergeMaps(dynamicValues, event.OperatorsResult.DynamicValues)
|
||||||
}
|
}
|
||||||
if hasInteractMarkers && request.options.Interactsh != nil {
|
if hasInteractMarkers && request.options.Interactsh != nil {
|
||||||
request.options.Interactsh.RequestEvent(interactURL, &interactsh.RequestData{
|
request.options.Interactsh.RequestEvent(generatedHttpRequest.interactshURLs, &interactsh.RequestData{
|
||||||
MakeResultFunc: request.MakeResultEvent,
|
MakeResultFunc: request.MakeResultEvent,
|
||||||
Event: event,
|
Event: event,
|
||||||
Operators: request.CompiledOperators,
|
Operators: request.CompiledOperators,
|
||||||
|
|
|
@ -16,6 +16,7 @@ type requestGenerator struct {
|
||||||
request *Request
|
request *Request
|
||||||
options *protocols.ExecuterOptions
|
options *protocols.ExecuterOptions
|
||||||
payloadIterator *generators.Iterator
|
payloadIterator *generators.Iterator
|
||||||
|
interactshURLs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// newGenerator creates a new request generator instance
|
// newGenerator creates a new request generator instance
|
||||||
|
|
|
@ -126,11 +126,7 @@ func (request *Request) executeRequestWithPayloads(actualAddress, address, input
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_ = conn.SetReadDeadline(time.Now().Add(time.Duration(request.options.Options.Timeout) * time.Second))
|
_ = conn.SetReadDeadline(time.Now().Add(time.Duration(request.options.Options.Timeout) * time.Second))
|
||||||
|
|
||||||
hasInteractMarkers := interactsh.HasMatchers(request.CompiledOperators)
|
var interactshURLs []string
|
||||||
var interactURL string
|
|
||||||
if request.options.Interactsh != nil && hasInteractMarkers {
|
|
||||||
interactURL = request.options.Interactsh.URL()
|
|
||||||
}
|
|
||||||
|
|
||||||
responseBuilder := &strings.Builder{}
|
responseBuilder := &strings.Builder{}
|
||||||
reqBuilder := &strings.Builder{}
|
reqBuilder := &strings.Builder{}
|
||||||
|
@ -143,9 +139,7 @@ func (request *Request) executeRequestWithPayloads(actualAddress, address, input
|
||||||
case "hex":
|
case "hex":
|
||||||
data, err = hex.DecodeString(input.Data)
|
data, err = hex.DecodeString(input.Data)
|
||||||
default:
|
default:
|
||||||
if interactURL != "" {
|
input.Data, interactshURLs = request.options.Interactsh.ReplaceMarkers(input.Data, []string{})
|
||||||
input.Data = request.options.Interactsh.ReplaceMarkers(input.Data, interactURL)
|
|
||||||
}
|
|
||||||
data = []byte(input.Data)
|
data = []byte(input.Data)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -267,14 +261,14 @@ func (request *Request) executeRequestWithPayloads(actualAddress, address, input
|
||||||
}
|
}
|
||||||
|
|
||||||
var event *output.InternalWrappedEvent
|
var event *output.InternalWrappedEvent
|
||||||
if interactURL == "" {
|
if len(interactshURLs) == 0 {
|
||||||
event = eventcreator.CreateEventWithAdditionalOptions(request, outputEvent, request.options.Options.Debug || request.options.Options.DebugResponse, func(wrappedEvent *output.InternalWrappedEvent) {
|
event = eventcreator.CreateEventWithAdditionalOptions(request, outputEvent, request.options.Options.Debug || request.options.Options.DebugResponse, func(wrappedEvent *output.InternalWrappedEvent) {
|
||||||
wrappedEvent.OperatorsResult.PayloadValues = payloads
|
wrappedEvent.OperatorsResult.PayloadValues = payloads
|
||||||
})
|
})
|
||||||
callback(event)
|
callback(event)
|
||||||
} else if request.options.Interactsh != nil {
|
} else if request.options.Interactsh != nil {
|
||||||
event = &output.InternalWrappedEvent{InternalEvent: outputEvent}
|
event = &output.InternalWrappedEvent{InternalEvent: outputEvent}
|
||||||
request.options.Interactsh.RequestEvent(interactURL, &interactsh.RequestData{
|
request.options.Interactsh.RequestEvent(interactshURLs, &interactsh.RequestData{
|
||||||
MakeResultFunc: request.MakeResultEvent,
|
MakeResultFunc: request.MakeResultEvent,
|
||||||
Event: event,
|
Event: event,
|
||||||
Operators: request.CompiledOperators,
|
Operators: request.CompiledOperators,
|
||||||
|
|
|
@ -58,6 +58,11 @@ var DefaultOptions = &types.Options{
|
||||||
Templates: []string{},
|
Templates: []string{},
|
||||||
ExcludedTemplates: []string{},
|
ExcludedTemplates: []string{},
|
||||||
CustomHeaders: []string{},
|
CustomHeaders: []string{},
|
||||||
|
InteractshURL: "https://interactsh.com",
|
||||||
|
InteractionsCacheSize: 5000,
|
||||||
|
InteractionsEviction: 60,
|
||||||
|
InteractionsCooldownPeriod: 5,
|
||||||
|
InteractionsPollDuration: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TemplateInfo contains info for a mock executed template.
|
// TemplateInfo contains info for a mock executed template.
|
||||||
|
|
|
@ -109,9 +109,9 @@ type Options struct {
|
||||||
// Eviction is the number of seconds after which to automatically discard
|
// Eviction is the number of seconds after which to automatically discard
|
||||||
// interaction requests.
|
// interaction requests.
|
||||||
InteractionsEviction int
|
InteractionsEviction int
|
||||||
// InteractionsColldownPeriod is additional seconds to wait for interactions after closing
|
// InteractionsCooldownPeriod is additional seconds to wait for interactions after closing
|
||||||
// of the poller.
|
// of the poller.
|
||||||
InteractionsColldownPeriod int
|
InteractionsCooldownPeriod int
|
||||||
// OfflineHTTP is a flag that specific offline processing of http response
|
// OfflineHTTP is a flag that specific offline processing of http response
|
||||||
// using same matchers/extractors from http protocol without the need
|
// using same matchers/extractors from http protocol without the need
|
||||||
// to send a new request, reading responses from a file.
|
// to send a new request, reading responses from a file.
|
||||||
|
|
Loading…
Reference in New Issue