Feature fail http to https for known status code and substrings (#308)

* Add `--fail-http-to-https` to retry as HTTPS when --retry-https is used and certain known responses are encountered indicating HTTPS should be used

* Apache: HTTP/400, substring "You're speaking plain HTTP to an SSL-enabled server port"
* NGINX: HTTP/400, substring "The plain HTTP request was sent to HTTPS port"

* Add additional substring observed indicating http->https

* Add another observed substring, adjust whitespace

* Use go-ism for slicing implicitly from index 0

Co-authored-by: Adam Greene <copyright@mzpqnxow.com>
This commit is contained in:
AG 2021-06-06 14:31:36 -04:00 committed by GitHub
parent 2b6e6cb2ec
commit ecd32d0d5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -46,12 +46,13 @@ var (
type Flags struct {
zgrab2.BaseFlags
zgrab2.TLSFlags
Method string `long:"method" default:"GET" description:"Set HTTP request method type"`
Endpoint string `long:"endpoint" default:"/" description:"Send an HTTP request to an endpoint"`
UserAgent string `long:"user-agent" default:"Mozilla/5.0 zgrab/0.x" description:"Set a custom user agent"`
RetryHTTPS bool `long:"retry-https" description:"If the initial request fails, reconnect and try with HTTPS."`
MaxSize int `long:"max-size" default:"256" description:"Max kilobytes to read in response to an HTTP request"`
MaxRedirects int `long:"max-redirects" default:"0" description:"Max number of redirects to follow"`
Method string `long:"method" default:"GET" description:"Set HTTP request method type"`
Endpoint string `long:"endpoint" default:"/" description:"Send an HTTP request to an endpoint"`
FailHTTPToHTTPS bool `long:"fail-http-to-https" description:"Trigger retry-https logic on known HTTP/400 protocol mismatch responses"`
UserAgent string `long:"user-agent" default:"Mozilla/5.0 zgrab/0.x" description:"Set a custom user agent"`
RetryHTTPS bool `long:"retry-https" description:"If the initial request fails, reconnect and try with HTTPS."`
MaxSize int `long:"max-size" default:"256" description:"Max kilobytes to read in response to an HTTP request"`
MaxRedirects int `long:"max-redirects" default:"0" description:"Max number of redirects to follow"`
// FollowLocalhostRedirects overrides the default behavior to return
// ErrRedirLocalhost whenever a redirect points to localhost.
@ -541,6 +542,23 @@ func (scan *scan) Grab() *zgrab2.ScanError {
bodyText = buf.String()
}
// Application-specific logic for retrying HTTP as HTTPS; if condition matches, return protocol error
if scan.scanner.config.FailHTTPToHTTPS && scan.results.Response.StatusCode == 400 && readLen < 1024 && readLen > 24 {
// Apache: "You're speaking plain HTTP to an SSL-enabled server port"
// NGINX: "The plain HTTP request was sent to HTTPS port"
var sliceLen int64 = 128
if readLen < sliceLen {
sliceLen = readLen
}
sliceBuf := bodyText[:sliceLen]
if strings.Contains(sliceBuf, "The plain HTTP request was sent to HTTPS port") ||
strings.Contains(sliceBuf, "You're speaking plain HTTP") ||
strings.Contains(sliceBuf, "combination of host and port requires TLS") ||
strings.Contains(sliceBuf, "Client sent an HTTP request to an HTTPS server") {
return zgrab2.NewScanError(zgrab2.SCAN_PROTOCOL_ERROR, errors.New("NGINX or Apache HTTP over HTTPS failure"))
}
}
// re-enforce readlen
if int64(len(bodyText)) > readLen {
scan.results.Response.BodyText = bodyText[:int(readLen)]