From c1a565fad833f119fe21842dd235258ef22584b1 Mon Sep 17 00:00:00 2001 From: tosticated <> Date: Tue, 22 Dec 2020 22:33:25 +0100 Subject: [PATCH 1/3] Custom HTTP request headers support added. Addresses #1770 --- CREDITS.md | 2 +- doc/testssl.1 | 3 +++ doc/testssl.1.html | 2 ++ doc/testssl.1.md | 2 ++ testssl.sh | 24 +++++++++++++++++++++++- 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index beee57a..de826d5 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -42,6 +42,7 @@ Full contribution, see git log. * Jim Blankendaal - maximum certificate lifespan of 398 days - ssl renegotiation amount variable + - custom http request headers * Frank Breedijk - Detection of insecure redirects @@ -181,4 +182,3 @@ Probably more I forgot to mention which did give me feedback, bug reports and he * Ivan Ristic/Qualys for the liberal license which made it possible to make partly use of the client data * My family for supporting me doing this work - diff --git a/doc/testssl.1 b/doc/testssl.1 index 57c7a4f..ad40aee 100644 --- a/doc/testssl.1 +++ b/doc/testssl.1 @@ -136,6 +136,9 @@ Please note that \fBfname\fR has to be in Unix format\. DOS carriage returns won .P \fB\-\-basicauth \fR This can be set to provide HTTP basic auth credentials which are used during checks for security headers\. BASICAUTH is the ENV variable you can use instead\. . +.P +\fB\-\-customhttpheader
\fR This can be used to add additional HTTP request headers in the correct format \fBHeadername: headercontent\fR\. This parameter can be called multiple times if required\. For example: \fB\-\-customhttpheader \'Proxy\-Authorization: Basic dGVzdHNzbDpydWxlcw==\' \-\-customhttpheader \'ClientID: 0xDEADBEAF\'\fR\. CUSTOMHTTPHEADER is the corresponding environment variable\. +. .SS "SPECIAL INVOCATIONS" \fB\-t , \-\-starttls \fR does a default run against a STARTTLS enabled \fBprotocol\fR\. \fBprotocol\fR must be one of \fBftp\fR, \fBsmtp\fR, \fBpop3\fR, \fBimap\fR, \fBxmpp\fR, \fBxmpp-server\fR, \fBtelnet\fR, \fBldap\fR, \fBirc\fR, \fBlmtp\fR, \fBnntp\fR, \fBpostgres\fR, \fBmysql\fR\. For the latter four you need e\.g\. the supplied OpenSSL or OpenSSL version 1\.1\.1\. Please note: MongoDB doesn\'t offer a STARTTLS connection, LDAP currently only works with \fB\-\-ssl\-native\fR\. \fBtelnet\fR and \fBirc\fR is WIP\. . diff --git a/doc/testssl.1.html b/doc/testssl.1.html index dff5c7c..c37689c 100644 --- a/doc/testssl.1.html +++ b/doc/testssl.1.html @@ -187,6 +187,8 @@ The same can be achieved by setting the environment variable WARNINGS--basicauth <user:pass> This can be set to provide HTTP basic auth credentials which are used during checks for security headers. BASICAUTH is the ENV variable you can use instead.

+

--customhttpheader <header> This can be used to add additional HTTP request headers in the correct format Headername: headercontent. This parameter can be called multiple times if required. For example: --customhttpheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --customhttpheader 'ClientID: 0xDEADBEAF'. CUSTOMHTTPHEADER is the corresponding environment variable.

+

SPECIAL INVOCATIONS

-t <protocol>, --starttls <protocol> does a default run against a STARTTLS enabled protocol. protocol must be one of ftp, smtp, pop3, imap, xmpp, xmpp-server, telnet, ldap, irc, lmtp, nntp, postgres, mysql. For the latter four you need e.g. the supplied OpenSSL or OpenSSL version 1.1.1. Please note: MongoDB doesn't offer a STARTTLS connection, LDAP currently only works with --ssl-native. telnet and irc is WIP.

diff --git a/doc/testssl.1.md b/doc/testssl.1.md index fca7195..ee914fc 100644 --- a/doc/testssl.1.md +++ b/doc/testssl.1.md @@ -110,6 +110,8 @@ The same can be achieved by setting the environment variable `WARNINGS`. `--basicauth ` This can be set to provide HTTP basic auth credentials which are used during checks for security headers. BASICAUTH is the ENV variable you can use instead. +`--customhttpheader
` This can be used to add additional HTTP request headers in the correct format `Headername: headercontent`. This parameter can be called multiple times if required. For example: `--customhttpheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --customhttpheader 'ClientID: 0xDEADBEAF'`. CUSTOMHTTPHEADER is the corresponding environment variable. + ### SPECIAL INVOCATIONS diff --git a/testssl.sh b/testssl.sh index 0b2f684..b3a3ee1 100755 --- a/testssl.sh +++ b/testssl.sh @@ -162,6 +162,7 @@ QUIET=${QUIET:-false} # don't output the banner. By doing this SSL_NATIVE=${SSL_NATIVE:-false} # we do per default bash sockets where possible "true": switch back to "openssl native" ASSUME_HTTP=${ASSUME_HTTP:-false} # in seldom cases (WAF, old servers, grumpy SSL) service detection fails. "True" enforces HTTP checks BASICAUTH=${BASICAUTH:-""} # HTTP basic auth credentials can be set here like user:pass +CUSTOMHTTPHEADER=${CUSTOMHTTPHEADER:-""} # HTTP custom request header can be set here like Header: content. Can be used multiple times. BUGS=${BUGS:-""} # -bugs option from openssl, needed for some BIG IP F5 WARNINGS=${WARNINGS:-""} # can be either off or batch DEBUG=${DEBUG:-0} # 1: normal output the files in /tmp/ are kept for further debugging purposes @@ -373,6 +374,7 @@ TLS_NOW="" # Similar TLS_DIFFTIME_SET=false # Tells TLS functions to measure the TLS difftime or not NOW_TIME="" HTTP_TIME="" +CUSTOMHTTPHEADERS=() GET_REQ11="" START_TIME=0 # time in epoch when the action started END_TIME=0 # .. ended @@ -886,6 +888,15 @@ is_ipv6addr() { return 1 } +join_by() { + # joins an array using a custom delimiter https://web.archive.org/web/20201222183540/https://stackoverflow.com/questions/1527049/how-can-i-join-elements-of-an-array-in-bash/17841619#17841619 + local d=$1 + shift + local f=$1 + shift + printf %s "$f" "${@/#/$d}"; +} + ###### END universal helper function definitions ###### ###### START ServerHello/OpenSSL/F5 function definitions ###### @@ -19239,6 +19250,7 @@ tuning / connect options (most also can be preset via environment variables): --phone-out allow to contact external servers for CRL download and querying OCSP responder --add-ca path to with *.pem or a comma separated list of CA files to include in trust check --basicauth provide HTTP basic auth information. + --customhttpheader
add custom http request headers output options (can also be preset via environment variables): --quiet don't output the banner. By doing this you acknowledge usage terms normally appearing in the banner @@ -19391,6 +19403,7 @@ SHOW_EACH_C: $SHOW_EACH_C SSL_NATIVE: $SSL_NATIVE ASSUME_HTTP $ASSUME_HTTP BASICAUTH: $BASICAUTH +CUSTOMHTTPHEADER: $CUSTOMHTTPHEADER SNEAKY: $SNEAKY OFFENSIVE: $OFFENSIVE PHONE_OUT: $PHONE_OUT @@ -20514,6 +20527,7 @@ determine_service() { local ua local protocol local basicauth_header="" + local customhttpheader="" # Check if we can connect to $NODEIP:$PORT. Attention: This ALWAYS uses sockets. Thus timeouts for --ssl-=native do not apply if ! fd_socket 5; then @@ -20541,7 +20555,10 @@ determine_service() { if [[ -n "$BASICAUTH" ]]; then basicauth_header="Authorization: Basic $(safe_echo "$BASICAUTH" | $OPENSSL base64 2>/dev/null)\r\n" fi - GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\n${basicauth_header}Accept-Encoding: identity\r\nAccept: text/*\r\nConnection: Close\r\n\r\n" + if [[ -n "$CUSTOMHTTPHEADERS" ]]; then + customhttpheader="$(join_by "\r\n" "${CUSTOMHTTPHEADERS[@]}")\r\n" #Add all required custom http headers to one string with newlines + fi + GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\n${basicauth_header}${customhttpheader}Accept-Encoding: identity\r\nAccept: text/*\r\nConnection: Close\r\n\r\n" # returns always 0: service_detection $OPTIMAL_PROTO else # STARTTLS @@ -22193,6 +22210,11 @@ parse_cmd_line() { BASICAUTH="$(parse_opt_equal_sign "$1" "$2")" [[ $? -eq 0 ]] && shift ;; + --customhttpheader|--customhttpheader=*) + CUSTOMHTTPHEADER="$(parse_opt_equal_sign "$1" "$2")" + [[ $? -eq 0 ]] && shift + CUSTOMHTTPHEADERS+=("$CUSTOMHTTPHEADER") + ;; (--) shift break ;; From 1473cdf02d2f51b09784c474470506c023049bc8 Mon Sep 17 00:00:00 2001 From: tosticated <70525720+tosticated@users.noreply.github.com> Date: Thu, 24 Dec 2020 22:00:42 +0100 Subject: [PATCH 2/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a81c7d..ab67fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * Added --overwrite argument to support overwriting output files without warning * Headerflag X-XSS-Protection is now labeled as INFO * Client simulation runs in wide mode which is even better readable +* Added --customhttpheader to support custom headers in HTTP requests ### Features implemented / improvements in 3.0 From 351f36c9433765d488e949bd955860c35f0d3abe Mon Sep 17 00:00:00 2001 From: tosticated <> Date: Fri, 25 Dec 2020 20:10:02 +0100 Subject: [PATCH 3/3] Changed parameter to --reqheader for custom HTTP headers. --- CHANGELOG.md | 2 +- doc/testssl.1 | 2 +- doc/testssl.1.html | 2 +- doc/testssl.1.md | 2 +- testssl.sh | 22 +++++++++++----------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab67fcb..4cf6cc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ * Added --overwrite argument to support overwriting output files without warning * Headerflag X-XSS-Protection is now labeled as INFO * Client simulation runs in wide mode which is even better readable -* Added --customhttpheader to support custom headers in HTTP requests +* Added --reqheader to support custom headers in HTTP requests ### Features implemented / improvements in 3.0 diff --git a/doc/testssl.1 b/doc/testssl.1 index ad40aee..3ea717c 100644 --- a/doc/testssl.1 +++ b/doc/testssl.1 @@ -137,7 +137,7 @@ Please note that \fBfname\fR has to be in Unix format\. DOS carriage returns won \fB\-\-basicauth \fR This can be set to provide HTTP basic auth credentials which are used during checks for security headers\. BASICAUTH is the ENV variable you can use instead\. . .P -\fB\-\-customhttpheader
\fR This can be used to add additional HTTP request headers in the correct format \fBHeadername: headercontent\fR\. This parameter can be called multiple times if required\. For example: \fB\-\-customhttpheader \'Proxy\-Authorization: Basic dGVzdHNzbDpydWxlcw==\' \-\-customhttpheader \'ClientID: 0xDEADBEAF\'\fR\. CUSTOMHTTPHEADER is the corresponding environment variable\. +\fB\-\-reqheader
\fR This can be used to add additional HTTP request headers in the correct format \fBHeadername: headercontent\fR\. This parameter can be called multiple times if required\. For example: \fB\-\-reqheader \'Proxy\-Authorization: Basic dGVzdHNzbDpydWxlcw==\' \-\-reqheader \'ClientID: 0xDEADBEAF\'\fR\. REQHEADER is the corresponding environment variable\. . .SS "SPECIAL INVOCATIONS" \fB\-t , \-\-starttls \fR does a default run against a STARTTLS enabled \fBprotocol\fR\. \fBprotocol\fR must be one of \fBftp\fR, \fBsmtp\fR, \fBpop3\fR, \fBimap\fR, \fBxmpp\fR, \fBxmpp-server\fR, \fBtelnet\fR, \fBldap\fR, \fBirc\fR, \fBlmtp\fR, \fBnntp\fR, \fBpostgres\fR, \fBmysql\fR\. For the latter four you need e\.g\. the supplied OpenSSL or OpenSSL version 1\.1\.1\. Please note: MongoDB doesn\'t offer a STARTTLS connection, LDAP currently only works with \fB\-\-ssl\-native\fR\. \fBtelnet\fR and \fBirc\fR is WIP\. diff --git a/doc/testssl.1.html b/doc/testssl.1.html index c37689c..df4743d 100644 --- a/doc/testssl.1.html +++ b/doc/testssl.1.html @@ -187,7 +187,7 @@ The same can be achieved by setting the environment variable WARNINGS--basicauth <user:pass> This can be set to provide HTTP basic auth credentials which are used during checks for security headers. BASICAUTH is the ENV variable you can use instead.

-

--customhttpheader <header> This can be used to add additional HTTP request headers in the correct format Headername: headercontent. This parameter can be called multiple times if required. For example: --customhttpheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --customhttpheader 'ClientID: 0xDEADBEAF'. CUSTOMHTTPHEADER is the corresponding environment variable.

+

--reqheader <header> This can be used to add additional HTTP request headers in the correct format Headername: headercontent. This parameter can be called multiple times if required. For example: --reqheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --reqheader 'ClientID: 0xDEADBEAF'. REQHEADER is the corresponding environment variable.

SPECIAL INVOCATIONS

diff --git a/doc/testssl.1.md b/doc/testssl.1.md index ee914fc..11cc267 100644 --- a/doc/testssl.1.md +++ b/doc/testssl.1.md @@ -110,7 +110,7 @@ The same can be achieved by setting the environment variable `WARNINGS`. `--basicauth ` This can be set to provide HTTP basic auth credentials which are used during checks for security headers. BASICAUTH is the ENV variable you can use instead. -`--customhttpheader
` This can be used to add additional HTTP request headers in the correct format `Headername: headercontent`. This parameter can be called multiple times if required. For example: `--customhttpheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --customhttpheader 'ClientID: 0xDEADBEAF'`. CUSTOMHTTPHEADER is the corresponding environment variable. +`--reqheader
` This can be used to add additional HTTP request headers in the correct format `Headername: headercontent`. This parameter can be called multiple times if required. For example: `--reqheader 'Proxy-Authorization: Basic dGVzdHNzbDpydWxlcw==' --reqheader 'ClientID: 0xDEADBEAF'`. REQHEADER is the corresponding environment variable. ### SPECIAL INVOCATIONS diff --git a/testssl.sh b/testssl.sh index b3a3ee1..cb21f34 100755 --- a/testssl.sh +++ b/testssl.sh @@ -162,7 +162,7 @@ QUIET=${QUIET:-false} # don't output the banner. By doing this SSL_NATIVE=${SSL_NATIVE:-false} # we do per default bash sockets where possible "true": switch back to "openssl native" ASSUME_HTTP=${ASSUME_HTTP:-false} # in seldom cases (WAF, old servers, grumpy SSL) service detection fails. "True" enforces HTTP checks BASICAUTH=${BASICAUTH:-""} # HTTP basic auth credentials can be set here like user:pass -CUSTOMHTTPHEADER=${CUSTOMHTTPHEADER:-""} # HTTP custom request header can be set here like Header: content. Can be used multiple times. +REQHEADER=${REQHEADER:-""} # HTTP custom request header can be set here like Header: content. Can be used multiple times. BUGS=${BUGS:-""} # -bugs option from openssl, needed for some BIG IP F5 WARNINGS=${WARNINGS:-""} # can be either off or batch DEBUG=${DEBUG:-0} # 1: normal output the files in /tmp/ are kept for further debugging purposes @@ -374,7 +374,7 @@ TLS_NOW="" # Similar TLS_DIFFTIME_SET=false # Tells TLS functions to measure the TLS difftime or not NOW_TIME="" HTTP_TIME="" -CUSTOMHTTPHEADERS=() +REQHEADERS=() GET_REQ11="" START_TIME=0 # time in epoch when the action started END_TIME=0 # .. ended @@ -19250,7 +19250,7 @@ tuning / connect options (most also can be preset via environment variables): --phone-out allow to contact external servers for CRL download and querying OCSP responder --add-ca path to with *.pem or a comma separated list of CA files to include in trust check --basicauth provide HTTP basic auth information. - --customhttpheader
add custom http request headers + --reqheader
add custom http request headers output options (can also be preset via environment variables): --quiet don't output the banner. By doing this you acknowledge usage terms normally appearing in the banner @@ -19403,7 +19403,7 @@ SHOW_EACH_C: $SHOW_EACH_C SSL_NATIVE: $SSL_NATIVE ASSUME_HTTP $ASSUME_HTTP BASICAUTH: $BASICAUTH -CUSTOMHTTPHEADER: $CUSTOMHTTPHEADER +REQHEADER: $REQHEADER SNEAKY: $SNEAKY OFFENSIVE: $OFFENSIVE PHONE_OUT: $PHONE_OUT @@ -20527,7 +20527,7 @@ determine_service() { local ua local protocol local basicauth_header="" - local customhttpheader="" + local reqheader="" # Check if we can connect to $NODEIP:$PORT. Attention: This ALWAYS uses sockets. Thus timeouts for --ssl-=native do not apply if ! fd_socket 5; then @@ -20555,10 +20555,10 @@ determine_service() { if [[ -n "$BASICAUTH" ]]; then basicauth_header="Authorization: Basic $(safe_echo "$BASICAUTH" | $OPENSSL base64 2>/dev/null)\r\n" fi - if [[ -n "$CUSTOMHTTPHEADERS" ]]; then - customhttpheader="$(join_by "\r\n" "${CUSTOMHTTPHEADERS[@]}")\r\n" #Add all required custom http headers to one string with newlines + if [[ -n "$REQHEADERS" ]]; then + reqheader="$(join_by "\r\n" "${REQHEADERS[@]}")\r\n" #Add all required custom http headers to one string with newlines fi - GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\n${basicauth_header}${customhttpheader}Accept-Encoding: identity\r\nAccept: text/*\r\nConnection: Close\r\n\r\n" + GET_REQ11="GET $URL_PATH HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $ua\r\n${basicauth_header}${reqheader}Accept-Encoding: identity\r\nAccept: text/*\r\nConnection: Close\r\n\r\n" # returns always 0: service_detection $OPTIMAL_PROTO else # STARTTLS @@ -22210,10 +22210,10 @@ parse_cmd_line() { BASICAUTH="$(parse_opt_equal_sign "$1" "$2")" [[ $? -eq 0 ]] && shift ;; - --customhttpheader|--customhttpheader=*) - CUSTOMHTTPHEADER="$(parse_opt_equal_sign "$1" "$2")" + --reqheader|--reqheader=*) + REQHEADER="$(parse_opt_equal_sign "$1" "$2")" [[ $? -eq 0 ]] && shift - CUSTOMHTTPHEADERS+=("$CUSTOMHTTPHEADER") + REQHEADERS+=("$REQHEADER") ;; (--) shift break