nuclei/v2/pkg/protocols/http/request_annotations.go

133 lines
3.7 KiB
Go
Raw Normal View History

2022-04-04 09:32:41 +02:00
package http
import (
"context"
2022-04-13 17:41:02 +02:00
"net"
2022-04-04 09:32:41 +02:00
"net/http"
"regexp"
"strings"
"time"
2022-04-13 17:41:02 +02:00
"github.com/projectdiscovery/fastdialer/fastdialer"
iputil "github.com/projectdiscovery/utils/ip"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
2022-04-04 09:32:41 +02:00
)
var (
// @Host:target overrides the input target with the annotated one (similar to self-contained requests)
reHostAnnotation = regexp.MustCompile(`(?m)^@Host:\s*(.+)\s*$`)
// @tls-sni:target overrides the input target with the annotated one
// special values:
// request.host: takes the value from the host header
// target: overiddes with the specific value
reSniAnnotation = regexp.MustCompile(`(?m)^@tls-sni:\s*(.+)\s*$`)
// @timeout:duration overrides the input timout with a custom duration
reTimeoutAnnotation = regexp.MustCompile(`(?m)^@timeout:\s*(.+)\s*$`)
// @once sets the request to be executed only once for a specific URL
reOnceAnnotation = regexp.MustCompile(`(?m)^@once\s*$`)
)
2022-04-04 09:32:41 +02:00
type flowMark int
const (
Once flowMark = iota
)
// parseFlowAnnotations and override requests flow
func parseFlowAnnotations(rawRequest string) (flowMark, bool) {
var fm flowMark
// parse request for known ovverride annotations
var hasFlowOveride bool
// @once
if reOnceAnnotation.MatchString(rawRequest) {
fm = Once
hasFlowOveride = true
}
return fm, hasFlowOveride
}
2022-04-04 09:32:41 +02:00
// parseAnnotations and override requests settings
2022-10-10 08:10:07 +02:00
func (r *Request) parseAnnotations(rawRequest string, request *http.Request) (*http.Request, context.CancelFunc, bool) {
var (
modified bool
cancelFunc context.CancelFunc
)
2022-04-04 09:32:41 +02:00
// parse request for known ovverride annotations
2022-10-10 08:10:07 +02:00
// @Host:target
2022-04-04 09:32:41 +02:00
if hosts := reHostAnnotation.FindStringSubmatch(rawRequest); len(hosts) > 0 {
2022-04-13 17:41:02 +02:00
value := strings.TrimSpace(hosts[1])
// handle scheme
switch {
case stringsutil.HasPrefixI(value, "http://"):
request.URL.Scheme = urlutil.HTTP
case stringsutil.HasPrefixI(value, "https://"):
request.URL.Scheme = urlutil.HTTPS
}
value = stringsutil.TrimPrefixAny(value, "http://", "https://")
if isHostPort(value) {
request.URL.Host = value
2022-04-14 12:59:21 +02:00
} else {
hostPort := value
port := request.URL.Port()
if port != "" {
hostPort = net.JoinHostPort(hostPort, port)
}
request.URL.Host = hostPort
2022-04-13 17:41:02 +02:00
}
modified = true
}
// @tls-sni:target
if hosts := reSniAnnotation.FindStringSubmatch(rawRequest); len(hosts) > 0 {
value := strings.TrimSpace(hosts[1])
value = stringsutil.TrimPrefixAny(value, "http://", "https://")
if idxForwardSlash := strings.Index(value, "/"); idxForwardSlash >= 0 {
value = value[:idxForwardSlash]
}
if stringsutil.EqualFoldAny(value, "request.host") {
value = request.Host
}
ctx := context.WithValue(request.Context(), fastdialer.SniName, value)
request = request.Clone(ctx)
modified = true
2022-04-13 17:41:02 +02:00
}
// @timeout:duration
if r.connConfiguration.NoTimeout {
modified = true
2022-10-10 08:10:07 +02:00
var ctx context.Context
if duration := reTimeoutAnnotation.FindStringSubmatch(rawRequest); len(duration) > 0 {
value := strings.TrimSpace(duration[1])
if parsed, err := time.ParseDuration(value); err == nil {
//nolint:govet // cancelled automatically by withTimeout
2022-10-10 08:10:07 +02:00
ctx, cancelFunc = context.WithTimeout(context.Background(), parsed)
request = request.Clone(ctx)
}
} else {
//nolint:govet // cancelled automatically by withTimeout
2022-10-10 08:10:07 +02:00
ctx, cancelFunc = context.WithTimeout(context.Background(), time.Duration(r.options.Options.Timeout)*time.Second)
request = request.Clone(ctx)
}
}
2022-10-10 08:10:07 +02:00
return request, cancelFunc, modified
2022-04-13 17:41:02 +02:00
}
func isHostPort(value string) bool {
_, port, err := net.SplitHostPort(value)
if err != nil {
return false
}
if !iputil.IsPort(port) {
return false
2022-04-04 09:32:41 +02:00
}
2022-04-13 17:41:02 +02:00
return true
2022-04-04 09:32:41 +02:00
}