mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-09-03 18:48:28 +02:00
Merge pull request #2842 from testssl/opossum
Redo PR for Opossum , see #2838
This commit is contained in:
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
* QUIC protocol check
|
* QUIC protocol check
|
||||||
* bump SSLlabs rating guide to 2009r
|
* bump SSLlabs rating guide to 2009r
|
||||||
|
* Check for Opossum vulnerability
|
||||||
|
|
||||||
### Features implemented / improvements in 3.2
|
### Features implemented / improvements in 3.2
|
||||||
|
|
||||||
|
@ -659,6 +659,9 @@ variable \f[CR]CCS_MAX_WAITSOCK\f[R].
|
|||||||
\f[CR]\-T, \-\-ticketbleed\f[R] Checks for Ticketbleed memory leakage in
|
\f[CR]\-T, \-\-ticketbleed\f[R] Checks for Ticketbleed memory leakage in
|
||||||
BigIP loadbalancers.
|
BigIP loadbalancers.
|
||||||
.PP
|
.PP
|
||||||
|
\f[CR]\-\-OP, \-\-opossum\f[R] Checks for HTTP to HTTPS upgrade
|
||||||
|
vulnerability named Opossum.
|
||||||
|
.PP
|
||||||
\f[CR]\-\-BB, \-\-robot\f[R] Checks for vulnerability to ROBOT /
|
\f[CR]\-\-BB, \-\-robot\f[R] Checks for vulnerability to ROBOT /
|
||||||
(\f[I]Return Of Bleichenbacher\[cq]s Oracle Threat\f[R]) attack.
|
(\f[I]Return Of Bleichenbacher\[cq]s Oracle Threat\f[R]) attack.
|
||||||
.PP
|
.PP
|
||||||
@ -1312,6 +1315,8 @@ RFC 2246: The TLS Protocol Version 1.0
|
|||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
RFC 2595: Using TLS with IMAP, POP3 and ACAP
|
RFC 2595: Using TLS with IMAP, POP3 and ACAP
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
|
RFC 2817: Upgrading to TLS Within HTTP/1.1
|
||||||
|
.IP \[bu] 2
|
||||||
RFC 2818: HTTP Over TLS
|
RFC 2818: HTTP Over TLS
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
RFC 2830: Lightweight Directory Access Protocol (v3): Extension for
|
RFC 2830: Lightweight Directory Access Protocol (v3): Extension for
|
||||||
|
@ -590,6 +590,8 @@
|
|||||||
<code>CCS_MAX_WAITSOCK</code>.</p>
|
<code>CCS_MAX_WAITSOCK</code>.</p>
|
||||||
<p><code>-T, --ticketbleed</code> Checks for Ticketbleed memory
|
<p><code>-T, --ticketbleed</code> Checks for Ticketbleed memory
|
||||||
leakage in BigIP loadbalancers.</p>
|
leakage in BigIP loadbalancers.</p>
|
||||||
|
<p><code>--OP, --opossum</code> Checks for HTTP to HTTPS upgrade
|
||||||
|
vulnerability named Opossum.</p>
|
||||||
<p><code>--BB, --robot</code> Checks for vulnerability to ROBOT
|
<p><code>--BB, --robot</code> Checks for vulnerability to ROBOT
|
||||||
/ (<em>Return Of Bleichenbacher’s Oracle Threat</em>)
|
/ (<em>Return Of Bleichenbacher’s Oracle Threat</em>)
|
||||||
attack.</p>
|
attack.</p>
|
||||||
@ -1131,6 +1133,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>RFC 2246: The TLS Protocol Version 1.0</li>
|
<li>RFC 2246: The TLS Protocol Version 1.0</li>
|
||||||
<li>RFC 2595: Using TLS with IMAP, POP3 and ACAP</li>
|
<li>RFC 2595: Using TLS with IMAP, POP3 and ACAP</li>
|
||||||
|
<li>RFC 2817: Upgrading to TLS Within HTTP/1.1</li>
|
||||||
<li>RFC 2818: HTTP Over TLS</li>
|
<li>RFC 2818: HTTP Over TLS</li>
|
||||||
<li>RFC 2830: Lightweight Directory Access Protocol (v3):
|
<li>RFC 2830: Lightweight Directory Access Protocol (v3):
|
||||||
Extension for Transport Layer Security</li>
|
Extension for Transport Layer Security</li>
|
||||||
|
@ -236,9 +236,11 @@ Also for multiple server certificates are being checked for as well as for the c
|
|||||||
|
|
||||||
`-T, --ticketbleed` Checks for Ticketbleed memory leakage in BigIP loadbalancers.
|
`-T, --ticketbleed` Checks for Ticketbleed memory leakage in BigIP loadbalancers.
|
||||||
|
|
||||||
`--BB, --robot` Checks for vulnerability to ROBOT / (*Return Of Bleichenbacher's Oracle Threat*) attack.
|
`--OP, --opossum` Checks for HTTP to HTTPS upgrade vulnerability named Opossum.
|
||||||
|
|
||||||
`--SI, --starttls-injection` Checks for STARTTLS injection vulnerabilities (SMTP, IMAP, POP3 only). `socat` and OpenSSL >=1.1.0 is needed.
|
`--BB, --robot` Checks for vulnerability to ROBOT / (*Return Of Bleichenbacher's Oracle Threat*) attack.
|
||||||
|
|
||||||
|
`--SI, --starttls-injection` Checks for STARTTLS injection vulnerabilities (SMTP, IMAP, POP3 only). `socat` and OpenSSL >=1.1.0 is needed.
|
||||||
|
|
||||||
`-R, --renegotiation` Tests renegotiation vulnerabilities. Currently there's a check for *Secure Renegotiation* and for *Secure Client-Initiated Renegotiation*. Please be aware that vulnerable servers to the latter can likely be DoSed very easily (HTTP). A check for *Insecure Client-Initiated Renegotiation* is not yet implemented.
|
`-R, --renegotiation` Tests renegotiation vulnerabilities. Currently there's a check for *Secure Renegotiation* and for *Secure Client-Initiated Renegotiation*. Please be aware that vulnerable servers to the latter can likely be DoSed very easily (HTTP). A check for *Insecure Client-Initiated Renegotiation* is not yet implemented.
|
||||||
|
|
||||||
@ -490,6 +492,7 @@ Please note that for plain TLS-encrypted ports you must not specify the protocol
|
|||||||
|
|
||||||
* RFC 2246: The TLS Protocol Version 1.0
|
* RFC 2246: The TLS Protocol Version 1.0
|
||||||
* RFC 2595: Using TLS with IMAP, POP3 and ACAP
|
* RFC 2595: Using TLS with IMAP, POP3 and ACAP
|
||||||
|
* RFC 2817: Upgrading to TLS Within HTTP/1.1
|
||||||
* RFC 2818: HTTP Over TLS
|
* RFC 2818: HTTP Over TLS
|
||||||
* RFC 2830: Lightweight Directory Access Protocol (v3): Extension for Transport Layer Security
|
* RFC 2830: Lightweight Directory Access Protocol (v3): Extension for Transport Layer Security
|
||||||
* RFC 3207: SMTP Service Extension for Secure SMTP over Transport Layer Security
|
* RFC 3207: SMTP Service Extension for Secure SMTP over Transport Layer Security
|
||||||
@ -551,7 +554,6 @@ Please note that for plain TLS-encrypted ports you must not specify the protocol
|
|||||||
|
|
||||||
**etc/client-simulation.txt** contains client simulation data.
|
**etc/client-simulation.txt** contains client simulation data.
|
||||||
|
|
||||||
|
|
||||||
**etc/cipher-mapping.txt** provides a mandatory file with mapping from OpenSSL cipher suites names to the ones from IANA / used in the RFCs.
|
**etc/cipher-mapping.txt** provides a mandatory file with mapping from OpenSSL cipher suites names to the ones from IANA / used in the RFCs.
|
||||||
|
|
||||||
**etc/tls_data.txt** provides a mandatory file for ciphers (bash sockets) and key material.
|
**etc/tls_data.txt** provides a mandatory file for ciphers (bash sockets) and key material.
|
||||||
|
@ -48,7 +48,7 @@ $edited_html =~ s/'/'/g;
|
|||||||
|
|
||||||
$diff = diff \$edited_html, \$out;
|
$diff = diff \$edited_html, \$out;
|
||||||
|
|
||||||
cmp_ok($edited_html, "eq", $out, "Checking if HTML file matches terminal output") or
|
ok($edited_html eq $out, "Checking if HTML file matches terminal output") or
|
||||||
diag ("\n%s\n", "$diff");
|
diag ("\n%s\n", "$diff");
|
||||||
|
|
||||||
$tests++;
|
$tests++;
|
||||||
@ -82,7 +82,7 @@ $debughtml =~ s/.*Using bash .*\n//g;
|
|||||||
|
|
||||||
$diff = diff \$debughtml, \$html;
|
$diff = diff \$debughtml, \$html;
|
||||||
|
|
||||||
cmp_ok($debughtml, "eq", $html, "Checking if HTML file created with --debug 4 matches HTML file created without --debug") or
|
ok($debughtml eq $html, "Checking if HTML file created with --debug 4 matches HTML file created without --debug") or
|
||||||
diag ("\n%s\n", "$diff");
|
diag ("\n%s\n", "$diff");
|
||||||
$tests++;
|
$tests++;
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@
|
|||||||
"heartbleed","testssl.sh/81.169.166.184","443","OK","not vulnerable, no heartbeat extension","CVE-2014-0160","CWE-119"
|
"heartbleed","testssl.sh/81.169.166.184","443","OK","not vulnerable, no heartbeat extension","CVE-2014-0160","CWE-119"
|
||||||
"CCS","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2014-0224","CWE-310"
|
"CCS","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2014-0224","CWE-310"
|
||||||
"ticketbleed","testssl.sh/81.169.166.184","443","OK","no session ticket extension","CVE-2016-9244","CWE-200"
|
"ticketbleed","testssl.sh/81.169.166.184","443","OK","no session ticket extension","CVE-2016-9244","CWE-200"
|
||||||
|
"opossum","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2025-49812","CWE-287"
|
||||||
"ROBOT","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2017-17382 CVE-2017-17427 CVE-2017-17428 CVE-2017-13098 CVE-2017-1000385 CVE-2017-13099 CVE-2016-6883 CVE-2012-5081 CVE-2017-6168","CWE-203"
|
"ROBOT","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2017-17382 CVE-2017-17427 CVE-2017-17428 CVE-2017-13098 CVE-2017-1000385 CVE-2017-13099 CVE-2016-6883 CVE-2012-5081 CVE-2017-6168","CWE-203"
|
||||||
"secure_renego","testssl.sh/81.169.166.184","443","OK","supported","","CWE-310"
|
"secure_renego","testssl.sh/81.169.166.184","443","OK","supported","","CWE-310"
|
||||||
"secure_client_renego","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2011-1473","CWE-310"
|
"secure_client_renego","testssl.sh/81.169.166.184","443","OK","not vulnerable","CVE-2011-1473","CWE-310"
|
||||||
|
185
testssl.sh
185
testssl.sh
@ -1786,12 +1786,13 @@ filter_input() {
|
|||||||
sed -e 's/#.*$//' -e '/^$/d' <<< "$1" | tr -d '\n' | tr -d '\t' | tr -d '\r'
|
sed -e 's/#.*$//' -e '/^$/d' <<< "$1" | tr -d '\n' | tr -d '\t' | tr -d '\r'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Dl's any URL (arg1) via HTTP 1.1 GET from port 80, arg2: file to store http body.
|
# Dl any URL (arg1) via HTTP 1.1 GET from port 80 or 443 (curl/wget). arg2: file to store http body.
|
||||||
# Proxy is not honored yet (see cmd line switches) -- except when using curl or wget.
|
# Proxy is not honored yet (see cmd line switches) -- except when using curl or wget.
|
||||||
# There the environment variable is used automatically
|
# The PROXY environment variable is used when specified
|
||||||
# Currently it is being used by check_revocation_crl() only.
|
# Currently this is being used by check_revocation_crl() only.
|
||||||
|
#
|
||||||
http_get() {
|
http_get() {
|
||||||
local proto z
|
local proto="" foo=""
|
||||||
local node="" query=""
|
local node="" query=""
|
||||||
local dl="$2"
|
local dl="$2"
|
||||||
local useragent="$UA_STD"
|
local useragent="$UA_STD"
|
||||||
@ -1825,7 +1826,7 @@ http_get() {
|
|||||||
# Worst option: slower and hiccups with chunked transfers. Workaround for the
|
# Worst option: slower and hiccups with chunked transfers. Workaround for the
|
||||||
# latter is using HTTP/1.0. We do not support https here, yet.
|
# latter is using HTTP/1.0. We do not support https here, yet.
|
||||||
# First the URL will be split
|
# First the URL will be split
|
||||||
IFS=/ read -r proto z node query <<< "$1"
|
IFS=/ read -r proto foo node query <<< "$1"
|
||||||
proto=${proto%:}
|
proto=${proto%:}
|
||||||
if [[ "$proto" != http ]]; then
|
if [[ "$proto" != http ]]; then
|
||||||
pr_warning "protocol $proto not supported yet"
|
pr_warning "protocol $proto not supported yet"
|
||||||
@ -1844,7 +1845,7 @@ http_get() {
|
|||||||
printf -- "%b" "GET $proto://$node/$query HTTP/1.0\r\nUser-Agent: $useragent\r\nHost: $node\r\nAccept: */*\r\n\r\n" >&33
|
printf -- "%b" "GET $proto://$node/$query HTTP/1.0\r\nUser-Agent: $useragent\r\nHost: $node\r\nAccept: */*\r\n\r\n" >&33
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
IFS=/ read -r proto z node query <<< "$1"
|
IFS=/ read -r proto foo node query <<< "$1"
|
||||||
exec 33<>/dev/tcp/$node/80
|
exec 33<>/dev/tcp/$node/80
|
||||||
printf -- "%b" "GET /$query HTTP/1.0\r\nUser-Agent: $useragent\r\nHost: $node\r\nAccept: */*\r\n\r\n" >&33
|
printf -- "%b" "GET /$query HTTP/1.0\r\nUser-Agent: $useragent\r\nHost: $node\r\nAccept: */*\r\n\r\n" >&33
|
||||||
fi
|
fi
|
||||||
@ -1861,55 +1862,105 @@ http_get() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Outputs the headers when downloading any URL (arg1) via HTTP 1.1 GET from port 80.
|
# Outputs the HTTP headers via HTTP 1.1 HEAD command via HTTPS and a valid certificate
|
||||||
|
# arg1 is the URL
|
||||||
|
# arg2 is optional and could be a request header. curl/wget don't send empty headers otherwise
|
||||||
|
#
|
||||||
# Only works if curl or wget is available.
|
# Only works if curl or wget is available.
|
||||||
# There the environment variable is used automatically
|
# The proxy environment variable is used automatically.
|
||||||
# Currently it is being used by check_pwnedkeys() only.
|
# Currently it is being used by check_pwnedkeys() only
|
||||||
http_get_header() {
|
#
|
||||||
|
http_head() {
|
||||||
local proto
|
local proto
|
||||||
local node="" query=""
|
local node="" query=""
|
||||||
local dl="$2"
|
local request_header="$2"
|
||||||
local useragent="$UA_STD"
|
local useragent="$UA_STD"
|
||||||
local jsonID="http_get_header"
|
local response_headers=""
|
||||||
local headers
|
local xtra_params=""
|
||||||
local -i ret
|
local -i ret
|
||||||
|
|
||||||
"$SNEAKY" && useragent="$UA_SNEAKY"
|
"$SNEAKY" && useragent="$UA_SNEAKY"
|
||||||
|
|
||||||
if type -p curl &>/dev/null; then
|
if type -p curl &>/dev/null; then
|
||||||
|
xtra_params="--connect-timeout $HEADER_MAXSLEEP --head -s"
|
||||||
if [[ -z "$PROXY" ]]; then
|
if [[ -z "$PROXY" ]]; then
|
||||||
headers="$(curl --head -s --noproxy '*' -A $''"$useragent"'' "$1")"
|
response_headers="$(curl $xtra_params --noproxy '*' -H $''"$request_header"'' -A $''"$useragent"'' "$1")"
|
||||||
else
|
else
|
||||||
# for the sake of simplicity assume the proxy is using http
|
# for the sake of simplicity assume the proxy is using http
|
||||||
headers="$(curl --head -s -x $PROXYIP:$PROXYPORT -A $''"$useragent"'' "$1")"
|
response_headers="$(curl $xtra_params -x $PROXYIP:$PROXYPORT -H $''"$request_header"'' -A $''"$useragent"'' "$1")"
|
||||||
fi
|
fi
|
||||||
ret=$?
|
ret=$?
|
||||||
[[ $ret -eq 0 ]] && tm_out "$headers"
|
[[ $ret -eq 0 ]] && tm_out "$response_headers"
|
||||||
return $ret
|
return $ret
|
||||||
elif type -p wget &>/dev/null; then
|
elif type -p wget &>/dev/null; then
|
||||||
|
xtra_params="--timeout=$HEADER_MAXSLEEP --tries=1 --cache=off"
|
||||||
# wget has no proxy command line. We need to use http_proxy instead. And for the sake of simplicity
|
# wget has no proxy command line. We need to use http_proxy instead. And for the sake of simplicity
|
||||||
# assume the GET protocol we query is using http -- http_proxy is the $ENV not for the connection TO
|
# assume the GET protocol we query is using http -- http_proxy is the $ENV not for the connection TO
|
||||||
# the proxy, but for the protocol we query THROUGH the proxy
|
# the proxy, but for the protocol we query THROUGH the proxy
|
||||||
if [[ -z "$PROXY" ]]; then
|
if [[ -z "$PROXY" ]]; then
|
||||||
headers="$(wget --no-proxy -q -S -U $''"$useragent"'' -O /dev/null "$1" 2>&1)"
|
response_headers="$(wget --no-proxy -q -S $xtra_params --header $''"$request_header"'' -U $''"$useragent"'' -O /dev/null "$1" 2>&1)"
|
||||||
else
|
else
|
||||||
if [[ -z "$http_proxy" ]]; then
|
if [[ -z "$http_proxy" ]]; then
|
||||||
headers="$(http_proxy=http://$PROXYIP:$PROXYPORT wget -q -S -U $''"$useragent"'' -O /dev/null "$1" 2>&1)"
|
response_headers="$(http_proxy=http://$PROXYIP:$PROXYPORT wget -q -S $xtra_params --header $''"$request_header"'' -U $''"$useragent"'' -O /dev/null "$1" 2>&1)"
|
||||||
else
|
else
|
||||||
headers="$(wget -q -S -U $''"$useragent"'' -O /dev/null "$1" 2>&1)"
|
response_headers="$(wget -q -S $xtra_params --header $''"$request_header"'' -U $''"$useragent"'' -O /dev/null "$1" 2>&1)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
ret=$?
|
ret=$?
|
||||||
[[ $ret -eq 0 ]] && tm_out "$headers"
|
[[ $ret -eq 0 ]] && tm_out "$response_headers"
|
||||||
# wget(1): "8: Server issued an error response.". Happens e.g. when 404 is returned. However also if the call wasn't correct (400)
|
# wget(1): "8: Server issued an error response.". Happens e.g. when 404 is returned. However also if the call wasn't correct (400)
|
||||||
# So we assume for now that everything is submitted correctly. We parse the error code too later
|
# So we assume for now that everything is submitted correctly. We parse the error code too later
|
||||||
[[ $ret -eq 8 ]] && ret=0 && tm_out "$headers"
|
[[ $ret -eq 8 ]] && ret=0 && tm_out "$response_headers"
|
||||||
return $ret
|
return $ret
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# does a simple http head via printf with no proxy, only used by run_opossum()
|
||||||
|
# arg1: URL
|
||||||
|
# arg2: extra http header
|
||||||
|
#
|
||||||
|
# return codes:
|
||||||
|
# 0: all fine
|
||||||
|
# 1: server dind't respond within HEADER_MAXSLEEP
|
||||||
|
# 3: server dind't respond within HEADER_MAXSLEEP and PROXY was defined
|
||||||
|
#
|
||||||
|
http_header_printf() {
|
||||||
|
local request_header="$2"
|
||||||
|
local useragent="$UA_STD"
|
||||||
|
local tmpfile=$TEMPDIR/$NODE.$NODEIP.http_header_printf.log
|
||||||
|
local errfile=$TEMPDIR/$NODE.$NODEIP.http_header_printf-err.log
|
||||||
|
local -i ret=0
|
||||||
|
local proto="" foo="" node="" query=""
|
||||||
|
|
||||||
|
[[ $DEBUG -eq 0 ]] && errfile=/dev/null
|
||||||
|
|
||||||
|
IFS=/ read -r proto foo node query <<< "$1"
|
||||||
|
exec 33<>/dev/tcp/$node/80
|
||||||
|
printf -- "%b" "HEAD ${proto}//${node}/${query} HTTP/1.1\r\nUser-Agent: ${useragent}\r\nHost: ${node}\r\n${request_header}\r\nAccept: */*\r\n\r\n\r\n" >&33 2>$errfile &
|
||||||
|
wait_kill $! $HEADER_MAXSLEEP
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
# not killed
|
||||||
|
if [[ -n "$PROXY" ]]; then
|
||||||
|
ret=3
|
||||||
|
fi
|
||||||
|
ret=1
|
||||||
|
else
|
||||||
|
ret=0
|
||||||
|
fi
|
||||||
|
if [[ $DEBUG -eq 0 ]] ; then
|
||||||
|
cat <&33
|
||||||
|
else
|
||||||
|
cat <&33 >$tmpfile
|
||||||
|
cat $tmpfile
|
||||||
|
fi
|
||||||
|
exec 33<&-
|
||||||
|
exec 33>&-
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ldap_get() {
|
ldap_get() {
|
||||||
local ldif
|
local ldif
|
||||||
local -i success
|
local -i success
|
||||||
@ -1940,6 +1991,7 @@ ldap_get() {
|
|||||||
# 1 - key not found in database
|
# 1 - key not found in database
|
||||||
# 2 - key found in database
|
# 2 - key found in database
|
||||||
# 7 - network/proxy failure
|
# 7 - network/proxy failure
|
||||||
|
#
|
||||||
check_pwnedkeys() {
|
check_pwnedkeys() {
|
||||||
local cert="$1"
|
local cert="$1"
|
||||||
local cert_key_algo="$2"
|
local cert_key_algo="$2"
|
||||||
@ -1969,7 +2021,7 @@ check_pwnedkeys() {
|
|||||||
fi
|
fi
|
||||||
fingerprint="$($OPENSSL pkey -pubin -outform DER <<< "$pubkey" 2>/dev/null | $OPENSSL dgst -sha256 -hex 2>/dev/null)"
|
fingerprint="$($OPENSSL pkey -pubin -outform DER <<< "$pubkey" 2>/dev/null | $OPENSSL dgst -sha256 -hex 2>/dev/null)"
|
||||||
fingerprint="${fingerprint#*= }"
|
fingerprint="${fingerprint#*= }"
|
||||||
response="$(http_get_header "https://v1.pwnedkeys.com/$fingerprint")"
|
response="$(http_head "https://v1.pwnedkeys.com/$fingerprint")"
|
||||||
# Handle curl's/wget's connectivity exit codes
|
# Handle curl's/wget's connectivity exit codes
|
||||||
case $? in
|
case $? in
|
||||||
4|5|7) return 7 ;;
|
4|5|7) return 7 ;;
|
||||||
@ -9927,7 +9979,7 @@ certificate_info() {
|
|||||||
check_pwnedkeys "$HOSTCERT" "$cert_key_algo" "$cert_keysize"
|
check_pwnedkeys "$HOSTCERT" "$cert_key_algo" "$cert_keysize"
|
||||||
case "$?" in
|
case "$?" in
|
||||||
0) outln "not checked"; fileout "pwnedkeys${json_postfix}" "INFO" "not checked" ;;
|
0) outln "not checked"; fileout "pwnedkeys${json_postfix}" "INFO" "not checked" ;;
|
||||||
1) outln "not in database"; fileout "pwnedkeys${json_postfix}" "INFO" "not in database" ;;
|
1) pr_svrty_good "not in database"; fileout "pwnedkeys${json_postfix}" "OK" "not in database" ;;
|
||||||
2) pr_svrty_critical "NOT ok --"; outln " key appears in database"; fileout "pwnedkeys${json_postfix}" "CRITICAL" "private key is known" ;;
|
2) pr_svrty_critical "NOT ok --"; outln " key appears in database"; fileout "pwnedkeys${json_postfix}" "CRITICAL" "private key is known" ;;
|
||||||
7) prln_warning "error querying https://v1.pwnedkeys.com"; fileout "pwnedkeys${json_postfix}" "WARN" "connection error" ;;
|
7) prln_warning "error querying https://v1.pwnedkeys.com"; fileout "pwnedkeys${json_postfix}" "WARN" "connection error" ;;
|
||||||
esac
|
esac
|
||||||
@ -12212,6 +12264,7 @@ code2network() {
|
|||||||
# sockets inspired by https://blog.chris007.de/using-bash-for-network-socket-operation/
|
# sockets inspired by https://blog.chris007.de/using-bash-for-network-socket-operation/
|
||||||
# ARG1: hexbytes separated by commas, with a leading comma
|
# ARG1: hexbytes separated by commas, with a leading comma
|
||||||
# ARG2: seconds to sleep
|
# ARG2: seconds to sleep
|
||||||
|
#
|
||||||
socksend_clienthello() {
|
socksend_clienthello() {
|
||||||
local data=""
|
local data=""
|
||||||
|
|
||||||
@ -12230,6 +12283,7 @@ socksend_clienthello() {
|
|||||||
|
|
||||||
# ARG1: hexbytes -- preceded by x -- separated by commas, with a leading comma
|
# ARG1: hexbytes -- preceded by x -- separated by commas, with a leading comma
|
||||||
# ARG2: seconds to sleep
|
# ARG2: seconds to sleep
|
||||||
|
#
|
||||||
socksend() {
|
socksend() {
|
||||||
local data line
|
local data line
|
||||||
|
|
||||||
@ -17339,6 +17393,7 @@ run_ccs_injection(){
|
|||||||
|
|
||||||
|
|
||||||
# see https://blog.filippo.io/finding-ticketbleed/ | https://filippo.io/ticketbleed/
|
# see https://blog.filippo.io/finding-ticketbleed/ | https://filippo.io/ticketbleed/
|
||||||
|
#
|
||||||
run_ticketbleed() {
|
run_ticketbleed() {
|
||||||
local tls_hexcode tls_proto=""
|
local tls_hexcode tls_proto=""
|
||||||
local sessticket_tls="" session_tckt_tls=""
|
local sessticket_tls="" session_tckt_tls=""
|
||||||
@ -17363,7 +17418,7 @@ run_ticketbleed() {
|
|||||||
pr_bold " Ticketbleed"; out " ($cve), experiment. "
|
pr_bold " Ticketbleed"; out " ($cve), experiment. "
|
||||||
|
|
||||||
if [[ "$SERVICE" != HTTP ]] && [[ "$CLIENT_AUTH" != required ]]; then
|
if [[ "$SERVICE" != HTTP ]] && [[ "$CLIENT_AUTH" != required ]]; then
|
||||||
outln "(applicable only for HTTPS)"
|
outln "(applicable only for HTTP service)"
|
||||||
fileout "$jsonID" "INFO" "not applicable, not HTTP" "$cve" "$cwe"
|
fileout "$jsonID" "INFO" "not applicable, not HTTP" "$cve" "$cwe"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -17625,6 +17680,55 @@ run_ticketbleed() {
|
|||||||
return $ret
|
return $ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# https://opossum-attack.com/, TLS Upgrade via old RFC 2817
|
||||||
|
#
|
||||||
|
run_opossum() {
|
||||||
|
local cve='CVE-2025-49812'
|
||||||
|
local jsonID="opossum"
|
||||||
|
local cwe="CWE-287"
|
||||||
|
local -i ret=0
|
||||||
|
local uri=$URI
|
||||||
|
local service="$SERVICE"
|
||||||
|
local response=""
|
||||||
|
|
||||||
|
[[ -n "$STARTTLS" ]] && return 0
|
||||||
|
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for Opossum vulnerability " && outln
|
||||||
|
pr_bold " Opossum"; out " ($cve) "
|
||||||
|
|
||||||
|
# we're trying to connect also if ASSUME_HTTP is not set, there should be either one of following hints though
|
||||||
|
if [[ -z $service ]]; then
|
||||||
|
[[ $uri =~ ^http ]] && service=HTTP # https provided as target/URL
|
||||||
|
[[ "$CLIENT_AUTH" == required ]] && service=HTTP # also try when client auth is requested (we dont use it over cleartext)
|
||||||
|
fi
|
||||||
|
case $service in
|
||||||
|
HTTP)
|
||||||
|
uri=${URI/https:\/\//}
|
||||||
|
response=$(http_header_printf http://${uri} 'Upgrade: TLS/1.0\r\n\r\nClose\r\n')
|
||||||
|
# In any case we use $response but we handle the return codes
|
||||||
|
case $? in
|
||||||
|
0) ret=0 ;;
|
||||||
|
1|3) ret=7 ;; # got stuck
|
||||||
|
esac
|
||||||
|
if [[ $response =~ Upgrade:\ TLS ]]; then
|
||||||
|
prln_svrty_high "VULNERABLE (NOT ok)"
|
||||||
|
fileout "$jsonID" "CRITICAL" "VULNERABLE" "$cve" "$cwe" "$hint"
|
||||||
|
else
|
||||||
|
prln_svrty_good "not vulnerable (OK)"
|
||||||
|
fileout "$jsonID" "OK" "not vulnerable $append" "$cve" "$cwe"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
IMAP|FTP|POP3|SMTP|LMTP|NNTP)
|
||||||
|
outln "(implemented currently for HTTP only)"
|
||||||
|
fileout "$jsonID" "INFO" "not yet implemented" "$cve" "$cwe"
|
||||||
|
;;
|
||||||
|
*) outln "(applicable only for HTTP service)"
|
||||||
|
fileout "$jsonID" "INFO" "not applicable, not HTTP" "$cve" "$cwe"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Overview @ http://www.exploresecurity.com/wp-content/uploads/custom/SSL_manual_cheatsheet.html
|
# Overview @ http://www.exploresecurity.com/wp-content/uploads/custom/SSL_manual_cheatsheet.html
|
||||||
#
|
#
|
||||||
run_renego() {
|
run_renego() {
|
||||||
@ -21257,6 +21361,7 @@ single check as <options> ("$PROG_NAME URI" does everything except -E and -g):
|
|||||||
-H, --heartbleed tests for Heartbleed vulnerability
|
-H, --heartbleed tests for Heartbleed vulnerability
|
||||||
-I, --ccs, --ccs-injection tests for CCS injection vulnerability
|
-I, --ccs, --ccs-injection tests for CCS injection vulnerability
|
||||||
-T, --ticketbleed tests for Ticketbleed vulnerability in BigIP loadbalancers
|
-T, --ticketbleed tests for Ticketbleed vulnerability in BigIP loadbalancers
|
||||||
|
--OP, --opossum tests for Opossum vulnerability
|
||||||
--BB, --robot tests for Return of Bleichenbacher's Oracle Threat (ROBOT) vulnerability
|
--BB, --robot tests for Return of Bleichenbacher's Oracle Threat (ROBOT) vulnerability
|
||||||
--SI, --starttls-injection tests for STARTTLS injection issues
|
--SI, --starttls-injection tests for STARTTLS injection issues
|
||||||
-R, --renegotiation tests for renegotiation vulnerabilities
|
-R, --renegotiation tests for renegotiation vulnerabilities
|
||||||
@ -23980,6 +24085,7 @@ initialize_globals() {
|
|||||||
do_breach=false
|
do_breach=false
|
||||||
do_ccs_injection=false
|
do_ccs_injection=false
|
||||||
do_ticketbleed=false
|
do_ticketbleed=false
|
||||||
|
do_opossum=false
|
||||||
do_robot=false
|
do_robot=false
|
||||||
do_cipher_per_proto=false
|
do_cipher_per_proto=false
|
||||||
do_crime=false
|
do_crime=false
|
||||||
@ -24028,6 +24134,7 @@ set_scanning_defaults() {
|
|||||||
do_heartbleed="$OFFENSIVE"
|
do_heartbleed="$OFFENSIVE"
|
||||||
do_ccs_injection="$OFFENSIVE"
|
do_ccs_injection="$OFFENSIVE"
|
||||||
do_ticketbleed="$OFFENSIVE"
|
do_ticketbleed="$OFFENSIVE"
|
||||||
|
do_opossum=true
|
||||||
do_robot="$OFFENSIVE"
|
do_robot="$OFFENSIVE"
|
||||||
do_crime=true
|
do_crime=true
|
||||||
do_freak=true
|
do_freak=true
|
||||||
@ -24048,9 +24155,9 @@ set_scanning_defaults() {
|
|||||||
do_tls_fallback_scsv=true
|
do_tls_fallback_scsv=true
|
||||||
do_client_simulation=true
|
do_client_simulation=true
|
||||||
if "$OFFENSIVE"; then
|
if "$OFFENSIVE"; then
|
||||||
VULN_COUNT=17
|
VULN_COUNT=18
|
||||||
else
|
else
|
||||||
VULN_COUNT=13
|
VULN_COUNT=14
|
||||||
fi
|
fi
|
||||||
do_rating=true
|
do_rating=true
|
||||||
}
|
}
|
||||||
@ -24061,10 +24168,10 @@ count_do_variables() {
|
|||||||
local -i true_nr=0
|
local -i true_nr=0
|
||||||
|
|
||||||
for gbl in do_allciphers do_vulnerabilities do_beast do_lucky13 do_breach do_ccs_injection do_ticketbleed do_cipher_per_proto do_crime \
|
for gbl in do_allciphers do_vulnerabilities do_beast do_lucky13 do_breach do_ccs_injection do_ticketbleed do_cipher_per_proto do_crime \
|
||||||
do_freak do_logjam do_drown do_header do_heartbleed do_mx_all_ips do_fs do_protocols do_rc4 do_starttls_injection do_grease do_robot do_renego \
|
do_freak do_logjam do_drown do_header do_heartbleed do_mx_all_ips do_fs do_protocols do_rc4 do_starttls_injection do_grease \
|
||||||
do_cipherlists do_server_defaults do_server_preference do_ssl_poodle do_tls_fallback_scsv do_winshock \
|
do_opossum do_robot do_renego do_cipherlists do_server_defaults do_server_preference do_ssl_poodle do_tls_fallback_scsv \
|
||||||
do_sweet32 do_client_simulation do_cipher_match do_tls_sockets do_mass_testing do_display_only do_rating; do
|
do_winshock do_sweet32 do_client_simulation do_cipher_match do_tls_sockets do_mass_testing do_display_only do_rating; do
|
||||||
"${!gbl}" && ((true_nr++))
|
"${!gbl}" && ((true_nr++))
|
||||||
done
|
done
|
||||||
return $true_nr
|
return $true_nr
|
||||||
}
|
}
|
||||||
@ -24074,10 +24181,10 @@ debug_globals() {
|
|||||||
local gbl
|
local gbl
|
||||||
|
|
||||||
for gbl in do_allciphers do_vulnerabilities do_beast do_lucky13 do_breach do_ccs_injection do_ticketbleed do_cipher_per_proto do_crime \
|
for gbl in do_allciphers do_vulnerabilities do_beast do_lucky13 do_breach do_ccs_injection do_ticketbleed do_cipher_per_proto do_crime \
|
||||||
do_freak do_logjam do_drown do_header do_heartbleed do_mx_all_ips do_fs do_protocols do_rc4 do_starttls_injection do_grease do_robot do_renego \
|
do_freak do_logjam do_drown do_header do_heartbleed do_mx_all_ips do_fs do_protocols do_rc4 do_starttls_injection do_grease\
|
||||||
do_cipherlists do_server_defaults do_server_preference do_ssl_poodle do_tls_fallback_scsv do_winshock \
|
do_opossum do_robot do_renego do_cipherlists do_server_defaults do_server_preference do_ssl_poodle do_tls_fallback_scsv \
|
||||||
do_sweet32 do_client_simulation do_cipher_match do_tls_sockets do_mass_testing do_display_only do_rating; do
|
do_winshock do_sweet32 do_client_simulation do_cipher_match do_tls_sockets do_mass_testing do_display_only do_rating; do
|
||||||
printf "%-22s = %s\n" $gbl "${!gbl}"
|
printf "%-22s = %s\n" $gbl "${!gbl}"
|
||||||
done
|
done
|
||||||
# ${!var} is an indirect expansion, see https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
|
# ${!var} is an indirect expansion, see https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
|
||||||
# Example: https://stackoverflow.com/questions/8515411/what-is-indirect-expansion-what-does-var-mean#8515492
|
# Example: https://stackoverflow.com/questions/8515411/what-is-indirect-expansion-what-does-var-mean#8515492
|
||||||
@ -24283,6 +24390,7 @@ parse_cmd_line() {
|
|||||||
do_heartbleed="$OFFENSIVE"
|
do_heartbleed="$OFFENSIVE"
|
||||||
do_ccs_injection="$OFFENSIVE"
|
do_ccs_injection="$OFFENSIVE"
|
||||||
do_ticketbleed="$OFFENSIVE"
|
do_ticketbleed="$OFFENSIVE"
|
||||||
|
do_opossum=true
|
||||||
do_robot="$OFFENSIVE"
|
do_robot="$OFFENSIVE"
|
||||||
do_renego=true
|
do_renego=true
|
||||||
do_crime=true
|
do_crime=true
|
||||||
@ -24299,9 +24407,9 @@ parse_cmd_line() {
|
|||||||
do_rc4=true
|
do_rc4=true
|
||||||
do_starttls_injection=true
|
do_starttls_injection=true
|
||||||
if "$OFFENSIVE"; then
|
if "$OFFENSIVE"; then
|
||||||
VULN_COUNT=17
|
VULN_COUNT=18
|
||||||
else
|
else
|
||||||
VULN_COUNT=13
|
VULN_COUNT=14
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
--ids-friendly)
|
--ids-friendly)
|
||||||
@ -24319,6 +24427,10 @@ parse_cmd_line() {
|
|||||||
do_ticketbleed=true
|
do_ticketbleed=true
|
||||||
((VULN_COUNT++))
|
((VULN_COUNT++))
|
||||||
;;
|
;;
|
||||||
|
--OP|--opossum)
|
||||||
|
do_opossum=true
|
||||||
|
((VULN_COUNT++))
|
||||||
|
;;
|
||||||
-BB|--BB|--robot)
|
-BB|--BB|--robot)
|
||||||
do_robot=true
|
do_robot=true
|
||||||
;;
|
;;
|
||||||
@ -24984,6 +25096,7 @@ lets_roll() {
|
|||||||
"$do_heartbleed" && { run_heartbleed; ret=$(($? + ret)); stopwatch run_heartbleed; }
|
"$do_heartbleed" && { run_heartbleed; ret=$(($? + ret)); stopwatch run_heartbleed; }
|
||||||
"$do_ccs_injection" && { run_ccs_injection; ret=$(($? + ret)); stopwatch run_ccs_injection; }
|
"$do_ccs_injection" && { run_ccs_injection; ret=$(($? + ret)); stopwatch run_ccs_injection; }
|
||||||
"$do_ticketbleed" && { run_ticketbleed; ret=$(($? + ret)); stopwatch run_ticketbleed; }
|
"$do_ticketbleed" && { run_ticketbleed; ret=$(($? + ret)); stopwatch run_ticketbleed; }
|
||||||
|
"$do_opossum" && { run_opossum; ret=$(($? + ret)); stopwatch run_opossum; }
|
||||||
"$do_robot" && { run_robot; ret=$(($? + ret)); stopwatch run_robot; }
|
"$do_robot" && { run_robot; ret=$(($? + ret)); stopwatch run_robot; }
|
||||||
"$do_renego" && { run_renego; ret=$(($? + ret)); stopwatch run_renego; }
|
"$do_renego" && { run_renego; ret=$(($? + ret)); stopwatch run_renego; }
|
||||||
"$do_crime" && { run_crime; ret=$(($? + ret)); stopwatch run_crime; }
|
"$do_crime" && { run_crime; ret=$(($? + ret)); stopwatch run_crime; }
|
||||||
|
Reference in New Issue
Block a user