Merge pull request #697 from projectdiscovery/bugfix-host-header

Better host header handling in RFC compliant requests
This commit is contained in:
Sandeep Singh 2021-05-04 18:24:22 +05:30 committed by GitHub
commit 31fc50d2a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 24 additions and 15 deletions

View File

@ -164,6 +164,9 @@ func (r *requestGenerator) handleRawWithPayloads(ctx context.Context, rawRequest
continue continue
} }
req.Header[key] = []string{value} req.Header[key] = []string{value}
if key == "Host" {
req.Host = value
}
} }
request, err := r.fillRequest(req, values, "") request, err := r.fillRequest(req, values, "")
if err != nil { if err != nil {
@ -181,6 +184,9 @@ func (r *requestGenerator) fillRequest(req *http.Request, values map[string]inte
value = r.options.Interactsh.ReplaceMarkers(value, interactURL) value = r.options.Interactsh.ReplaceMarkers(value, interactURL)
} }
req.Header[header] = []string{replacer.Replace(value, values)} req.Header[header] = []string{replacer.Replace(value, values)}
if header == "Host" {
req.Host = replacer.Replace(value, values)
}
} }
// In case of multiple threads the underlying connection should remain open to allow reuse // In case of multiple threads the underlying connection should remain open to allow reuse
@ -211,4 +217,7 @@ func setHeader(req *http.Request, name, value string) {
if _, ok := req.Header[name]; !ok { if _, ok := req.Header[name]; !ok {
req.Header.Set(name, value) req.Header.Set(name, value)
} }
if name == "Host" {
req.Host = value
}
} }

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"net/url" "net/url"
"strings" "strings"
@ -100,20 +99,11 @@ func Parse(request, baseURL string, unsafe bool) (*Request, error) {
rawRequest.Path = parts[1] rawRequest.Path = parts[1]
} }
// If raw request doesn't have a Host header and/ path,
// this will be generated from the parsed baseURL
parsedURL, err := url.Parse(baseURL) parsedURL, err := url.Parse(baseURL)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not parse request URL: %s", err) return nil, fmt.Errorf("could not parse request URL: %s", err)
} }
templateHost := rawRequest.Headers["Host"]
hostURL := parsedURL.Host hostURL := parsedURL.Host
if strings.Contains(templateHost, ":") {
_, templatePort, _ := net.SplitHostPort(templateHost)
hostURL = net.JoinHostPort(parsedURL.Hostname(), templatePort)
}
if strings.HasSuffix(parsedURL.Path, "/") && strings.HasPrefix(rawRequest.Path, "/") { if strings.HasSuffix(parsedURL.Path, "/") && strings.HasPrefix(rawRequest.Path, "/") {
parsedURL.Path = strings.TrimSuffix(parsedURL.Path, "/") parsedURL.Path = strings.TrimSuffix(parsedURL.Path, "/")
} }
@ -123,6 +113,12 @@ func Parse(request, baseURL string, unsafe bool) (*Request, error) {
} }
rawRequest.FullURL = fmt.Sprintf("%s://%s%s", parsedURL.Scheme, strings.TrimSpace(hostURL), rawRequest.Path) rawRequest.FullURL = fmt.Sprintf("%s://%s%s", parsedURL.Scheme, strings.TrimSpace(hostURL), rawRequest.Path)
// If raw request doesn't have a Host header
// this will be generated from the parsed baseURL
if rawRequest.Headers["Host"] == "" {
rawRequest.Headers["Host"] = hostURL
}
// Set the request body // Set the request body
b, err := ioutil.ReadAll(reader) b, err := ioutil.ReadAll(reader)
if err != nil { if err != nil {

View File

@ -15,7 +15,7 @@ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 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`, "https://example.com:8080", false) Accept-Language: en-US,en;q=0.9`, "https://example.com:8080", false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:123/gg/phpinfo.php", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/gg/phpinfo.php", request.FullURL, "Could not parse request url correctly")
require.Equal(t, "/gg/phpinfo.php", request.Path, "Could not parse request path correctly") require.Equal(t, "/gg/phpinfo.php", request.Path, "Could not parse request path correctly")
t.Run("path-suffix", func(t *testing.T) { t.Run("path-suffix", func(t *testing.T) {
@ -29,17 +29,17 @@ Host: {{Hostname}}`, "https://example.com:8080/test", false)
request, err := Parse(`GET ?username=test&password=test HTTP/1.1 request, err := Parse(`GET ?username=test&password=test HTTP/1.1
Host: {{Hostname}}:123`, "https://example.com:8080/test", false) Host: {{Hostname}}:123`, "https://example.com:8080/test", false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:123/test?username=test&password=test", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test?username=test&password=test", request.FullURL, "Could not parse request url correctly")
request, err = Parse(`GET ?username=test&password=test HTTP/1.1 request, err = Parse(`GET ?username=test&password=test HTTP/1.1
Host: {{Hostname}}:123`, "https://example.com:8080/test/", false) Host: {{Hostname}}:123`, "https://example.com:8080/test/", false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:123/test/?username=test&password=test", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test/?username=test&password=test", request.FullURL, "Could not parse request url correctly")
request, err = Parse(`GET /?username=test&password=test HTTP/1.1 request, err = Parse(`GET /?username=test&password=test HTTP/1.1
Host: {{Hostname}}:123`, "https://example.com:8080/test/", false) Host: {{Hostname}}:123`, "https://example.com:8080/test/", false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:123/test/?username=test&password=test", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test/?username=test&password=test", request.FullURL, "Could not parse request url correctly")
}) })
} }

View File

@ -430,7 +430,11 @@ func (r *Request) setCustomHeaders(req *generatedRequest) {
if req.rawRequest != nil { if req.rawRequest != nil {
req.rawRequest.Headers[k] = v req.rawRequest.Headers[k] = v
} else { } else {
req.request.Header.Set(strings.TrimSpace(k), strings.TrimSpace(v)) kk, vv := strings.TrimSpace(k), strings.TrimSpace(v)
req.request.Header.Set(kk, vv)
if kk == "Host" {
req.request.Host = vv
}
} }
} }
} }