- VERBOSE -eq 1 is now DEBUG -eq 2 (VERBOSE completely removed)

- DEBUG has now four modes 1: just keep files 2: VERBOSE -eq 1 3: head hexdumps and other stuff, 4: full debugging
- env and internal stuff $TEMPDIR
This commit is contained in:
Dirk 2015-01-21 12:53:00 +01:00
parent 82764845f2
commit 6c6511ddb2

View File

@ -47,7 +47,7 @@ SWCONTACT="dirk aet testssl dot sh"
CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet. FC has only a CA bundle per default, ==> openssl version -d CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet. FC has only a CA bundle per default, ==> openssl version -d
ECHO="/usr/bin/printf --" # works under Linux, BSD, MacOS. ECHO="/usr/bin/printf --" # works under Linux, BSD, MacOS.
COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all
SHOW_LOC_CIPH=${SHOW_LOC_CIPH}=0 # determines whether the client side ciphers are displayed at all (makes no sense normally) SHOW_LOC_CIPH=${SHOW_LOC_CIPH:-0} # determines whether the client side ciphers are displayed at all (makes no sense normally)
VERBERR=${VERBERR:-1} # 0 means to be more verbose (some like the errors to be dispayed so that one can tell better VERBERR=${VERBERR:-1} # 0 means to be more verbose (some like the errors to be dispayed so that one can tell better
# whether handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1 # whether handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1
LOCERR=${LOCERR:-0} # displays the local error LOCERR=${LOCERR:-0} # displays the local error
@ -56,11 +56,8 @@ SNEAKY=${SNEAKY:-1} # if zero: the referer and useragent we leave while chec
#FIXME: consequently we should mute the initial openssl s_client -connect as they cause a 400 (nginx, apache) #FIXME: consequently we should mute the initial openssl s_client -connect as they cause a 400 (nginx, apache)
#FIXME: still to be filled with (more) sense: #FIXME: still to be filled with (more) sense:
DEBUG=${DEBUG:-0} # if 1 the temp files won't be erased. Currently only keeps the last output for TMFILE DEBUG=${DEBUG:-0} # if 1 the temp files won't be erased. 2: list more what's going on (formerly: eq VERBOSE=1), 3: slight hexdumps
TEMPDIR="" # and other info, 4: the whole nine yards of output
VERBOSE=${VERBOSE:-0} # if 1 it shows what's going on. Currently only used for heartbleed and ccs injection
VERB_CLIST="" # ... and if so, "-V" shows them row by row cipher, SSL-version, KX, Au, Enc and Mac
HSTS_MIN=180 # >180 days is ok for HSTS HSTS_MIN=180 # >180 days is ok for HSTS
HPKP_MIN=30 # >=30 days should be ok for HPKP_MIN, practical hints? HPKP_MIN=30 # >=30 days should be ok for HPKP_MIN, practical hints?
MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply
@ -68,7 +65,8 @@ CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS
DAYS2WARN1=60 # days to warn before cert expires, threshold 1 DAYS2WARN1=60 # days to warn before cert expires, threshold 1
DAYS2WARN2=30 # days to warn before cert expires, threshold 2 DAYS2WARN2=30 # days to warn before cert expires, threshold 2
# more global vars, empty: # more global vars, here just declared
TEMPDIR=""
TLS_PROTO_OFFERED="" TLS_PROTO_OFFERED=""
SOCKREPLY="" SOCKREPLY=""
HEXC="" HEXC=""
@ -470,7 +468,15 @@ serverbanner() {
outln "no HTTP header, interesting!" outln "no HTTP header, interesting!"
fi fi
tmpfile_handle $FUNCNAME.txt
return $?
}
applicationbanner() {
bold " Application " bold " Application "
if [ ! -s $HEADERFILE ] ; then
http_header "$1" || return 3
fi
# examples: dev.testssl.sh, php.net, asp.net , www.regonline.com # examples: dev.testssl.sh, php.net, asp.net , www.regonline.com
egrep -ai '^X-Powered-By|^X-AspNet-Version|^X-Runtime|^X-Version' $HEADERFILE >$TMPFILE egrep -ai '^X-Powered-By|^X-AspNet-Version|^X-Runtime|^X-Version' $HEADERFILE >$TMPFILE
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
@ -578,7 +584,7 @@ prettyprint_local() {
# list ciphers (and makes sure you have them locally configured) # list ciphers (and makes sure you have them locally configured)
# arg[1]: cipher list (or anything else) # arg[1]: cipher list (or anything else)
listciphers() { listciphers() {
$OPENSSL ciphers "$VERB_CLIST" $1 &>$TMPFILE $OPENSSL ciphers $1 &>$TMPFILE
ret=$? ret=$?
[[ $LOCERR -eq 1 ]] && cat $TMPFILE [[ $LOCERR -eq 1 ]] && cat $TMPFILE
@ -596,7 +602,7 @@ std_cipherlists() {
[ $SHOW_LOC_CIPH = "1" ] && out "local ciphers are: " && cat $TMPFILE | sed 's/:/, /g' [ $SHOW_LOC_CIPH = "1" ] && out "local ciphers are: " && cat $TMPFILE | sed 's/:/, /g'
$OPENSSL s_client -cipher "$1" $STARTTLS -connect $NODEIP:$PORT $SNI 2>$TMPFILE >/dev/null </dev/null $OPENSSL s_client -cipher "$1" $STARTTLS -connect $NODEIP:$PORT $SNI 2>$TMPFILE >/dev/null </dev/null
ret=$? ret=$?
[[ $VERBOSE -eq 1 ]] && cat $TMPFILE [[ $DEBUG -eq 2 ]] && cat $TMPFILE
case $3 in case $3 in
0) # ok to offer 0) # ok to offer
if [[ $ret -eq 0 ]]; then # was offered if [[ $ret -eq 0 ]]; then # was offered
@ -625,7 +631,7 @@ std_cipherlists() {
fi fi
# we need lf in those cases: # we need lf in those cases:
[[ $LOCERR -eq 1 ]] && echo [[ $LOCERR -eq 1 ]] && echo
[[ $VERBOSE -eq 1 ]] && echo [[ $DEBUG -eq 2 ]] && echo
} }
@ -635,7 +641,7 @@ std_cipherlists() {
socksend() { socksend() {
# the following works under BSD and Linux, which is quite tricky. So don't mess with it unless you're really sure what you do # the following works under BSD and Linux, which is quite tricky. So don't mess with it unless you're really sure what you do
data=`echo "$1" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\\/g' | tr -d '\n'` data=`echo "$1" | sed -e 's/# .*$//g' -e 's/ //g' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//; /^$/d' | sed 's/,/\\\/g' | tr -d '\n'`
[ $VERBOSE -eq 1 ] && echo "\"$data\"" [[ $DEBUG -ge 4 ]] && echo "\"$data\""
printf -- "$data" >&5 2>/dev/null & printf -- "$data" >&5 2>/dev/null &
sleep $2 sleep $2
} }
@ -920,7 +926,7 @@ server_preference() {
green "yes (OK)" green "yes (OK)"
remark4default_cipher="" remark4default_cipher=""
fi fi
[[ $VERBOSE -eq 1 ]] && out " $cipher1 | $cipher2" [[ $DEBUG -eq 2 ]] && out " $cipher1 | $cipher2"
outln outln
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $SNI </dev/null 2>/dev/null >$TMPFILE
@ -957,7 +963,7 @@ server_preference() {
proto[i]=`grep -w "Protocol" $TMPFILE | sed -e 's/^ \+Protocol \+://' -e 's/ //g'` proto[i]=`grep -w "Protocol" $TMPFILE | sed -e 's/^ \+Protocol \+://' -e 's/ //g'`
cipher[i]=`grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'` cipher[i]=`grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'`
[[ ${cipher[i]} == "0000" ]] && cipher[i]="" # Hack! [[ ${cipher[i]} == "0000" ]] && cipher[i]="" # Hack!
[[ $VERBOSE -eq 1 ]] && outln "Default cipher for ${proto[i]}: ${cipher[i]}" [[ $DEBUG -eq 2 ]] && outln "Default cipher for ${proto[i]}: ${cipher[i]}"
else else
proto[i]="" proto[i]=""
cipher[i]="" cipher[i]=""
@ -973,7 +979,7 @@ server_preference() {
cipher[i]="" cipher[i]=""
else else
cipher[i]=`grep -aw "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'` cipher[i]=`grep -aw "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g'`
[[ $VERBOSE -eq 1 ]] && outln "Default cipher for ${proto[i]}: ${cipher[i]}" [[ $DEBUG -eq 2 ]] && outln "Default cipher for ${proto[i]}: ${cipher[i]}"
fi fi
fi fi
fi fi
@ -1067,7 +1073,7 @@ server_defaults() {
CN_nosni=`$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT 2>/dev/null </dev/null | awk '/-----BEGIN/,/-----END/ { print $0 }' | \ CN_nosni=`$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT 2>/dev/null </dev/null | awk '/-----BEGIN/,/-----END/ { print $0 }' | \
$OPENSSL x509 -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//'` $OPENSSL x509 -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//'`
[[ $VERBOSE -eq 1 ]] && out "$NODE | $CN | $CN_nosni" [[ $DEBUG -eq 2 ]] && out "$NODE | $CN | $CN_nosni"
if [[ $NODE == $CN_nosni ]]; then if [[ $NODE == $CN_nosni ]]; then
outln " (works w/o SNI)" outln " (works w/o SNI)"
else else
@ -1232,14 +1238,15 @@ pfs() {
rc4() { rc4() {
shopt -s lastpipe shopt -s lastpipe # otherwise it's more tricky to access variables in a while loop
outln outln
blue "--> Checking RC4 Ciphers" ; outln blue "--> Checking RC4 Ciphers" ; outln
$OPENSSL ciphers -V 'RC4:@STRENGTH' >$TMPFILE $OPENSSL ciphers -V 'RC4:@STRENGTH' >$TMPFILE
[ $SHOW_LOC_CIPH = "1" ] && echo "local ciphers available for testing RC4:" && echo `cat $TMPFILE` [ $SHOW_LOC_CIPH = "1" ] && echo "local ciphers available for testing RC4:" && echo `cat $TMPFILE`
$OPENSSL s_client -cipher `$OPENSSL ciphers RC4` $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null </dev/null $OPENSSL s_client -cipher `$OPENSSL ciphers RC4` $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null </dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
litered "\nRC4 seems generally available. Now testing specific ciphers..."; outln "\n" literedln "\nRC4 is broken. It seems generally available. Now testing specific ciphers...";
outln "(for legacy support (e.g. IE6) rather consider x13 or x0a)\n"
bad=1 bad=1
neat_header neat_header
cat $TMPFILE | while read hexcode n ciph sslvers kx auth enc mac; do cat $TMPFILE | while read hexcode n ciph sslvers kx auth enc mac; do
@ -1265,14 +1272,15 @@ rc4() {
# https://en.wikipedia.org/wiki/Transport_Layer_Security#RC4_attacks # https://en.wikipedia.org/wiki/Transport_Layer_Security#RC4_attacks
# http://blog.cryptographyengineering.com/2013/03/attack-of-week-rc4-is-kind-of-broken-in.html # http://blog.cryptographyengineering.com/2013/03/attack-of-week-rc4-is-kind-of-broken-in.html
outln outln
outln "RC4 is broken, for legacy support (IE6) rather consider x13 or x0a"
else else
outln outln
litegreenln "no RC4 ciphers detected (OK)" litegreenln "no RC4 ciphers detected (OK)"
bad=0 bad=0
fi fi
shopt -u lastpipe shopt -u lastpipe # othwise for some reason it segfaults
# FIXME: still segfaults: see https://www.mail-archive.com/bug-bash@gnu.org/msg14428.html |
# maybe use @PIPESTATUS as a workaround
tmpfile_handle $FUNCNAME.txt tmpfile_handle $FUNCNAME.txt
return $bad return $bad
} }
@ -1294,7 +1302,7 @@ lucky13() {
spdy_pre(){ spdy_pre(){
if [ "x$STARTTLS" != "x" ]; then if [ "x$STARTTLS" != "x" ]; then
[[ $VERBOSE -eq 1 ]] && outln "SPDY doesn't work with !HTTP" [[ $DEBUG -eq 2 ]] && outln "SPDY doesn't work with !HTTP"
return 1 return 1
fi fi
# first, does the current openssl support it? # first, does the current openssl support it?
@ -1409,12 +1417,12 @@ ccs_injection(){
fd_socket 5 || return 6 fd_socket 5 || return 6
[ $VERBOSE -eq 1 ] && out "\nsending client hello, " [[ $DEBUG -ge 2 ]] && out "\nsending client hello, "
socksend "$client_hello" 1 socksend "$client_hello" 1
sockread 16384 sockread 16384
if [ $VERBOSE -eq 1 ]; then [[ $DEBUG -ge 2 ]] && outln "\nreading server hello"
outln "\nserver hello:" if [[ $DEBUG -ge 3 ]]; then
echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20 echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20
outln "[...]" outln "[...]"
outln "\npayload #1 with TLS version $tls_hexcode:" outln "\npayload #1 with TLS version $tls_hexcode:"
@ -1422,7 +1430,7 @@ ccs_injection(){
socksend "$ccs_message" 1 || ok_ids socksend "$ccs_message" 1 || ok_ids
sockread 2048 5 # 5 seconds sockread 2048 5 # 5 seconds
if [ $VERBOSE -eq 1 ]; then if [[ $DEBUG -ge 3 ]]; then
outln "\n1st reply: " outln "\n1st reply: "
out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20 out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20
# ok: 15 | 0301 | 02 | 02 0a == ALERT | TLS 1.0 | Length=2 | Unexpected Message (0a) # ok: 15 | 0301 | 02 | 02 0a == ALERT | TLS 1.0 | Length=2 | Unexpected Message (0a)
@ -1434,7 +1442,7 @@ ccs_injection(){
sockread 2048 5 sockread 2048 5
retval=$? retval=$?
if [ $VERBOSE -eq 1 ]; then if [[ $DEBUG -ge 3 ]]; then
outln "\n2nd reply: " outln "\n2nd reply: "
out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}"
# not ok: 15 | 0301 | 02 | 02 | 15 == ALERT | TLS 1.0 | Length=2 | Decryption failed (21) # not ok: 15 | 0301 | 02 | 02 | 15 == ALERT | TLS 1.0 | Length=2 | Decryption failed (21)
@ -1525,12 +1533,12 @@ heartbleed(){
fd_socket 5 || return 6 fd_socket 5 || return 6
[ $VERBOSE -eq 1 ] && outln "\n\nsending client hello (TLS version $tls_hexcode)" [[ $DEBUG -ge 2 ]] && outln "\n\nsending client hello (TLS version $tls_hexcode)"
socksend "$client_hello" 1 socksend "$client_hello" 1
sockread 16384 sockread 16384
if [ $VERBOSE -eq 1 ]; then [[ $DEBUG -ge 2 ]] && outln "\nreading server hello"
outln "\nserver hello:" if [[ $DEBUG -ge 3 ]]; then
echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20 echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20
outln "[...]" outln "[...]"
outln "\nsending payload with TLS version $tls_hexcode:" outln "\nsending payload with TLS version $tls_hexcode:"
@ -1540,7 +1548,7 @@ heartbleed(){
sockread 16384 sockread 16384
retval=$? retval=$?
if [ $VERBOSE -eq 1 ]; then if [[ $DEBUG -ge 3 ]]; then
outln "\nheartbleed reply: " outln "\nheartbleed reply: "
echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}"
outln outln
@ -1685,13 +1693,13 @@ crime() {
return $ret return $ret
} }
detected_cbc_cipher=""
# Browser Exploit Against SSL/TLS # Browser Exploit Against SSL/TLS
beast(){ beast(){
shopt -s lastpipe # otherwise it's more tricky to access variables in a while loop shopt -s lastpipe # otherwise it's more tricky to access variables in a while loop
local hexcode dash cbc_cipher sslvers kx auth enc mac export local hexcode dash cbc_cipher sslvers kx auth enc mac export
local detected_proto local detected_proto
local detected_cbc_cipher=""
local higher_proto_supported="" local higher_proto_supported=""
local -i ret=0 local -i ret=0
local spaces=" " local spaces=" "
@ -1941,12 +1949,51 @@ maketempf () {
HEADERFILE=$TEMPDIR/http_header.txt HEADERFILE=$TEMPDIR/http_header.txt
HEADERFILE_BREACH=$TEMPDIR/http_header_breach.txt HEADERFILE_BREACH=$TEMPDIR/http_header_breach.txt
LOGFILE=$TEMPDIR/logfile.txt LOGFILE=$TEMPDIR/logfile.txt
if [ $DEBUG -ne 0 ]; then
cat >$TEMPDIR/environment.txt << EOF
PID: $$
bash version: ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}
status: ${BASH_VERSINFO[4]}
machine: ${BASH_VERSINFO[5]}
shellopts: $SHELLOPTS
"$osslver" [$nr_ciphers ciphers] on $hn:$osslpath
built: "$OSSL_BUILD_DATE", platform: "$OSSL_VER_PLATFORM"
$idtag
PATH: $PATH
RUN_DIR: $RUN_DIR
CAPATH: $CAPATH
ECHO: $ECHO
COLOR: $COLOR
SHOW_LOC_CIPH: $SHOW_LOC_CIPH
VERBERR: $VERBERR
LOCERR: $LOCERR
SHOW_EACH_C: $SHOW_EACH_C
SNEAKY: $SNEAKY
DEBUG: $DEBUG
HSTS_MIN: $HSTS_MIN
HPKP_MIN: $HPKP_MIN
MAX_WAITSOCK: $MAX_WAITSOCK
HEADER_MAXSLEEP: $HEADER_MAXSLEEP
CLIENT_MIN_PFS: $CLIENT_MIN_PFS
DAYS2WARN1: $DAYS2WARN1
DAYS2WARN2: $DAYS2WARN2
EOF
$OPENSSL ciphers -V $1 &>$TEMPDIR/all_local_ciphers.txt
fi
} }
cleanup () { cleanup () {
if [[ "$DEBUG" -eq 1 ]] ; then if [[ "$DEBUG" -ge 1 ]] ; then
outln outln
underline "DEBUG: see files in $TEMPDIR" underline "DEBUG (level $DEBUG): see files in $TEMPDIR"
else else
[ -d "$TEMPDIR" ] && rm -rf ${TEMPDIR}; [ -d "$TEMPDIR" ] && rm -rf ${TEMPDIR};
fi fi
@ -2089,7 +2136,7 @@ get_dns_entries() {
# for IPv6 we often get this :ffff:IPV4 address which isn't of any use # for IPv6 we often get this :ffff:IPV4 address which isn't of any use
#which getent 2>&1 >/dev/null && IP6=`getent ahostsv6 $NODE | grep $NODE | awk '{ print $1}' | grep -v '::ffff' | uniq` #which getent 2>&1 >/dev/null && IP6=`getent ahostsv6 $NODE | grep $NODE | awk '{ print $1}' | grep -v '::ffff' | uniq`
if [ -z "$IP6" ] ; then if [ -z "$IP6" ] ; then
if host -t aaaa $NODE 2>&1 >/dev/null ; then if host -t aaaa $NODE &>/dev/null ; then
IP6=`host -t aaaa $NODE | grep -v alias | grep -v "no AAAA record" | sed 's/^.*address //'` IP6=`host -t aaaa $NODE | grep -v alias | grep -v "no AAAA record" | sed 's/^.*address //'`
else else
IP6="" IP6=""
@ -2105,7 +2152,7 @@ get_dns_entries() {
# we can't do this as some checks and even openssl are not yet IPv6 safe # we can't do this as some checks and even openssl are not yet IPv6 safe
#NODEIP=`echo "$IP6" | head -1` #NODEIP=`echo "$IP6" | head -1`
rDNS=`host -t PTR $NODEIP | grep -v "is an alias for" | sed -e 's/^.*pointer //' -e 's/\.$//'` rDNS=`host -t PTR $NODEIP 2>/dev/null | grep -v "is an alias for" | sed -e 's/^.*pointer //' -e 's/\.$//'`
echo $rDNS | grep -q NXDOMAIN && rDNS=" - " echo $rDNS | grep -q NXDOMAIN && rDNS=" - "
} }
@ -2282,6 +2329,8 @@ case "$1" in
ret=$? ret=$?
serverbanner "$URL_PATH" serverbanner "$URL_PATH"
ret=`expr $? + $ret` ret=`expr $? + $ret`
applicationbanner "$URL_PATH"
ret=`expr $? + $ret`
cookieflags "$URL_PATH" cookieflags "$URL_PATH"
ret=`expr $? + $ret` ret=`expr $? + $ret`
else else
@ -2317,6 +2366,7 @@ case "$1" in
hsts "$URL_PATH" ; ret=`expr $? + $ret` hsts "$URL_PATH" ; ret=`expr $? + $ret`
hpkp "$URL_PATH" ; ret=`expr $? + $ret` hpkp "$URL_PATH" ; ret=`expr $? + $ret`
serverbanner "$URL_PATH" ; ret=`expr $? + $ret` serverbanner "$URL_PATH" ; ret=`expr $? + $ret`
applicationbanner "$URL_PATH" ; ret=`expr $? + $ret`
cookieflags "$URL_PATH" ; ret=`expr $? + $ret` cookieflags "$URL_PATH" ; ret=`expr $? + $ret`
fi fi
@ -2325,6 +2375,6 @@ case "$1" in
exit $ret ;; exit $ret ;;
esac esac
# $Id: testssl.sh,v 1.169 2015/01/20 20:59:20 dirkw Exp $ # $Id: testssl.sh,v 1.170 2015/01/21 11:52:59 dirkw Exp $
# vim:ts=5:sw=5 # vim:ts=5:sw=5