2020-12-26 02:09:16 +05:30
|
|
|
package http
|
|
|
|
|
|
|
|
|
|
import (
|
2021-10-14 22:26:01 +05:30
|
|
|
"bufio"
|
2020-12-28 01:33:50 +05:30
|
|
|
"context"
|
2021-08-13 20:08:18 +05:30
|
|
|
"fmt"
|
2020-12-28 01:33:50 +05:30
|
|
|
"strings"
|
|
|
|
|
"time"
|
2020-12-26 22:57:40 +05:30
|
|
|
|
2021-04-13 13:27:36 +07:00
|
|
|
"github.com/corpix/uarand"
|
2021-02-24 12:07:16 +05:30
|
|
|
"github.com/pkg/errors"
|
2021-09-07 17:31:46 +03:00
|
|
|
|
2022-08-25 15:37:03 +05:30
|
|
|
"github.com/projectdiscovery/gologger"
|
2022-12-09 19:47:03 +01:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
|
2021-02-24 12:07:16 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions"
|
2020-12-26 22:57:40 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
2022-08-25 15:37:03 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump"
|
2020-12-28 01:33:50 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/race"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/raw"
|
2022-11-01 20:28:50 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/utils"
|
2023-05-02 23:49:56 +05:30
|
|
|
protocolutils "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
|
2021-10-18 14:25:25 +02:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
2020-12-28 20:02:26 +05:30
|
|
|
"github.com/projectdiscovery/rawhttp"
|
2020-12-28 01:33:50 +05:30
|
|
|
"github.com/projectdiscovery/retryablehttp-go"
|
2023-02-01 17:23:28 +05:30
|
|
|
errorutil "github.com/projectdiscovery/utils/errors"
|
2023-01-24 22:04:52 +05:30
|
|
|
readerutil "github.com/projectdiscovery/utils/reader"
|
2022-11-06 21:24:23 +01:00
|
|
|
stringsutil "github.com/projectdiscovery/utils/strings"
|
2023-01-05 16:41:59 +05:30
|
|
|
urlutil "github.com/projectdiscovery/utils/url"
|
2020-12-26 02:09:16 +05:30
|
|
|
)
|
|
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// ErrEvalExpression
|
2023-05-01 12:15:35 +05:30
|
|
|
var (
|
|
|
|
|
ErrEvalExpression = errorutil.NewWithTag("expr", "could not evaluate helper expressions")
|
|
|
|
|
ErrUnresolvedVars = errorutil.NewWithFmt("unresolved variables `%v` found in request")
|
|
|
|
|
)
|
2022-05-12 05:10:14 -05:00
|
|
|
|
2021-09-07 17:31:46 +03:00
|
|
|
// generatedRequest is a single generated request wrapped for a template request
|
2020-12-28 01:33:50 +05:30
|
|
|
type generatedRequest struct {
|
2022-10-10 08:10:07 +02:00
|
|
|
original *Request
|
|
|
|
|
rawRequest *raw.Request
|
|
|
|
|
meta map[string]interface{}
|
|
|
|
|
pipelinedClient *rawhttp.PipelineClient
|
|
|
|
|
request *retryablehttp.Request
|
|
|
|
|
dynamicValues map[string]interface{}
|
|
|
|
|
interactshURLs []string
|
|
|
|
|
customCancelFunction context.CancelFunc
|
2020-12-28 01:33:50 +05:30
|
|
|
}
|
|
|
|
|
|
2021-10-18 19:48:47 +05:30
|
|
|
func (g *generatedRequest) URL() string {
|
|
|
|
|
if g.request != nil {
|
|
|
|
|
return g.request.URL.String()
|
|
|
|
|
}
|
|
|
|
|
if g.rawRequest != nil {
|
|
|
|
|
return g.rawRequest.FullURL
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// Total returns the total number of requests for the generator
|
|
|
|
|
func (r *requestGenerator) Total() int {
|
|
|
|
|
if r.payloadIterator != nil {
|
|
|
|
|
return len(r.request.Raw) * r.payloadIterator.Remaining()
|
|
|
|
|
}
|
|
|
|
|
return len(r.request.Path)
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-26 22:57:40 +05:30
|
|
|
// Make creates a http request for the provided input.
|
|
|
|
|
// It returns io.EOF as error when all the requests have been exhausted.
|
2023-02-01 17:23:28 +05:30
|
|
|
func (r *requestGenerator) Make(ctx context.Context, input *contextargs.Context, reqData string, payloads, dynamicValues map[string]interface{}) (*generatedRequest, error) {
|
|
|
|
|
// value of `reqData` depends on the type of request specified in template
|
|
|
|
|
// 1. If request is raw request = reqData contains raw request (i.e http request dump)
|
|
|
|
|
// 2. If request is Normal ( simply put not a raw request) (Ex: with placeholders `path`) = reqData contains relative path
|
2021-10-14 22:26:01 +05:30
|
|
|
if r.request.SelfContained {
|
2023-02-01 17:23:28 +05:30
|
|
|
return r.makeSelfContainedRequest(ctx, reqData, payloads, dynamicValues)
|
2020-12-26 22:57:40 +05:30
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
isRawRequest := len(r.request.Raw) > 0
|
|
|
|
|
// replace interactsh variables with actual interactsh urls
|
2021-11-16 20:02:39 +05:30
|
|
|
if r.options.Interactsh != nil {
|
2023-02-07 09:32:10 +01:00
|
|
|
reqData, r.interactshURLs = r.options.Interactsh.Replace(reqData, []string{})
|
2021-11-16 20:02:39 +05:30
|
|
|
for payloadName, payloadValue := range payloads {
|
2023-02-07 09:32:10 +01:00
|
|
|
payloads[payloadName], r.interactshURLs = r.options.Interactsh.Replace(types.ToString(payloadValue), r.interactshURLs)
|
2021-11-16 20:02:39 +05:30
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for payloadName, payloadValue := range payloads {
|
|
|
|
|
payloads[payloadName] = types.ToString(payloadValue)
|
|
|
|
|
}
|
2021-10-18 14:25:25 +02:00
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
|
|
|
|
|
// Parse target url
|
2023-01-24 22:04:52 +05:30
|
|
|
parsed, err := urlutil.Parse(input.MetaInput.Input)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2023-01-24 22:04:52 +05:30
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// Non-Raw Requests ex `{{BaseURL}}/somepath` may or maynot have slash after variable and the same is the case for
|
|
|
|
|
// target url to avoid inconsistencies extra slash if exists has to removed from default variables
|
|
|
|
|
hasTrailingSlash := false
|
2023-01-24 22:04:52 +05:30
|
|
|
if !isRawRequest {
|
2023-02-01 17:23:28 +05:30
|
|
|
// if path contains port ex: {{BaseURL}}:8080 use port specified in reqData
|
|
|
|
|
parsed, reqData = utils.UpdateURLPortFromPayload(parsed, reqData)
|
|
|
|
|
hasTrailingSlash = utils.HasTrailingSlash(reqData)
|
2023-01-24 22:04:52 +05:30
|
|
|
}
|
2021-10-20 20:26:40 +05:30
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// defaultreqvars are vars generated from request/input ex: {{baseURL}}, {{Host}} etc
|
|
|
|
|
// contextargs generate extra vars that may/may not be available always (ex: "ip")
|
2023-05-02 23:49:56 +05:30
|
|
|
defaultReqVars := protocolutils.GenerateVariables(parsed, hasTrailingSlash, contextargs.GenerateVariables(input))
|
2023-02-01 17:23:28 +05:30
|
|
|
// optionvars are vars passed from CLI or env variables
|
|
|
|
|
optionVars := generators.BuildPayloadFromOptions(r.request.options.Options)
|
|
|
|
|
|
2023-04-12 01:50:58 +05:30
|
|
|
variablesMap, interactURLs := r.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(defaultReqVars, optionVars), r.options.Interactsh)
|
|
|
|
|
if len(interactURLs) > 0 {
|
|
|
|
|
r.interactshURLs = append(r.interactshURLs, interactURLs...)
|
|
|
|
|
}
|
|
|
|
|
// allVars contains all variables from all sources
|
2023-05-25 18:32:35 +02:00
|
|
|
allVars := generators.MergeMaps(dynamicValues, defaultReqVars, optionVars, variablesMap, r.options.Constants)
|
2023-04-12 01:50:58 +05:30
|
|
|
|
|
|
|
|
// Evaluate payload variables
|
|
|
|
|
// eg: payload variables can be username: jon.doe@{{Hostname}}
|
|
|
|
|
for payloadName, payloadValue := range payloads {
|
|
|
|
|
payloads[payloadName], err = expressions.Evaluate(types.ToString(payloadValue), allVars)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, ErrEvalExpression.Wrap(err).WithTag("http")
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
// finalVars contains allVars and any generator/fuzzing specific payloads
|
2023-03-04 04:57:27 +05:30
|
|
|
// payloads used in generator should be given the most preference
|
2023-02-01 17:23:28 +05:30
|
|
|
finalVars := generators.MergeMaps(allVars, payloads)
|
2021-10-20 20:29:28 +05:30
|
|
|
|
2022-11-01 20:28:50 +05:30
|
|
|
if vardump.EnableVarDump {
|
2023-02-01 17:23:28 +05:30
|
|
|
gologger.Debug().Msgf("Final Protocol request variables: \n%s\n", vardump.DumpVariables(finalVars))
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-20 22:26:04 +05:30
|
|
|
// Note: If possible any changes to current logic (i.e evaluate -> then parse URL)
|
|
|
|
|
// should be avoided since it is dependent on `urlutil` core logic
|
|
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// Evaluate (replace) variable with final values
|
|
|
|
|
reqData, err = expressions.Evaluate(reqData, finalVars)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, ErrEvalExpression.Wrap(err).WithTag("http")
|
2022-08-25 15:37:03 +05:30
|
|
|
}
|
2021-08-09 00:22:09 +02:00
|
|
|
|
2021-02-04 17:56:53 +05:30
|
|
|
if isRawRequest {
|
2023-02-01 17:23:28 +05:30
|
|
|
return r.generateRawRequest(ctx, reqData, parsed, finalVars, payloads)
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
|
|
|
|
|
reqURL, err := urlutil.ParseURL(reqData, true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errorutil.NewWithTag("http", "failed to parse url %v while creating http request", reqData)
|
|
|
|
|
}
|
|
|
|
|
// while merging parameters first preference is given to target params
|
|
|
|
|
finalparams := parsed.Params
|
|
|
|
|
finalparams.Merge(reqURL.Params)
|
|
|
|
|
reqURL.Params = finalparams
|
2023-02-10 18:28:28 +05:30
|
|
|
return r.generateHttpRequest(ctx, reqURL, finalVars, payloads)
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// selfContained templates do not need/use target data and all values i.e {{Hostname}} , {{BaseURL}} etc are already available
|
|
|
|
|
// in template . makeSelfContainedRequest parses and creates variables map and then creates corresponding http request or raw request
|
2022-07-21 21:29:34 +05:30
|
|
|
func (r *requestGenerator) makeSelfContainedRequest(ctx context.Context, data string, payloads, dynamicValues map[string]interface{}) (*generatedRequest, error) {
|
2021-10-20 20:17:00 +05:30
|
|
|
isRawRequest := r.request.isRaw()
|
2021-10-14 22:26:01 +05:30
|
|
|
|
2023-05-01 12:15:35 +05:30
|
|
|
values := generators.MergeMaps(
|
|
|
|
|
generators.BuildPayloadFromOptions(r.request.options.Options),
|
|
|
|
|
dynamicValues,
|
|
|
|
|
payloads, // payloads should override other variables in case of duplicate vars
|
|
|
|
|
)
|
|
|
|
|
// adds all variables from `variables` section in template
|
|
|
|
|
variablesMap := r.request.options.Variables.Evaluate(values)
|
|
|
|
|
values = generators.MergeMaps(variablesMap, values)
|
|
|
|
|
|
|
|
|
|
signerVars := GetDefaultSignerVars(r.request.Signature.Value)
|
|
|
|
|
// this will ensure that default signer variables are overwritten by other variables
|
2023-05-25 18:32:35 +02:00
|
|
|
values = generators.MergeMaps(signerVars, values, r.options.Constants)
|
2023-05-01 12:15:35 +05:30
|
|
|
|
|
|
|
|
// priority of variables is as follows (from low to high) for self contained templates
|
2023-05-25 18:32:35 +02:00
|
|
|
// default signer vars < variables < cli vars < payload < dynamic values < constants
|
2023-05-01 12:15:35 +05:30
|
|
|
|
|
|
|
|
// evaluate request
|
|
|
|
|
data, err := expressions.Evaluate(data, values)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, ErrEvalExpression.Wrap(err).WithTag("self-contained")
|
|
|
|
|
}
|
2021-10-20 20:17:00 +05:30
|
|
|
// If the request is a raw request, get the URL from the request
|
|
|
|
|
// header and use it to make the request.
|
2021-10-14 22:26:01 +05:30
|
|
|
if isRawRequest {
|
|
|
|
|
// Get the hostname from the URL section to build the request.
|
|
|
|
|
reader := bufio.NewReader(strings.NewReader(data))
|
2022-08-23 12:45:55 +05:30
|
|
|
read_line:
|
2021-10-14 22:26:01 +05:30
|
|
|
s, err := reader.ReadString('\n')
|
|
|
|
|
if err != nil {
|
2021-11-25 15:18:46 +02:00
|
|
|
return nil, fmt.Errorf("could not read request: %w", err)
|
2021-10-14 22:26:01 +05:30
|
|
|
}
|
2022-08-23 12:45:55 +05:30
|
|
|
// ignore all annotations
|
|
|
|
|
if stringsutil.HasPrefixAny(s, "@") {
|
|
|
|
|
goto read_line
|
|
|
|
|
}
|
2021-10-14 22:26:01 +05:30
|
|
|
|
|
|
|
|
parts := strings.Split(s, " ")
|
|
|
|
|
if len(parts) < 3 {
|
|
|
|
|
return nil, fmt.Errorf("malformed request supplied")
|
|
|
|
|
}
|
2021-11-12 19:29:45 +01:00
|
|
|
|
2023-05-01 12:15:35 +05:30
|
|
|
if err := expressions.ContainsUnresolvedVariables(parts[1]); err != nil {
|
|
|
|
|
return nil, ErrUnresolvedVars.Msgf(parts[1])
|
2021-11-12 19:29:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-24 22:04:52 +05:30
|
|
|
parsed, err := urlutil.ParseURL(parts[1], true)
|
2021-10-14 22:26:01 +05:30
|
|
|
if err != nil {
|
2021-11-25 15:18:46 +02:00
|
|
|
return nil, fmt.Errorf("could not parse request URL: %w", err)
|
2021-10-14 22:26:01 +05:30
|
|
|
}
|
2022-05-23 15:12:58 +05:30
|
|
|
values = generators.MergeMaps(
|
2023-05-02 23:49:56 +05:30
|
|
|
generators.MergeMaps(dynamicValues, protocolutils.GenerateVariables(parsed, false, nil)),
|
2022-05-23 15:12:58 +05:30
|
|
|
values,
|
2021-10-18 19:48:47 +05:30
|
|
|
)
|
2023-02-01 17:23:28 +05:30
|
|
|
// Evaluate (replace) variable with final values
|
|
|
|
|
data, err = expressions.Evaluate(data, values)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, ErrEvalExpression.Wrap(err).WithTag("self-contained", "raw")
|
|
|
|
|
}
|
|
|
|
|
return r.generateRawRequest(ctx, data, parsed, values, payloads)
|
2021-10-14 22:26:01 +05:30
|
|
|
}
|
2023-05-01 12:15:35 +05:30
|
|
|
if err := expressions.ContainsUnresolvedVariables(data); err != nil {
|
|
|
|
|
// early exit: if there are any unresolved variables in `path` after evaluation
|
|
|
|
|
// then return early since this will definitely fail
|
|
|
|
|
return nil, ErrUnresolvedVars.Msgf(data)
|
2021-05-03 14:31:44 +05:30
|
|
|
}
|
2023-05-01 12:15:35 +05:30
|
|
|
|
2023-02-10 18:28:28 +05:30
|
|
|
urlx, err := urlutil.ParseURL(data, true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errorutil.NewWithErr(err).Msgf("failed to parse %v in self contained request", data).WithTag("self-contained")
|
|
|
|
|
}
|
|
|
|
|
return r.generateHttpRequest(ctx, urlx, values, payloads)
|
2023-02-01 17:23:28 +05:30
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// generateHttpRequest generates http request from request data from template and variables
|
|
|
|
|
// finalVars = contains all variables including generator and protocol specific variables
|
|
|
|
|
// generatorValues = contains variables used in fuzzing or other generator specific values
|
2023-02-10 18:28:28 +05:30
|
|
|
func (r *requestGenerator) generateHttpRequest(ctx context.Context, urlx *urlutil.URL, finalVars, generatorValues map[string]interface{}) (*generatedRequest, error) {
|
2023-02-01 17:23:28 +05:30
|
|
|
method, err := expressions.Evaluate(r.request.Method.String(), finalVars)
|
2021-08-16 00:14:47 +05:30
|
|
|
if err != nil {
|
2023-02-01 17:23:28 +05:30
|
|
|
return nil, ErrEvalExpression.Wrap(err).Msgf("failed to evaluate while generating http request")
|
2021-08-16 00:14:47 +05:30
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
// Build a request on the specified URL
|
2023-02-10 18:28:28 +05:30
|
|
|
req, err := retryablehttp.NewRequestFromURLWithContext(ctx, method, urlx, nil)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
request, err := r.fillRequest(req, finalVars)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalVars, interactshURLs: r.interactshURLs}, nil
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2023-02-01 17:23:28 +05:30
|
|
|
// generateRawRequest generates Raw Request from from request data from template and variables
|
|
|
|
|
// finalVars = contains all variables including generator and protocol specific variables
|
|
|
|
|
// generatorValues = contains variables used in fuzzing or other generator specific values
|
|
|
|
|
func (r *requestGenerator) generateRawRequest(ctx context.Context, rawRequest string, baseURL *urlutil.URL, finalVars, generatorValues map[string]interface{}) (*generatedRequest, error) {
|
2023-05-01 12:15:35 +05:30
|
|
|
|
|
|
|
|
var rawRequestData *raw.Request
|
|
|
|
|
var err error
|
|
|
|
|
if r.request.SelfContained {
|
|
|
|
|
// in self contained requests baseURL is extracted from raw request itself
|
|
|
|
|
rawRequestData, err = raw.ParseRawRequest(rawRequest, r.request.Unsafe)
|
|
|
|
|
} else {
|
|
|
|
|
rawRequestData, err = raw.Parse(rawRequest, baseURL, r.request.Unsafe)
|
|
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
2023-05-01 12:15:35 +05:30
|
|
|
return nil, errorutil.NewWithErr(err).Msgf("failed to parse raw request")
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2021-02-04 04:48:45 +05:30
|
|
|
// Unsafe option uses rawhttp library
|
2020-12-28 01:33:50 +05:30
|
|
|
if r.request.Unsafe {
|
2021-11-08 19:33:54 +01:00
|
|
|
if len(r.options.Options.CustomHeaders) > 0 {
|
|
|
|
|
_ = rawRequestData.TryFillCustomHeaders(r.options.Options.CustomHeaders)
|
|
|
|
|
}
|
2022-04-20 17:11:14 +02:00
|
|
|
unsafeReq := &generatedRequest{rawRequest: rawRequestData, meta: generatorValues, original: r.request, interactshURLs: r.interactshURLs}
|
2020-12-26 02:09:16 +05:30
|
|
|
return unsafeReq, nil
|
|
|
|
|
}
|
2023-04-19 01:57:53 +05:30
|
|
|
|
2023-02-10 18:28:28 +05:30
|
|
|
urlx, err := urlutil.ParseURL(rawRequestData.FullURL, true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errorutil.NewWithErr(err).Msgf("failed to create request with url %v got %v", rawRequestData.FullURL, err).WithTag("raw")
|
|
|
|
|
}
|
2023-05-01 12:15:35 +05:30
|
|
|
req, err := retryablehttp.NewRequestFromURLWithContext(ctx, rawRequestData.Method, urlx, rawRequestData.Data)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2023-04-19 01:57:53 +05:30
|
|
|
// override the body with a new one that will be used to read the request body in parallel threads
|
|
|
|
|
// for race condition testing
|
|
|
|
|
if r.request.Threads > 0 && r.request.Race {
|
|
|
|
|
req.Body = race.NewOpenGateWithTimeout(req.Body, time.Duration(2)*time.Second)
|
|
|
|
|
}
|
2020-12-28 01:33:50 +05:30
|
|
|
for key, value := range rawRequestData.Headers {
|
2021-02-22 18:59:03 +05:30
|
|
|
if key == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
req.Header[key] = []string{value}
|
2021-05-02 20:10:49 +02:00
|
|
|
if key == "Host" {
|
|
|
|
|
req.Host = value
|
|
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
request, err := r.fillRequest(req, finalVars)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-02-20 00:35:39 +01:00
|
|
|
|
2022-10-10 08:10:07 +02:00
|
|
|
generatedRequest := &generatedRequest{
|
|
|
|
|
request: request,
|
|
|
|
|
meta: generatorValues,
|
|
|
|
|
original: r.request,
|
2023-02-01 17:23:28 +05:30
|
|
|
dynamicValues: finalVars,
|
2022-10-10 08:10:07 +02:00
|
|
|
interactshURLs: r.interactshURLs,
|
2022-05-12 13:13:56 +02:00
|
|
|
}
|
2022-04-04 09:32:41 +02:00
|
|
|
|
2023-02-07 09:32:10 +01:00
|
|
|
if reqWithOverrides, hasAnnotations := r.request.parseAnnotations(rawRequest, req); hasAnnotations {
|
|
|
|
|
generatedRequest.request = reqWithOverrides.request
|
|
|
|
|
generatedRequest.customCancelFunction = reqWithOverrides.cancelFunc
|
|
|
|
|
generatedRequest.interactshURLs = append(generatedRequest.interactshURLs, reqWithOverrides.interactshURLs...)
|
2022-10-10 08:10:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return generatedRequest, nil
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-28 01:33:50 +05:30
|
|
|
// fillRequest fills various headers in the request with values
|
2023-01-24 22:04:52 +05:30
|
|
|
func (r *requestGenerator) fillRequest(req *retryablehttp.Request, values map[string]interface{}) (*retryablehttp.Request, error) {
|
2020-12-26 02:09:16 +05:30
|
|
|
// Set the header values requested
|
2020-12-28 01:33:50 +05:30
|
|
|
for header, value := range r.request.Headers {
|
2021-11-16 20:02:39 +05:30
|
|
|
if r.options.Interactsh != nil {
|
2023-02-07 09:32:10 +01:00
|
|
|
value, r.interactshURLs = r.options.Interactsh.Replace(value, r.interactshURLs)
|
2021-11-16 20:02:39 +05:30
|
|
|
}
|
2021-08-16 00:14:47 +05:30
|
|
|
value, err := expressions.Evaluate(value, values)
|
|
|
|
|
if err != nil {
|
2023-02-01 17:23:28 +05:30
|
|
|
return nil, ErrEvalExpression.Wrap(err).Msgf("failed to evaluate while adding headers to request")
|
2021-08-16 00:14:47 +05:30
|
|
|
}
|
|
|
|
|
req.Header[header] = []string{value}
|
2021-05-02 20:10:49 +02:00
|
|
|
if header == "Host" {
|
2021-08-16 00:14:47 +05:30
|
|
|
req.Host = value
|
2021-05-02 20:10:49 +02:00
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In case of multiple threads the underlying connection should remain open to allow reuse
|
2020-12-28 01:33:50 +05:30
|
|
|
if r.request.Threads <= 0 && req.Header.Get("Connection") == "" {
|
2020-12-26 02:09:16 +05:30
|
|
|
req.Close = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if the user requested a request body
|
2020-12-28 01:33:50 +05:30
|
|
|
if r.request.Body != "" {
|
2021-11-16 20:02:39 +05:30
|
|
|
body := r.request.Body
|
|
|
|
|
if r.options.Interactsh != nil {
|
2023-02-07 09:32:10 +01:00
|
|
|
body, r.interactshURLs = r.options.Interactsh.Replace(r.request.Body, r.interactshURLs)
|
2021-11-16 20:02:39 +05:30
|
|
|
}
|
2021-08-16 00:14:47 +05:30
|
|
|
body, err := expressions.Evaluate(body, values)
|
|
|
|
|
if err != nil {
|
2023-02-01 17:23:28 +05:30
|
|
|
return nil, ErrEvalExpression.Wrap(err)
|
2021-08-16 00:14:47 +05:30
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
bodyReader, err := readerutil.NewReusableReadCloser([]byte(body))
|
2023-01-24 22:04:52 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "failed to create reusable reader for request body")
|
|
|
|
|
}
|
2023-02-01 17:23:28 +05:30
|
|
|
req.Body = bodyReader
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2021-11-27 17:10:27 -06:00
|
|
|
if !r.request.Unsafe {
|
2023-02-01 17:23:28 +05:30
|
|
|
utils.SetHeader(req, "User-Agent", uarand.GetRandom())
|
2021-11-27 17:10:27 -06:00
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
|
2021-09-07 17:31:46 +03:00
|
|
|
// Only set these headers on non-raw requests
|
2021-11-27 17:10:27 -06:00
|
|
|
if len(r.request.Raw) == 0 && !r.request.Unsafe {
|
2023-02-01 17:23:28 +05:30
|
|
|
utils.SetHeader(req, "Accept", "*/*")
|
|
|
|
|
utils.SetHeader(req, "Accept-Language", "en")
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2022-01-18 04:13:59 +05:30
|
|
|
|
|
|
|
|
if !LeaveDefaultPorts {
|
|
|
|
|
switch {
|
|
|
|
|
case req.URL.Scheme == "http" && strings.HasSuffix(req.Host, ":80"):
|
|
|
|
|
req.Host = strings.TrimSuffix(req.Host, ":80")
|
|
|
|
|
case req.URL.Scheme == "https" && strings.HasSuffix(req.Host, ":443"):
|
|
|
|
|
req.Host = strings.TrimSuffix(req.Host, ":443")
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-05 11:43:56 +02:00
|
|
|
|
|
|
|
|
if r.request.DigestAuthUsername != "" {
|
2023-01-24 22:04:52 +05:30
|
|
|
req.Auth = &retryablehttp.Auth{
|
2022-04-05 11:43:56 +02:00
|
|
|
Type: retryablehttp.DigestAuth,
|
|
|
|
|
Username: r.request.DigestAuthUsername,
|
|
|
|
|
Password: r.request.DigestAuthPassword,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-24 22:04:52 +05:30
|
|
|
return req, nil
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|