Shortcuts for vulnerability tests

Several vulnerability checks add a time penalty when the server
side only support TLS 1.3 as The TLS 1.3 RFC 8446 and implementations
known so far don't support the flaws being checked for.

This PR adds "shortcut" checks for all TLS 1.3, assuming that the
TLS 1.3 implementation is correct which seems at this time a valid
assumpution. That either saves a TCP connect or at least some logic to
be executed.  Also in some cases a TLS 1.3 only server emitted unnecessary
warnings, see #1444.

If $DEBUG -eq 1 then it outputs information that a shortcut was
used. It doesn't do that in other cases because the screen output
seems too obtrusive.

It also adds a shortcut for beast when SSL 3 or TLS 1.0 is is known
not to be supported.

This commit radds 747fb039ed which
was accidenially reverted in 45f28d8166.
It fixes #1462.

See also #1459.
This commit is contained in:
Dirk 2020-01-20 21:37:02 +01:00
parent c08250d1bb
commit 952231dd94
1 changed files with 123 additions and 49 deletions

View File

@ -12480,7 +12480,7 @@ parse_tls_serverhello() {
# If the ClientHello included a supported_versions extension, then check that the
# $DETECTED_TLS_VERSION appeared in the list offered in the ClientHello.
if [[ "${TLS_CLIENT_HELLO:0:2}" == "01" ]]; then
if [[ "${TLS_CLIENT_HELLO:0:2}" == 01 ]]; then
# get position of cipher lists (just after session id)
offset=78+2*$(hex2dec "${TLS_CLIENT_HELLO:76:2}")
# get position of compression methods
@ -12496,7 +12496,7 @@ parse_tls_serverhello() {
offset+=6
tls_protocol2="$(tolower "$tls_protocol2")"
for (( j=0; j < extension_len-2; j=j+4 )); do
[[ "${TLS_CLIENT_HELLO:offset:4}" == "$tls_protocol2" ]] && break
[[ "${TLS_CLIENT_HELLO:offset:4}" == $tls_protocol2 ]] && break
offset+=4
done
if [[ $j -eq $extension_len-2 ]]; then
@ -14333,27 +14333,36 @@ run_renego() {
pr_bold " Secure Renegotiation (RFC 5746) "
jsonID="secure_renego"
# first fingerprint for the Line "Secure Renegotiation IS NOT" or "Secure Renegotiation IS "
$OPENSSL s_client $(s_client_options "$proto $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY") 2>&1 </dev/null >$TMPFILE 2>$ERRFILE
if sclient_connect_successful $? $TMPFILE; then
grep -iaq "Secure Renegotiation IS NOT" $TMPFILE
sec_renego=$? # 0= Secure Renegotiation IS NOT supported
# grep -iaq "Secure Renegotiation IS supported"
#FIXME: didn't occur to me yet but why not also to check on "Secure Renegotiation IS supported"
case $sec_renego in
0) prln_svrty_critical "Not supported / VULNERABLE (NOT ok)"
fileout "$jsonID" "CRITICAL" "VULNERABLE" "$cve" "$cwe" "$hint"
;;
1) prln_svrty_best "supported (OK)"
fileout "$jsonID" "OK" "supported" "$cve" "$cwe"
;;
*) prln_warning "FIXME (bug): $sec_renego"
fileout "$jsonID" "WARN" "FIXME (bug) $sec_renego" "$cve" "$cwe"
;;
esac
if "$TLS13_ONLY"; then
# https://www.openssl.org/blog/blog/2018/02/08/tlsv1.3/
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no renegotiation support in TLS 1.3 only servers"
outln
fileout "$jsonID" "OK" "TLS 1.3 only server" "$cve" "$cwe"
else
prln_warning "OpenSSL handshake didn't succeed"
fileout "$jsonID" "WARN" "OpenSSL handshake didn't succeed" "$cve" "$cwe"
# first fingerprint for the Line "Secure Renegotiation IS NOT" or "Secure Renegotiation IS "
$OPENSSL s_client $(s_client_options "$proto $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY") 2>&1 </dev/null >$TMPFILE 2>$ERRFILE
if sclient_connect_successful $? $TMPFILE; then
grep -iaq "Secure Renegotiation IS NOT" $TMPFILE
sec_renego=$? # 0= Secure Renegotiation IS NOT supported
# grep -iaq "Secure Renegotiation IS supported"
#FIXME: didn't occur to me yet but why not also to check on "Secure Renegotiation IS supported"
case $sec_renego in
0) prln_svrty_critical "Not supported / VULNERABLE (NOT ok)"
fileout "$jsonID" "CRITICAL" "VULNERABLE" "$cve" "$cwe" "$hint"
;;
1) prln_svrty_best "supported (OK)"
fileout "$jsonID" "OK" "supported" "$cve" "$cwe"
;;
*) prln_warning "FIXME (bug): $sec_renego"
fileout "$jsonID" "WARN" "FIXME (bug) $sec_renego" "$cve" "$cwe"
;;
esac
else
prln_warning "OpenSSL handshake didn't succeed"
fileout "$jsonID" "WARN" "OpenSSL handshake didn't succeed" "$cve" "$cwe"
fi
fi
# FIXME: Basically this can be done with sockets and we might have that information already
@ -14368,7 +14377,8 @@ run_renego() {
cve="CVE-2011-1473"
# see: https://blog.qualys.com/ssllabs/2011/10/31/tls-renegotiation-and-denial-of-service-attacks
# http://blog.ivanristic.com/2009/12/testing-for-ssl-renegotiation.html -- head/get doesn't seem to be needed though
# https://archive.fo/20130415224936/http://www.thc.org/thc-ssl-dos/, https://vincent.bernat.ch/en/blog/2011-ssl-dos-mitigation
# https://archive.fo/20130415224936/http://www.thc.org/thc-ssl-dos/
# https://vincent.bernat.ch/en/blog/2011-ssl-dos-mitigation
case "$OSSL_VER" in
0.9.8*) # we need this for Mac OSX unfortunately
case "$OSSL_VER_APPENDIX" in
@ -14389,7 +14399,12 @@ run_renego() {
esac
if "$CLIENT_AUTH"; then
if "$TLS13_ONLY"; then
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no renegotiation support in TLS 1.3 only servers"
outln
fileout "$jsonID" "OK" "not vulnerable, TLS 1.3 only" "$cve" "$cwe"
elif "$CLIENT_AUTH"; then
prln_warning "client x509-based authentication prevents this from being tested"
fileout "$jsonID" "WARN" "client x509-based authentication prevents this from being tested"
sec_client_renego=1
@ -14404,7 +14419,7 @@ run_renego() {
sec_client_renego=1
else
# second try in the foreground as we are sure now it won't hang
echo R | $OPENSSL s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -msg -connect $NODEIP:$PORT $PROXY") >$TMPFILE 2>>$ERRFILE
echo R | $OPENSSL s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY") >$TMPFILE 2>>$ERRFILE
sec_client_renego=$? # 0=client is renegotiating & doesn't return an error --> vuln!
case "$sec_client_renego" in
0) # We try again if server is HTTP. This could be either a node.js server or something else.
@ -14415,7 +14430,7 @@ run_renego() {
fileout "$jsonID" "MEDIUM" "VULNERABLE, potential DoS threat" "$cve" "$cwe" "$hint"
else
(for i in {1..4}; do echo R; sleep 1; done) | \
$OPENSSL s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -msg -connect $NODEIP:$PORT $PROXY") >$TMPFILE 2>>$ERRFILE
$OPENSSL s_client $(s_client_options "$proto $legacycmd $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY") >$TMPFILE 2>>$ERRFILE
case $? in
0) pr_svrty_high "VULNERABLE (NOT ok)"; outln ", DoS threat"
fileout "$jsonID" "HIGH" "VULNERABLE, DoS threat" "$cve" "$cwe" "$hint"
@ -14461,15 +14476,23 @@ run_crime() {
local cwe="CWE-310"
local hint=""
# in a nutshell: don't offer TLS/SPDY compression on the server side
# This tests for CRIME Vulnerability (www.ekoparty.org/2012/juliano-rizzo.php) on HTTPS, not SPDY (yet)
# Please note that it is an attack where you need client side control, so in regular situations this
# means anyway "game over", w/wo CRIME
# www.h-online.com/security/news/item/Vulnerability-in-SSL-encryption-is-barely-exploitable-1708604.html
# In a nutshell: don't offer TLS/SPDY compression. This tests for CRIME Vulnerability on HTTPS only,
# not SPDY or ALPN (yet). Please note that it is an attack where you need client side control, so in
# regular situations this # means anyway "game over", with or without CRIME.
#
# https://blog.qualys.com/ssllabs/2012/09/14/crime-information-leakage-attack-against-ssltls
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for CRIME vulnerability " && outln
pr_bold " CRIME, TLS " ; out "($cve) "
if "$TLS13_ONLY"; then
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no compression in TLS 1.3 only servers"
outln
fileout "$jsonID" "OK" "TLS 1.3 only server" "$cve" "$cwe"
return 0
fi
if ! "$HAS_ZLIB"; then
if "$SSL_NATIVE"; then
prln_local_problem "$OPENSSL lacks zlib support"
@ -14488,20 +14511,21 @@ run_crime() {
sclient_connect_successful $? $TMPFILE
sclient_success=$?
fi
if [[ $sclient_success -ne 0 ]]; then
pr_warning "test failed (couldn't connect)"
fileout "CRIME_TLS" "WARN" "Check failed, couldn't connect" "$cve" "$cwe"
ret=1
elif grep -a Compression $TMPFILE | grep -aq NONE >/dev/null; then
pr_svrty_good "not vulnerable (OK)"
if [[ $SERVICE != "HTTP" ]] && ! "$CLIENT_AUTH"; then
if [[ $SERVICE != HTTP ]] && ! "$CLIENT_AUTH"; then
out " (not using HTTP anyway)"
fileout "CRIME_TLS" "OK" "not vulnerable (not using HTTP anyway)" "$cve" "$cwe"
else
fileout "CRIME_TLS" "OK" "not vulnerable" "$cve" "$cwe"
fi
else
if [[ $SERVICE == "HTTP" ]] || "$CLIENT_AUTH"; then
if [[ $SERVICE == HTTP ]] || "$CLIENT_AUTH"; then
pr_svrty_high "VULNERABLE (NOT ok)"
fileout "CRIME_TLS" "HIGH" "VULNERABLE" "$cve" "$cwe" "$hint"
else
@ -14646,13 +14670,21 @@ run_sweet32() {
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for SWEET32 (Birthday Attacks on 64-bit Block Ciphers) " && outln
pr_bold " SWEET32"; out " (${cve// /, }) "
if "$TLS13_ONLY"; then
# Unfortunately there's no restriction using TLS 1.2 with $sweet32_ciphers
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", TLS 1.3 doesn't offer such ciphers"
outln
fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe"
return 0
fi
"$SSL_NATIVE" && using_sockets=false
# The openssl binary distributed has almost everything we need (PSK, KRB5 ciphers and feff, ffe0 are typically missing).
# Measurements show that there's little impact whether we use sockets or TLS here, so the default is sockets here
# Measurements show that there's little impact whether we use sockets or TLS here, so the default is sockets here.
if "$using_sockets"; then
for proto in 03 02 01 00; do
"$FAST" && [[ "$proto" != 03 ]] && break
! "$FAST" && [[ $(has_server_protocol "$proto") -eq 1 ]] && continue
[[ $(has_server_protocol "$proto") -eq 1 ]] && continue
tls_sockets "$proto" "${sweet32_ciphers_hex}, 00,ff"
sclient_success=$?
[[ $sclient_success -eq 2 ]] && sclient_success=0
@ -14766,6 +14798,15 @@ run_ssl_poodle() {
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for SSLv3 POODLE (Padding Oracle On Downgraded Legacy Encryption) " && outln
pr_bold " POODLE, SSL"; out " ($cve) "
if "$TLS13_ONLY" || [[ $(has_server_protocol ssl3) -ne 0 ]]; then
# one condition should normally suffice but we don't know when run_poddle() was called
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no SSLv3 support"
outln
fileout "$jsonID" "OK" "not vulnerable, no SSLv3 support" "$cve" "$cwe"
return 0
fi
"$SSL_NATIVE" && using_sockets=false
# The openssl binary distributed has almost everything we need (PSK and KRB5 ciphers are typically missing).
# Measurements show that there's little impact whether we use sockets or TLS here, so the default is sockets here
@ -14878,10 +14919,9 @@ run_tls_fallback_scsv() {
return 0
;;
*) if [[ $(has_server_protocol tls1_3) -eq 0 ]]; then
# If the server supports TLS 1.3, and does not support TLS 1.2, TLS 1.1,
# or TLS 1, then assume it does not support SSLv3, even if SSLv3 cannot
# be tested.
prln_svrty_good "No fallback possible, TLS 1.3 is the only protocol (OK)"
# If the server supports TLS 1.3, and does not support TLS 1.2, TLS 1.1, or TLS 1,
# then assume it does not support SSLv3, even if SSLv3 cannot be tested.
pr_svrty_good "No fallback possible (OK)"; outln ", TLS 1.3 is the only protocol"
fileout "$jsonID" "OK" "only TLS 1.3 supported"
elif [[ $(has_server_protocol tls1_3) -eq 1 ]] && \
( [[ $(has_server_protocol ssl3) -eq 1 ]] || "$HAS_SSL3" ); then
@ -14894,8 +14934,8 @@ run_tls_fallback_scsv() {
# If the server does not support TLS 1.3, TLS 1.2, TLS 1.1, or TLS 1, and
# support for SSLv3 cannot be tested, then treat it as HIGH severity, since
# it is very likely that SSLv3 is the only supported protocol.
prln_svrty_high "No fallback possible, TLS 1.3, TLS 1.2, TLS 1.1, and TLS 1 not supported"
fileout "$jsonID" "HIGH" "TLS 1.3, TLS 1.2, TLS 1.1, and TLS 1 not supported"
pr_svrty_high "NOT ok, no fallback possible"; outln ", TLS 1.3, 1.2, 1.1 and 1.0 not supported"
fileout "$jsonID" "HIGH" "TLS 1.3, 1.2, 1.1, 1.0 not supported"
else
# TLS 1.2, TLS 1.1, and TLS 1 are not supported, but can't tell whether TLS 1.3 is supported.
# This could be a TLS 1.3 only server, an SSLv3 only server (if SSLv3 support cannot be tested),
@ -14924,7 +14964,7 @@ run_tls_fallback_scsv() {
if ! "$HAS_SSL3" && \
( [[ "$low_proto" == ssl3 ]] || \
( [[ "$high_proto" == tls1 ]] && [[ $(has_server_protocol "ssl3") -eq 2 ]] ) ); then
( [[ "$high_proto" == tls1 ]] && [[ $(has_server_protocol ssl3) -eq 2 ]] ) ); then
# If the protocol that the server would fall back to is SSLv3, but $OPENSSL does
# not support SSLv3, then the test cannot be performed. So, if $OPENSSL does not
# support SSLv3 and it is known that SSLv3 is the fallback protocol ($low_proto), then
@ -14941,7 +14981,7 @@ run_tls_fallback_scsv() {
if [[ -z "$low_proto" ]]; then
case "$high_proto" in
"tls1_2")
prln_svrty_good "No fallback possible, no protocol below $high_proto_str offered (OK)"
pr_svrty_good "No fallback possible (OK)"; outln ", no protocol below $high_proto_str offered"
;;
*) outln "No fallback possible, no protocol below $high_proto_str offered (OK)"
;;
@ -15026,6 +15066,14 @@ run_freak() {
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for FREAK attack " && outln
pr_bold " FREAK"; out " ($cve) "
if "$TLS13_ONLY"; then
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", TLS 1.3 only server"
outln
fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe"
return 0
fi
"$SSL_NATIVE" && using_sockets=false
if "$using_sockets"; then
nr_supported_ciphers=$(count_words "$exportrsa_tls_cipher_list_hex")+$(count_words "$exportrsa_ssl2_cipher_list_hex")
@ -15473,7 +15521,6 @@ run_beast(){
local hint=""
local jsonID="BEAST"
"$SSL_NATIVE" && using_sockets=false
if [[ $VULN_COUNT -le $VULN_THRESHLD ]]; then
outln
pr_headlineln " Testing for BEAST vulnerability "
@ -15481,8 +15528,17 @@ run_beast(){
fi
pr_bold " BEAST"; out " ($cve) "
if "$TLS13_ONLY" || ( [[ $(has_server_protocol ssl3) -eq 1 ]] && [[ $(has_server_protocol tls1) -eq 1 ]] ); then
pr_svrty_good "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no SSL3 or TLS1"
outln
fileout "$jsonID" "OK" "not vulnerable, no SSL3 or TLS1" "$cve" "$cwe"
return 0
fi
"$SSL_NATIVE" && using_sockets=false
# $cbc_ciphers_hex has 126 ciphers, we omitted SRP-AES-256-CBC-SHA bc the trailing 00,ff below will pose
# a problem for ACE loadbalancers otherwise. So in case we know this is not true, we'll re-add it
# a problem for ACE loadbalancers otherwise. So in case we know this is not true, we'll re-add it
! "$SERVER_SIZE_LIMIT_BUG" & "$using_sockets" && cbc_ciphers_hex="$cbc_ciphers_hex, C0,20"
[[ $TLS_NR_CIPHERS == 0 ]] && using_sockets=false
@ -15564,12 +15620,14 @@ run_beast(){
if [[ $sclient_success -ne 0 ]]; then # protocol supported?
if "$continued"; then # second round: we hit TLS1
if "$HAS_SSL3" || "$using_sockets"; then
prln_svrty_good "no SSL3 or TLS1 (OK)"
pr_svrty_good "not vulnerable (OK)" ; out ", no SSL3 or TLS1"
fileout "$jsonID" "OK" "not vulnerable, no SSL3 or TLS1" "$cve" "$cwe"
else
prln_svrty_good "no TLS1 (OK)"
fileout "$jsonID" "OK" "not vulnerable, no TLS1" "$cve" "$cwe"
fi
set +x
exit 0
return 0
else # protocol not succeeded but it's the first time
continued=true
@ -15597,7 +15655,7 @@ run_beast(){
sigalg[nr_ciphers]=""
done
while true; do
[[ "$proto" == "ssl3" ]] && ! "$HAS_SSL3" && break
[[ "$proto" == ssl3 ]] && ! "$HAS_SSL3" && break
ciphers_to_test=""
for (( i=0; i < nr_ciphers; i++ )); do
! "${ciphers_found[i]}" && "${ossl_supported[i]}" && ciphers_to_test+=":${ciph[i]}"
@ -15695,7 +15753,7 @@ run_beast(){
detected_cbc_ciphers="" # empty for next round
first=false
else
[[ $proto == "tls1" ]] && ! $first && echo -n "$spaces "
[[ $proto == tls1 ]] && ! $first && echo -n "$spaces "
prln_svrty_good "no CBC ciphers for $(toupper $proto) (OK)"
first=false
fi
@ -15762,6 +15820,14 @@ run_lucky13() {
fi
pr_bold " LUCKY13"; out " ($cve), experimental "
if "$TLS13_ONLY"; then
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no CBC ciphers in TLS 1.3 only servers"
outln
fileout "$jsonID" "OK" "not vulnerable, TLS 1.3 only" "$cve" "$cwe"
return 0
fi
"$SSL_NATIVE" && using_sockets=false
# The openssl binary distributed has almost everything we need (PSK, KRB5 ciphers and feff, ffe0 are typically missing).
# Measurements show that there's little impact whether we use sockets or TLS here, so the default is sockets here
@ -15841,6 +15907,14 @@ run_rc4() {
fi
pr_bold " RC4"; out " (${cve// /, }) "
if "$TLS13_ONLY"; then
pr_svrty_best "not vulnerable (OK)"
[[ $DEBUG -ge 1 ]] && out ", no RC4 support in TLS 1.3 only servers"
outln
fileout "$jsonID" "OK" "not vulnerable, TLS 1.3 only" "$cve" "$cwe"
return 0
fi
# get a list of all the cipher suites to test
if "$using_sockets" || [[ $OSSL_VER_MAJOR -lt 1 ]]; then
for (( i=0; i < TLS_NR_CIPHERS; i++ )); do