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
|
|
|
"io"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"net"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
2021-08-30 13:35:11 +05:30
|
|
|
"path"
|
2020-12-26 02:09:16 +05:30
|
|
|
"regexp"
|
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
|
|
|
|
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"
|
2021-11-12 19:29:45 +01:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
|
2022-01-14 12:00:59 +01:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/dns"
|
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"
|
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"
|
2020-12-26 02:09:16 +05:30
|
|
|
)
|
|
|
|
|
|
2020-12-28 01:33:50 +05:30
|
|
|
var (
|
2021-02-24 12:07:16 +05:30
|
|
|
urlWithPortRegex = regexp.MustCompile(`{{BaseURL}}:(\d+)`)
|
2020-12-28 01:33:50 +05:30
|
|
|
)
|
2020-12-26 14:55:15 +05:30
|
|
|
|
2022-05-12 05:10:14 -05:00
|
|
|
const evaluateHelperExpressionErrorMessage = "could not evaluate helper expressions"
|
|
|
|
|
|
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 {
|
2020-12-28 20:02:26 +05:30
|
|
|
original *Request
|
|
|
|
|
rawRequest *raw.Request
|
|
|
|
|
meta map[string]interface{}
|
|
|
|
|
pipelinedClient *rawhttp.PipelineClient
|
|
|
|
|
request *retryablehttp.Request
|
2021-09-15 18:02:22 +05:30
|
|
|
dynamicValues map[string]interface{}
|
2021-11-04 17:13:47 +05:30
|
|
|
interactshURLs []string
|
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 ""
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
2021-11-24 21:08:08 +05:30
|
|
|
func (r *requestGenerator) Make(baseURL, data string, payloads, dynamicValues map[string]interface{}) (*generatedRequest, error) {
|
2021-10-14 22:26:01 +05:30
|
|
|
if r.request.SelfContained {
|
2021-11-24 21:08:08 +05:30
|
|
|
return r.makeSelfContainedRequest(data, payloads, dynamicValues)
|
2020-12-26 22:57:40 +05:30
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
ctx := context.Background()
|
2021-11-16 20:02:39 +05:30
|
|
|
if r.options.Interactsh != nil {
|
2021-12-22 21:42:21 +05:30
|
|
|
data, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(data, []string{})
|
2021-11-16 20:02:39 +05:30
|
|
|
for payloadName, payloadValue := range payloads {
|
|
|
|
|
payloads[payloadName], r.interactshURLs = r.options.Interactsh.ReplaceMarkers(types.ToString(payloadValue), r.interactshURLs)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for payloadName, payloadValue := range payloads {
|
|
|
|
|
payloads[payloadName] = types.ToString(payloadValue)
|
|
|
|
|
}
|
2021-10-18 14:25:25 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-26 02:09:16 +05:30
|
|
|
parsed, err := url.Parse(baseURL)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-02-05 14:43:11 +05:30
|
|
|
|
|
|
|
|
data, parsed = baseURLWithTemplatePrefs(data, parsed)
|
|
|
|
|
|
2021-02-21 16:31:34 +05:30
|
|
|
isRawRequest := len(r.request.Raw) > 0
|
2021-10-20 20:26:40 +05:30
|
|
|
|
|
|
|
|
// If the request is not a raw request, and the URL input path is suffixed with
|
2021-10-20 20:27:36 +05:30
|
|
|
// a trailing slash, and our Input URL is also suffixed with a trailing slash,
|
2021-10-20 20:26:40 +05:30
|
|
|
// mark trailingSlash bool as true which will be later used during variable generation
|
|
|
|
|
// to generate correct path removed slash which would otherwise generate // invalid sequence.
|
2021-10-20 20:29:28 +05:30
|
|
|
// TODO: Figure out a cleaner way to do this sanitization.
|
2021-10-14 22:26:01 +05:30
|
|
|
trailingSlash := false
|
2021-02-04 17:56:53 +05:30
|
|
|
if !isRawRequest && strings.HasSuffix(parsed.Path, "/") && strings.Contains(data, "{{BaseURL}}/") {
|
2021-08-12 12:10:35 -05:00
|
|
|
trailingSlash = true
|
2021-02-04 17:56:53 +05:30
|
|
|
}
|
2021-10-20 20:29:28 +05:30
|
|
|
|
2021-10-17 11:52:48 +02:00
|
|
|
values := generators.MergeMaps(
|
|
|
|
|
generators.MergeMaps(dynamicValues, generateVariables(parsed, trailingSlash)),
|
|
|
|
|
generators.BuildPayloadFromOptions(r.request.options.Options),
|
|
|
|
|
)
|
2021-08-09 00:22:09 +02:00
|
|
|
|
2021-02-04 04:48:45 +05:30
|
|
|
// If data contains \n it's a raw request, process it like raw. Else
|
2020-12-26 22:57:40 +05:30
|
|
|
// continue with the template based request flow.
|
2021-02-04 17:56:53 +05:30
|
|
|
if isRawRequest {
|
2021-11-04 17:13:47 +05:30
|
|
|
return r.makeHTTPRequestFromRaw(ctx, parsed.String(), data, values, payloads)
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2021-11-04 17:13:47 +05:30
|
|
|
return r.makeHTTPRequestFromModel(ctx, data, values, payloads)
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2021-11-24 21:08:08 +05:30
|
|
|
func (r *requestGenerator) makeSelfContainedRequest(data string, payloads, dynamicValues map[string]interface{}) (*generatedRequest, error) {
|
2021-10-14 22:26:01 +05:30
|
|
|
ctx := context.Background()
|
|
|
|
|
|
2021-10-20 20:17:00 +05:30
|
|
|
isRawRequest := r.request.isRaw()
|
2021-10-14 22:26:01 +05:30
|
|
|
|
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))
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parts := strings.Split(s, " ")
|
|
|
|
|
if len(parts) < 3 {
|
|
|
|
|
return nil, fmt.Errorf("malformed request supplied")
|
|
|
|
|
}
|
2021-11-12 19:29:45 +01:00
|
|
|
|
2022-05-23 15:12:58 +05:30
|
|
|
values := generators.MergeMaps(
|
2022-01-09 13:39:50 +01:00
|
|
|
payloads,
|
|
|
|
|
generators.BuildPayloadFromOptions(r.request.options.Options),
|
|
|
|
|
)
|
|
|
|
|
|
2021-12-18 20:06:51 +01:00
|
|
|
// in case cases (eg requests signing, some variables uses default values if missing)
|
|
|
|
|
if defaultList := GetVariablesDefault(r.request.Signature.Value); defaultList != nil {
|
2022-05-23 15:12:58 +05:30
|
|
|
values = generators.MergeMaps(defaultList, values)
|
2021-12-18 20:06:51 +01:00
|
|
|
}
|
2022-01-09 13:39:50 +01:00
|
|
|
|
2022-05-23 15:12:58 +05:30
|
|
|
parts[1] = replacer.Replace(parts[1], values)
|
2022-01-09 13:39:50 +01:00
|
|
|
if len(dynamicValues) > 0 {
|
|
|
|
|
parts[1] = replacer.Replace(parts[1], dynamicValues)
|
|
|
|
|
}
|
2021-12-18 20:06:51 +01:00
|
|
|
|
|
|
|
|
// the url might contain placeholders with ignore list
|
|
|
|
|
if ignoreList := GetVariablesNamesSkipList(r.request.Signature.Value); ignoreList != nil {
|
|
|
|
|
if err := expressions.ContainsVariablesWithIgnoreList(ignoreList, parts[1]); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
} else { // the url might contain placeholders
|
|
|
|
|
if err := expressions.ContainsUnresolvedVariables(parts[1]); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-11-12 19:29:45 +01:00
|
|
|
}
|
|
|
|
|
|
2021-10-14 22:26:01 +05:30
|
|
|
parsed, err := url.Parse(parts[1])
|
|
|
|
|
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(
|
2021-10-18 19:48:47 +05:30
|
|
|
generators.MergeMaps(dynamicValues, generateVariables(parsed, false)),
|
2022-05-23 15:12:58 +05:30
|
|
|
values,
|
2021-10-18 19:48:47 +05:30
|
|
|
)
|
|
|
|
|
|
2021-11-04 17:13:47 +05:30
|
|
|
return r.makeHTTPRequestFromRaw(ctx, parsed.String(), data, values, payloads)
|
2021-10-14 22:26:01 +05:30
|
|
|
}
|
2021-10-18 19:48:47 +05:30
|
|
|
values := generators.MergeMaps(
|
|
|
|
|
dynamicValues,
|
|
|
|
|
generators.BuildPayloadFromOptions(r.request.options.Options),
|
|
|
|
|
)
|
2021-11-04 17:13:47 +05:30
|
|
|
return r.makeHTTPRequestFromModel(ctx, data, values, payloads)
|
2021-10-14 22:26:01 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-29 18:02:45 +05:30
|
|
|
// Total returns the total number of requests for the generator
|
|
|
|
|
func (r *requestGenerator) Total() int {
|
2020-12-28 20:02:26 +05:30
|
|
|
if r.payloadIterator != nil {
|
2020-12-29 18:02:45 +05:30
|
|
|
return len(r.request.Raw) * r.payloadIterator.Remaining()
|
2020-12-28 20:02:26 +05:30
|
|
|
}
|
2020-12-29 18:02:45 +05:30
|
|
|
return len(r.request.Path)
|
2020-12-28 20:02:26 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-26 22:57:40 +05:30
|
|
|
// baseURLWithTemplatePrefs returns the url for BaseURL keeping
|
2021-02-04 04:48:45 +05:30
|
|
|
// the template port and path preference over the user provided one.
|
2021-02-05 14:43:11 +05:30
|
|
|
func baseURLWithTemplatePrefs(data string, parsed *url.URL) (string, *url.URL) {
|
|
|
|
|
// template port preference over input URL port if template has a port
|
|
|
|
|
matches := urlWithPortRegex.FindAllStringSubmatch(data, -1)
|
|
|
|
|
if len(matches) == 0 {
|
|
|
|
|
return data, parsed
|
|
|
|
|
}
|
|
|
|
|
port := matches[0][1]
|
|
|
|
|
parsed.Host = net.JoinHostPort(parsed.Hostname(), port)
|
|
|
|
|
data = strings.ReplaceAll(data, ":"+port, "")
|
|
|
|
|
if parsed.Path == "" {
|
|
|
|
|
parsed.Path = "/"
|
2020-12-26 22:57:40 +05:30
|
|
|
}
|
2021-02-05 14:43:11 +05:30
|
|
|
return data, parsed
|
2020-12-26 22:57:40 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-26 02:09:16 +05:30
|
|
|
// MakeHTTPRequestFromModel creates a *http.Request from a request template
|
2021-11-04 17:13:47 +05:30
|
|
|
func (r *requestGenerator) makeHTTPRequestFromModel(ctx context.Context, data string, values, generatorValues map[string]interface{}) (*generatedRequest, error) {
|
2021-11-16 20:02:39 +05:30
|
|
|
if r.options.Interactsh != nil {
|
|
|
|
|
data, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(data, r.interactshURLs)
|
|
|
|
|
}
|
2021-08-13 19:40:10 +05:30
|
|
|
|
|
|
|
|
// Combine the template payloads along with base
|
|
|
|
|
// request values.
|
|
|
|
|
finalValues := generators.MergeMaps(generatorValues, values)
|
|
|
|
|
|
2021-09-16 11:36:08 -05:00
|
|
|
// Evaluate the expressions for the request if any.
|
2021-08-13 19:40:10 +05:30
|
|
|
var err error
|
|
|
|
|
data, err = expressions.Evaluate(data, finalValues)
|
|
|
|
|
if err != nil {
|
2022-05-12 05:10:14 -05:00
|
|
|
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
2021-05-03 14:31:44 +05:30
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
|
2021-11-18 07:50:21 -06:00
|
|
|
method, err := expressions.Evaluate(r.request.Method.String(), finalValues)
|
2021-08-16 00:14:47 +05:30
|
|
|
if err != nil {
|
2022-05-12 05:10:14 -05:00
|
|
|
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
2021-08-16 00:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-26 02:09:16 +05:30
|
|
|
// Build a request on the specified URL
|
2021-08-16 00:14:47 +05:30
|
|
|
req, err := http.NewRequestWithContext(ctx, method, data, nil)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-04 17:13:47 +05:30
|
|
|
request, err := r.fillRequest(req, finalValues)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-11-04 17:13:47 +05:30
|
|
|
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues, interactshURLs: r.interactshURLs}, nil
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// makeHTTPRequestFromRaw creates a *http.Request from a raw request
|
2021-11-04 17:13:47 +05:30
|
|
|
func (r *requestGenerator) makeHTTPRequestFromRaw(ctx context.Context, baseURL, data string, values, payloads map[string]interface{}) (*generatedRequest, error) {
|
2021-11-16 20:02:39 +05:30
|
|
|
if r.options.Interactsh != nil {
|
|
|
|
|
data, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(data, r.interactshURLs)
|
|
|
|
|
}
|
2021-04-13 13:28:29 +07:00
|
|
|
return r.handleRawWithPayloads(ctx, data, baseURL, values, payloads)
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2021-04-13 13:28:29 +07:00
|
|
|
// handleRawWithPayloads handles raw requests along with payloads
|
|
|
|
|
func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest, baseURL string, values, generatorValues map[string]interface{}) (*generatedRequest, error) {
|
2021-02-04 04:48:45 +05:30
|
|
|
// Combine the template payloads along with base
|
|
|
|
|
// request values.
|
|
|
|
|
finalValues := generators.MergeMaps(generatorValues, values)
|
2020-12-26 02:09:16 +05:30
|
|
|
|
2021-09-16 11:36:08 -05:00
|
|
|
// Evaluate the expressions for raw request if any.
|
2021-02-24 12:07:16 +05:30
|
|
|
var err error
|
|
|
|
|
rawRequest, err = expressions.Evaluate(rawRequest, finalValues)
|
|
|
|
|
if err != nil {
|
2022-05-12 05:10:14 -05:00
|
|
|
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
2021-02-24 12:07:16 +05:30
|
|
|
}
|
2020-12-28 01:33:50 +05:30
|
|
|
rawRequestData, err := raw.Parse(rawRequest, baseURL, r.request.Unsafe)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// retryablehttp
|
|
|
|
|
var body io.ReadCloser
|
2020-12-28 01:33:50 +05:30
|
|
|
body = ioutil.NopCloser(strings.NewReader(rawRequestData.Data))
|
|
|
|
|
if r.request.Race {
|
2020-12-26 02:09:16 +05:30
|
|
|
// More or less this ensures that all requests hit the endpoint at the same approximated time
|
|
|
|
|
// Todo: sync internally upon writing latest request byte
|
2020-12-26 14:55:15 +05:30
|
|
|
body = race.NewOpenGateWithTimeout(body, time.Duration(2)*time.Second)
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-28 01:33:50 +05:30
|
|
|
req, err := http.NewRequestWithContext(ctx, rawRequestData.Method, rawRequestData.FullURL, body)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
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
|
|
|
}
|
2021-11-04 17:13:47 +05:30
|
|
|
request, err := r.fillRequest(req, finalValues)
|
2020-12-26 02:09:16 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-02-20 00:35:39 +01:00
|
|
|
|
2022-05-12 13:13:56 +02:00
|
|
|
if reqWithAnnotations, hasAnnotations := parseAnnotations(rawRequest, req); hasAnnotations {
|
|
|
|
|
req = reqWithAnnotations
|
|
|
|
|
request = request.WithContext(req.Context())
|
|
|
|
|
}
|
2022-04-04 09:32:41 +02:00
|
|
|
|
2021-11-04 17:13:47 +05:30
|
|
|
return &generatedRequest{request: request, meta: generatorValues, original: r.request, dynamicValues: finalValues, interactshURLs: r.interactshURLs}, 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
|
2021-11-04 17:13:47 +05:30
|
|
|
func (r *requestGenerator) fillRequest(req *http.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 {
|
|
|
|
|
value, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(value, r.interactshURLs)
|
|
|
|
|
}
|
2021-08-16 00:14:47 +05:30
|
|
|
value, err := expressions.Evaluate(value, values)
|
|
|
|
|
if err != nil {
|
2022-05-12 05:10:14 -05:00
|
|
|
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
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 {
|
|
|
|
|
body, r.interactshURLs = r.options.Interactsh.ReplaceMarkers(r.request.Body, r.interactshURLs)
|
|
|
|
|
}
|
2021-08-16 00:14:47 +05:30
|
|
|
body, err := expressions.Evaluate(body, values)
|
|
|
|
|
if err != nil {
|
2022-05-12 05:10:14 -05:00
|
|
|
return nil, errors.Wrap(err, evaluateHelperExpressionErrorMessage)
|
2021-08-16 00:14:47 +05:30
|
|
|
}
|
2021-04-16 16:56:41 +05:30
|
|
|
req.Body = ioutil.NopCloser(strings.NewReader(body))
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2021-11-27 17:10:27 -06:00
|
|
|
if !r.request.Unsafe {
|
|
|
|
|
setHeader(req, "User-Agent", uarand.GetRandom())
|
|
|
|
|
}
|
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 {
|
2021-02-04 04:48:45 +05:30
|
|
|
setHeader(req, "Accept", "*/*")
|
|
|
|
|
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
|
|
|
|
|
|
|
|
filledRequest, err := retryablehttp.FromRequest(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r.request.DigestAuthUsername != "" {
|
|
|
|
|
filledRequest.Auth = &retryablehttp.Auth{
|
|
|
|
|
Type: retryablehttp.DigestAuth,
|
|
|
|
|
Username: r.request.DigestAuthUsername,
|
|
|
|
|
Password: r.request.DigestAuthPassword,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filledRequest, nil
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setHeader sets some headers only if the header wasn't supplied by the user
|
|
|
|
|
func setHeader(req *http.Request, name, value string) {
|
|
|
|
|
if _, ok := req.Header[name]; !ok {
|
|
|
|
|
req.Header.Set(name, value)
|
|
|
|
|
}
|
2021-05-02 20:10:49 +02:00
|
|
|
if name == "Host" {
|
|
|
|
|
req.Host = value
|
|
|
|
|
}
|
2020-12-26 02:09:16 +05:30
|
|
|
}
|
2021-08-12 12:10:35 -05:00
|
|
|
|
|
|
|
|
// generateVariables will create default variables after parsing a url
|
|
|
|
|
func generateVariables(parsed *url.URL, trailingSlash bool) map[string]interface{} {
|
|
|
|
|
domain := parsed.Host
|
|
|
|
|
if strings.Contains(parsed.Host, ":") {
|
|
|
|
|
domain = strings.Split(parsed.Host, ":")[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port := parsed.Port()
|
|
|
|
|
if port == "" {
|
|
|
|
|
if parsed.Scheme == "https" {
|
|
|
|
|
port = "443"
|
|
|
|
|
} else if parsed.Scheme == "http" {
|
|
|
|
|
port = "80"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if trailingSlash {
|
|
|
|
|
parsed.Path = strings.TrimSuffix(parsed.Path, "/")
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 13:35:11 +05:30
|
|
|
escapedPath := parsed.EscapedPath()
|
|
|
|
|
directory := path.Dir(escapedPath)
|
|
|
|
|
if directory == "." {
|
|
|
|
|
directory = ""
|
|
|
|
|
}
|
|
|
|
|
base := path.Base(escapedPath)
|
|
|
|
|
if base == "." {
|
|
|
|
|
base = ""
|
|
|
|
|
}
|
2022-01-14 12:00:59 +01:00
|
|
|
httpVariables := map[string]interface{}{
|
2021-08-12 12:10:35 -05:00
|
|
|
"BaseURL": parsed.String(),
|
2021-08-13 20:08:18 +05:30
|
|
|
"RootURL": fmt.Sprintf("%s://%s", parsed.Scheme, parsed.Host),
|
2021-08-12 12:10:35 -05:00
|
|
|
"Hostname": parsed.Host,
|
2021-08-13 20:08:18 +05:30
|
|
|
"Host": domain,
|
2021-08-12 12:10:35 -05:00
|
|
|
"Port": port,
|
2021-08-30 13:35:11 +05:30
|
|
|
"Path": directory,
|
|
|
|
|
"File": base,
|
2021-08-13 20:08:18 +05:30
|
|
|
"Scheme": parsed.Scheme,
|
2021-08-12 12:10:35 -05:00
|
|
|
}
|
2022-01-14 12:00:59 +01:00
|
|
|
return generators.MergeMaps(httpVariables, dns.GenerateDNSVariables(domain))
|
2021-08-12 12:10:35 -05:00
|
|
|
}
|