mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-01-03 23:39:45 +01:00
Exit error codes improvements, some formatting
According to programming standards e.g. C-style defines) testssl.sh has now internal error variables (ERR_*) which are defined to deal with exit codes in error conditions. Details see ``testssl.sh(1)``, section exit. Thus exit codes because of an error are now standardized and if needed can be easily changed to other values. This is part of a cleanup mentioned in #985 and #752. Codes for monitoring tools (#327) which imply some kind of rating are still to be done. The beginning section was reformatted and some items were reordered to keep variables and functions together which serve similar purposes. ``readonly`` was replaced by ``declare -r`` (closer to C's define and it makes more sense to settle on one variable if both are being used for the same purpose)
This commit is contained in:
parent
24a392d6eb
commit
b2be380b54
469
testssl.sh
469
testssl.sh
@ -3,19 +3,15 @@
|
||||
# vim:ts=5:sw=5:expandtab
|
||||
# we have a spaces softtab, that ensures readability with other editors too
|
||||
|
||||
[ -z "$BASH_VERSINFO" ] && printf "\n\033[1;35m Please make sure you're using \"bash\"! Bye...\033[m\n\n" >&2 && exit 245
|
||||
[ $(kill -l | grep -c SIG) -eq 0 ] && printf "\n\033[1;35m Please make sure you're calling me without leading \"sh\"! Bye...\033[m\n\n" >&2 && exit 245
|
||||
[ ${BASH_VERSINFO[0]} -lt 3 ] && printf "\n\033[1;35m Minimum requirement is bash 3.2. You have $BASH_VERSION \033[m\n\n" >&2 && exit 245
|
||||
[ ${BASH_VERSINFO[0]} -le 3 -a ${BASH_VERSINFO[1]} -le 1 ] && printf "\n\033[1;35m Minimum requirement is bash 3.2. You have $BASH_VERSION \033[m\n\n" >&2 && exit 245
|
||||
|
||||
# testssl.sh is a program for spotting weak SSL encryption, ciphers, version and some
|
||||
# vulnerabilities or features
|
||||
#
|
||||
# Devel version is available from https://github.com/drwetter/testssl.sh
|
||||
# Stable version from https://testssl.sh
|
||||
# Please file bugs at github! https://github.com/drwetter/testssl.sh/issues
|
||||
|
||||
# Main author: Dirk Wetter, copyleft: 2007-today, contributions so far see CREDITS.md
|
||||
#
|
||||
# Project lead and initiator: Dirk Wetter, copyleft: 2007-today, contributions so far see CREDITS.md
|
||||
# Main contriubtions from David Cooper
|
||||
#
|
||||
# License: GPLv2, see http://www.fsf.org/licensing/licenses/info/GPLv2.html
|
||||
# and accompanying license "LICENSE.txt". Redistribution + modification under this
|
||||
@ -33,63 +29,73 @@
|
||||
# stating a CC BY 3.0 US license: https://creativecommons.org/licenses/by/3.0/us/
|
||||
#
|
||||
# Please note: USAGE WITHOUT ANY WARRANTY, THE SOFTWARE IS PROVIDED "AS IS".
|
||||
#
|
||||
# USE IT AT your OWN RISK!
|
||||
# Seriously! The threat is you run this code on your computer and input could be /
|
||||
# is being supplied via untrusted sources.
|
||||
|
||||
#
|
||||
# HISTORY:
|
||||
# Back in 2006 it all started with a few openssl commands...
|
||||
# That's because openssl is a such a good swiss army knife (see e.g.
|
||||
# wiki.openssl.org/index.php/Command_Line_Utilities) that it was difficult to resist
|
||||
# wrapping some shell commands around it, which I used for my pen tests. This is how
|
||||
# everything started.
|
||||
# Now it has grown up, it has bash socket support for some features, which is basically replacing
|
||||
# more and more functions of OpenSSL and will serve as some kind of library in the future.
|
||||
# The socket checks in bash may sound cool and unique -- they are -- but probably you
|
||||
# can achieve e.g. the same result with my favorite interactive shell: zsh (zmodload zsh/net/socket
|
||||
# -- checkout zsh/net/tcp) too!
|
||||
# /bin/bash though is way more often used within Linux and it's perfect
|
||||
# for cross platform support, see MacOS X and also under Windows the MSYS2 extension or Cygwin
|
||||
# as well as Bash on Windows (WSL)
|
||||
# Now it has grown up, it has bash socket support for most features, which has been basically
|
||||
# replacing more and more functions of OpenSSL and some sockets functions serve as some kind
|
||||
# of central functions.
|
||||
#
|
||||
# WHY BASH?
|
||||
# Cross-platform is one of the three main goals of this script. Second: Ease of installation.
|
||||
# No compiling, install gems, go to CPAN, use pip etc. Third: Easy to use and to interpret
|
||||
# the results.
|
||||
|
||||
# Did I mention it's open source?
|
||||
|
||||
# /bin/bash including the builtin sockets fulfill all that. The socket checks in bash may sound
|
||||
# cool and unique -- they are -- but probably you can achieve e.g. the same result with my favorite
|
||||
# interactive shell: zsh (zmodload zsh/net/socket -- checkout zsh/net/tcp) too! Oh, and btw.
|
||||
# ksh93 has socket support too.
|
||||
# /bin/bash though is way more often used within Linux and it's perfect for cross platform support.
|
||||
# MacOS X has it and also under Windows the MSYS2 extension or Cygwin as well as Bash on Windows (WSL)
|
||||
# has /bin/bash.
|
||||
#
|
||||
# Q: So what's the difference to www.ssllabs.com/ssltest/ or sslcheck.globalsign.com/ ?
|
||||
# A: As of now ssllabs only check 1) webservers 2) on standard ports, 3) reachable from the
|
||||
# internet. And those examples above 4) are 3rd parties. If these restrictions are all fine
|
||||
# with you and you need a management compatible rating -- go ahead and use those.
|
||||
|
||||
# But also if your fine with those restrictions: testssl.sh is meant as a tool in your hand
|
||||
# and it's way more flexible.
|
||||
#
|
||||
# Oh, and did I mention testssl.sh is open source?
|
||||
# But also if your fine with those restrictions: testssl.sh is meant as a tool in your hand
|
||||
# and it's way more flexible. Oh, and did I mention testssl.sh is open source?
|
||||
#
|
||||
#################### Stop talking, action now ####################
|
||||
|
||||
# Note that up to today there were a lot changes for "standard" openssl
|
||||
# binaries: a lot of features (ciphers, protocols, vulnerabilities)
|
||||
# are disabled as they'll impact security otherwise. For security
|
||||
# testing though we need all broken features. testssl.sh will
|
||||
# over time replace those checks with bash sockets -- however it's
|
||||
# still recommended to use the supplied binaries or cook your own, see
|
||||
# https://github.com/drwetter/testssl.sh/blob/master/bin/Readme.md .
|
||||
# Don't worry if feature X is not available you'll get a warning about
|
||||
# this missing feature! The idea is if this script can't tell something
|
||||
# for sure it speaks up so that you have clear picture.
|
||||
|
||||
# debugging help:
|
||||
readonly PS4='|${LINENO}> \011${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
########### Definition of error codes
|
||||
#
|
||||
declare -r ERR_BASH=255 # Bash version incorrect
|
||||
declare -r ERR_CMDLINE=254 # Cmd line couldn't be parsed
|
||||
declare -r ERR_FCREATE=253 # Output file couldn't be created
|
||||
declare -r ERR_FNAMEPARSE=252 # Input file couldn't be parsed
|
||||
declare -r ERR_NOSUPPORT=251 # Feature requested is not supported
|
||||
declare -r ERR_OSSLBIN=250 # Problem with OpenSSL binary
|
||||
declare -r ERR_DNSBIN=249 # Problem with DNS lookup binaries
|
||||
declare -r ERR_OTHERCLIENT=248 # Other client problem
|
||||
declare -r ERR_DNSLOOKUP=247 # Problem with resolving IP addresses or names
|
||||
declare -r ERR_CONNECT=246 # Connectivity problem
|
||||
declare -r ERR_CLUELESS=245 # Weird state, either though user options or testssl.sh
|
||||
declare -r ERR_RESSOURCE=244 # Resources testssl.sh needs couldn't be read
|
||||
declare -r ERR_CHILD=242 # Child received a signal from master
|
||||
declare -r ALLOK=0 # All is fine
|
||||
|
||||
# see stackoverflow.com/questions/5014823/how-to-profile-a-bash-shell-script-slow-startup#20855353
|
||||
# how to paste both in order to do performance analysis
|
||||
DEBUGTIME=${DEBUGTIME:-false}
|
||||
|
||||
[ -z "$BASH_VERSINFO" ] && printf "\n\033[1;35m Please make sure you're using \"bash\"! Bye...\033[m\n\n" >&2 && exit $ERR_BASH
|
||||
[ $(kill -l | grep -c SIG) -eq 0 ] && printf "\n\033[1;35m Please make sure you're calling me without leading \"sh\"! Bye...\033[m\n\n" >&2 && exit $ERR_BASH
|
||||
[ ${BASH_VERSINFO[0]} -lt 3 ] && printf "\n\033[1;35m Minimum requirement is bash 3.2. You have $BASH_VERSION \033[m\n\n" >&2 && exit $ERR_BASH
|
||||
[ ${BASH_VERSINFO[0]} -le 3 -a ${BASH_VERSINFO[1]} -le 1 ] && printf "\n\033[1;35m Minimum requirement is bash 3.2. You have $BASH_VERSION \033[m\n\n" >&2 && exit $ERR_BASH
|
||||
|
||||
########### Debugging helpers + profiling
|
||||
#
|
||||
declare -r PS4='|${LINENO}> \011${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
DEBUGTIME=${DEBUGTIME:-false} # stackoverflow.com/questions/5014823/how-to-profile-a-bash-shell-script-slow-startup#20855353, profiling bash
|
||||
DEBUG_ALLINONE=${DEBUG_ALLINONE:-false} # true: do debugging in one sceen (old behaviour for testssl.sh and bash3's default
|
||||
# false: needed for performance analysis or useful for just having an extra file
|
||||
DEBUG_ALLINONE=${SETX:-false} # SETX as a shortcut for old style debugging, overriding DEBUG_ALLINONE
|
||||
|
||||
|
||||
if grep -q xtrace <<< "$SHELLOPTS"; then
|
||||
if "$DEBUGTIME"; then
|
||||
# separate debugging, doesn't mess up the screen, $DEBUGTIME determines whether we also do performance analysis
|
||||
@ -103,19 +109,31 @@ if grep -q xtrace <<< "$SHELLOPTS"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# make sure that temporary files are cleaned up after use in ANY case
|
||||
########### Traps! Make sure that temporary files are cleaned up after use in ANY case
|
||||
#
|
||||
trap "cleanup" QUIT EXIT
|
||||
trap "child_error" USR1
|
||||
|
||||
readonly VERSION="2.9dev"
|
||||
readonly SWCONTACT="dirk aet testssl dot sh"
|
||||
egrep -q "dev|rc" <<< "$VERSION" && \
|
||||
########### Internal definitions
|
||||
#
|
||||
declare -r VERSION="2.9dev"
|
||||
declare -r SWCONTACT="dirk aet testssl dot sh"
|
||||
egrep -q "dev|rc|beta" <<< "$VERSION" && \
|
||||
SWURL="https://testssl.sh/dev/" ||
|
||||
SWURL="https://testssl.sh/"
|
||||
|
||||
readonly PROG_NAME="$(basename "$0")"
|
||||
readonly RUN_DIR="$(dirname "$0")"
|
||||
declare -r CVS_REL=$(tail -5 "$0" | awk '/dirkw Exp/ { print $4" "$5" "$6}')
|
||||
declare -r CVS_REL_SHORT=$(tail -5 "$0" | awk '/dirkw Exp/ { print $4 }')
|
||||
if git log &>/dev/null; then
|
||||
declare -r GIT_REL=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $1" "$2" "$3 }')
|
||||
declare -r GIT_REL_SHORT=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $1 }')
|
||||
declare -r REL_DATE=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $2 }')
|
||||
else
|
||||
declare -r REL_DATE=$(tail -5 "$0" | awk '/dirkw Exp/ { print $5 }')
|
||||
fi
|
||||
declare -r PROG_NAME="$(basename "$0")"
|
||||
declare -r RUN_DIR="$(dirname "$0")"
|
||||
declare -r SYSTEM=$(uname -s)
|
||||
SYSTEM2="" # currently only being used for WSL = bash on windows
|
||||
TESTSSL_INSTALL_DIR="${TESTSSL_INSTALL_DIR:-""}" # If you run testssl.sh and it doesn't find it necessary file automagically set TESTSSL_INSTALL_DIR
|
||||
CA_BUNDLES_PATH="${CA_BUNDLES_PATH:-""}" # You can have your stores some place else
|
||||
ADDITIONAL_CA_FILES="${ADDITIONAL_CA_FILES:-""}" # single file with a CA in PEM format or comma separated lists of them
|
||||
@ -126,27 +144,16 @@ HNAME="$(hostname)"
|
||||
HNAME="${HNAME%%.*}"
|
||||
|
||||
declare CMDLINE
|
||||
# When performing mass testing, the child processes need to be sent the
|
||||
# command line in the form of an array (see #702 and http://mywiki.wooledge.org/BashFAQ/050).
|
||||
readonly -a CMDLINE_ARRAY=("$@")
|
||||
declare -a MASS_TESTING_CMDLINE
|
||||
declare -r -a CMDLINE_ARRAY=("$@") # When performing mass testing, the child processes need to be sent the
|
||||
declare -r -a MASS_TESTING_CMDLINE # command line in the form of an array (see #702 and http://mywiki.wooledge.org/BashFAQ/050).
|
||||
|
||||
readonly CVS_REL=$(tail -5 "$0" | awk '/dirkw Exp/ { print $4" "$5" "$6}')
|
||||
readonly CVS_REL_SHORT=$(tail -5 "$0" | awk '/dirkw Exp/ { print $4 }')
|
||||
if git log &>/dev/null; then
|
||||
readonly GIT_REL=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $1" "$2" "$3 }')
|
||||
readonly GIT_REL_SHORT=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $1 }')
|
||||
readonly REL_DATE=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $2 }')
|
||||
else
|
||||
readonly REL_DATE=$(tail -5 "$0" | awk '/dirkw Exp/ { print $5 }')
|
||||
fi
|
||||
readonly SYSTEM=$(uname -s)
|
||||
SYSTEM2="" # currently only being used for WSL = bash on windows
|
||||
|
||||
########### Some predefinitions: date, sed (we always use test and not try to determine
|
||||
# capabilities by querying the OS)
|
||||
#
|
||||
HAS_GNUDATE=false
|
||||
HAS_FREEBSDDATE=false
|
||||
HAS_OPENBSDDATE=false
|
||||
|
||||
if date -d @735275209 >/dev/null 2>&1; then
|
||||
if date -r @735275209 >/dev/null 2>&1; then
|
||||
# it can't do any conversion from a plain date output
|
||||
@ -160,12 +167,13 @@ date -j -f '%s' 1234567 >/dev/null 2>&1 && \
|
||||
HAS_FREEBSDDATE=true
|
||||
|
||||
echo A | sed -E 's/A//' >/dev/null 2>&1 && \
|
||||
readonly HAS_SED_E=true || \
|
||||
readonly HAS_SED_E=false
|
||||
declare -r HAS_SED_E=true || \
|
||||
declare -r HAS_SED_E=false
|
||||
|
||||
########### Terminal defintions
|
||||
tty -s && \
|
||||
readonly INTERACTIVE=true || \
|
||||
readonly INTERACTIVE=false
|
||||
declare -r INTERACTIVE=true || \
|
||||
declare -r INTERACTIVE=false
|
||||
|
||||
if [[ -z $TERM_WIDTH ]]; then # no batch file and no otherwise predefined TERM_WIDTH
|
||||
if ! tput cols &>/dev/null || ! "$INTERACTIVE";then # Prevent tput errors if running non interactive
|
||||
@ -176,12 +184,13 @@ if [[ -z $TERM_WIDTH ]]; then # no batch file and
|
||||
fi
|
||||
TERM_CURRPOS=0 # custom line wrapping needs alter the current horizontal cursor pos
|
||||
|
||||
## CONFIGURATION PART ##
|
||||
# following variables make use of $ENV, e.g. OPENSSL=<myprivate_path_to_openssl> ./testssl.sh <URI>
|
||||
# 0 means (normally) true here. Some of the variables are also accessible with a command line switch, see --help
|
||||
|
||||
########### Defining (and presetting) variables which can be changed
|
||||
#
|
||||
# Following variables make use of $ENV and can be used like "OPENSSL=<myprivate_path_to_openssl> ./testssl.sh <URI>"
|
||||
declare -x OPENSSL OPENSSL_TIMEOUT
|
||||
FAST_SOCKET=${FAST_SOCKET:-false} # EXPERIMENTAL feature to accelerate sockets -- DO NOT USE it for production
|
||||
COLOR=${COLOR:-2} # 3: extra color, 2: Full color, 1: b/w+positioning, 0: no ESC at all
|
||||
COLOR=${COLOR:-2} # 3: Extra color (ciphers, curves), 2: Full color, 1: B/W only 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
|
||||
SHOW_SIGALGO=${SHOW_SIGALGO:-false} # "secret" switch whether testssl.sh shows the signature algorithm for -E / -e
|
||||
@ -207,11 +216,12 @@ HTMLFILE="${HTMLFILE:-""}" # HTML if used
|
||||
FNAME=${FNAME:-""} # file name to read commands from
|
||||
FNAME_PREFIX=${FNAME_PREFIX:-""} # output filename prefix, see --outprefix
|
||||
APPEND=${APPEND:-false} # append to csv/json file instead of overwriting it
|
||||
# NODNS=${NODNS:-"no"} # if unset it does all DNS lookups per default. "min" only for hosts or "none" at all
|
||||
[[ -z "$NODNS" ]] && declare NODNS # If unset it does all DNS lookups per default. "min" only for hosts or "none" at all
|
||||
HAS_IPv6=${HAS_IPv6:-false} # if you have OpenSSL with IPv6 support AND IPv6 networking set it to yes
|
||||
ALL_CLIENTS=${ALL_CLIENTS:-false} # do you want to run all client simulation form all clients supplied by SSLlabs?
|
||||
|
||||
# tuning vars which cannot be set by a cmd line switch
|
||||
########### Tuning vars which cannot be set by a cmd line switch
|
||||
#
|
||||
EXPERIMENTAL=${EXPERIMENTAL:-false}
|
||||
HEADER_MAXSLEEP=${HEADER_MAXSLEEP:-5} # we wait this long before killing the process to retrieve a service banner / http header
|
||||
MAX_SOCKET_FAIL=${MAX_SOCKET_FAIL:-2} # If this many failures for TCP socket connects are reached we terminate
|
||||
@ -234,7 +244,7 @@ VULN_THRESHLD=${VULN_THRESHLD:-1} # if vulnerabilities to check >$VULN_THR
|
||||
DNS_VIA_PROXY=${DNS_VIA_PROXY:-false} # don't do DNS lookups via proxy. --ip=proxy reverses this
|
||||
UNBRACKTD_IPV6=${UNBRACKTD_IPV6:-false} # some versions of OpenSSL (like Gentoo) don't support [bracketed] IPv6 addresses
|
||||
NO_ENGINE=${NO_ENGINE:-false} # if there are problems finding the (external) openssl engine set this to true
|
||||
readonly CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS
|
||||
declare -r CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS
|
||||
CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet (FC has only a CA bundle per default, ==> openssl version -d)
|
||||
MEASURE_TIME_FILE=${MEASURE_TIME_FILE:-""}
|
||||
if [[ -n "$MEASURE_TIME_FILE" ]] && [[ -z "$MEASURE_TIME" ]]; then
|
||||
@ -243,10 +253,11 @@ else
|
||||
MEASURE_TIME=${MEASURE_TIME:-false}
|
||||
fi
|
||||
DISPLAY_CIPHERNAMES="openssl" # display OpenSSL ciphername (but both OpenSSL and RFC ciphernames in wide mode)
|
||||
readonly UA_STD="TLS tester from $SWURL"
|
||||
readonly UA_SNEAKY="Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
|
||||
declare -r UA_STD="TLS tester from $SWURL"
|
||||
declare -r UA_SNEAKY="Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
|
||||
|
||||
# initialization part, further global vars just declared here
|
||||
########### Initialization part, further global vars just being declared here
|
||||
#
|
||||
IKNOW_FNAME=false
|
||||
FIRST_FINDING=true # is this the first finding we are outputting to file?
|
||||
JSONHEADER=true # include JSON headers and footers in HTML file, if one is being created
|
||||
@ -260,10 +271,12 @@ HAD_SLEPT=0
|
||||
NR_SOCKET_FAIL=0 # Counter for socket failures
|
||||
NR_OSSL_FAIL=0 # .. for OpenSSL connects
|
||||
NR_HEADER_FAIL=0 # .. for HTTP_GET
|
||||
readonly NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1"
|
||||
PROTOS_OFFERED="" # This keeps which protocol is being offered. See has_server_protocol().
|
||||
DETECTED_TLS_VERSION=""
|
||||
TLS_EXTENSIONS=""
|
||||
declare -r NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1"
|
||||
# alpn_protos needs to be space-separated, not comma-seperated, including odd ones observerd @ facebook and others, old ones like h2-17 omitted as they could not be found
|
||||
readonly ALPN_PROTOs="h2 spdy/3.1 http/1.1 h2-fb spdy/1 spdy/2 spdy/3 stun.turn stun.nat-discovery webrtc c-webrtc ftp"
|
||||
|
||||
declare -r ALPN_PROTOs="h2 spdy/3.1 http/1.1 h2-fb spdy/1 spdy/2 spdy/3 stun.turn stun.nat-discovery webrtc c-webrtc ftp"
|
||||
declare -a SESS_RESUMPTION
|
||||
TEMPDIR=""
|
||||
TMPFILE=""
|
||||
@ -274,15 +287,12 @@ HOSTCERT="" # File with host certificate, without in
|
||||
HEADERFILE=""
|
||||
HEADERVALUE=""
|
||||
HTTP_STATUS_CODE=""
|
||||
PROTOS_OFFERED="" # This is a global to keep the info which protocol is being offered. See has_server_protocol().
|
||||
KEY_SHARE_EXTN_NR="33" # The extension number for key_share was changed from 40 to 51 in TLSv1.3 draft 23. In order to
|
||||
# support draft 23 in additional to earlier drafts, need to know which extension number to use.
|
||||
# Note that it appears that a single ClientHello cannot advertise both draft 23 and earlier drafts.
|
||||
# Preset may help to deal with STARTTLS + TLS 1.3 draft 23 but not earlier.
|
||||
TLS_EXTENSIONS=""
|
||||
BAD_SERVER_HELLO_CIPHER=false # reserved for cases where a ServerHello doesn't contain a cipher offered in the ClientHello
|
||||
GOST_STATUS_PROBLEM=false
|
||||
DETECTED_TLS_VERSION=""
|
||||
PATTERN2SHOW=""
|
||||
SOCK_REPLY_FILE=""
|
||||
NW_STR=""
|
||||
@ -319,27 +329,27 @@ PORT=443 # unless otherwise auto-determined, see
|
||||
NODE=""
|
||||
NODEIP=""
|
||||
rDNS=""
|
||||
CORRECT_SPACES="" # used for IPv6 and proper output formatting
|
||||
CORRECT_SPACES="" # Used for IPv6 and proper output formatting
|
||||
IPADDRs=""
|
||||
IP46ADDRs=""
|
||||
LOCAL_A=false # does the $NODEIP come from /etc/hosts?
|
||||
LOCAL_AAAA=false # does the IPv6 IP come from /etc/hosts?
|
||||
LOCAL_A=false # Does the $NODEIP come from /etc/hosts?
|
||||
LOCAL_AAAA=false # Does the IPv6 IP come from /etc/hosts?
|
||||
XMPP_HOST=""
|
||||
PROXY=""
|
||||
PROXYIP=""
|
||||
PROXYPORT=""
|
||||
VULN_COUNT=0
|
||||
SERVICE="" # is the server running an HTTP server, SMTP, POP or IMAP?
|
||||
SERVICE="" # Is the server running an HTTP server, SMTP, POP or IMAP?
|
||||
URI=""
|
||||
CERT_FINGERPRINT_SHA2=""
|
||||
RSA_CERT_FINGERPRINT_SHA2=""
|
||||
STARTTLS_PROTOCOL=""
|
||||
OPTIMAL_PROTO="" # we need this for IIS6 (sigh) and OpenSSL 1.0.2, otherwise some handshakes
|
||||
# will fail, see https://github.com/PeterMosmans/openssl/issues/19#issuecomment-100897892
|
||||
STARTTLS_OPTIMAL_PROTO="" # same for STARTTLS, see https://github.com/drwetter/testssl.sh/issues/188
|
||||
TLS_TIME="" # to keep the value of TLS server timestamp
|
||||
TLS_NOW="" # similar
|
||||
TLS_DIFFTIME_SET=false # tells TLS functions to measure the TLS difftime or not
|
||||
OPTIMAL_PROTO="" # Need this for IIS6 (sigh) + OpenSSL 1.0.2, otherwise some handshakes will fail see
|
||||
# https://github.com/PeterMosmans/openssl/issues/19#issuecomment-100897892
|
||||
STARTTLS_OPTIMAL_PROTO="" # Same for STARTTLS, see https://github.com/drwetter/testssl.sh/issues/188
|
||||
TLS_TIME="" # To keep the value of TLS server timestamp
|
||||
TLS_NOW="" # Similar
|
||||
TLS_DIFFTIME_SET=false # Tells TLS functions to measure the TLS difftime or not
|
||||
NOW_TIME=""
|
||||
HTTP_TIME=""
|
||||
GET_REQ11=""
|
||||
@ -347,15 +357,15 @@ START_TIME=0 # time in epoch when the action started
|
||||
END_TIME=0 # .. ended
|
||||
SCAN_TIME=0 # diff of both: total scan time
|
||||
LAST_TIME=0 # only used for performance measurements (MEASURE_TIME=true)
|
||||
|
||||
# Devel stuff, see -q below
|
||||
TLS_LOW_BYTE=""
|
||||
HEX_CIPHER=""
|
||||
|
||||
SERVER_COUNTER=0 # Counter for multiple servers
|
||||
|
||||
TLS_LOW_BYTE="" # For "secret" development stuff, see -q below
|
||||
HEX_CIPHER="" # "
|
||||
|
||||
|
||||
########### Global variables for parallel mass testing
|
||||
readonly PARALLEL_SLEEP=1 # Time to sleep after starting each test
|
||||
#
|
||||
declare -r PARALLEL_SLEEP=1 # Time to sleep after starting each test
|
||||
MAX_WAIT_TEST=${MAX_WAIT_TEST:-1200} # Maximum time (in seconds) to wait for a test to complete
|
||||
MAX_PARALLEL=${MAX_PARALLEL:-20} # Maximum number of tests to run in parallel
|
||||
# This value may be made larger on systems with faster processors
|
||||
@ -365,8 +375,23 @@ declare -i NR_PARALLEL_TESTS=0 # number of parallel tests run
|
||||
declare -i NEXT_PARALLEL_TEST_TO_FINISH=0 # number of parallel tests that have completed and have been processed
|
||||
declare FIRST_JSON_OUTPUT=true # true if no output has been added to $JSONFILE yet.
|
||||
|
||||
#################### SEVERITY ####################
|
||||
|
||||
########### Cipher suite information
|
||||
#
|
||||
declare -i TLS_NR_CIPHERS=0
|
||||
declare TLS_CIPHER_HEXCODE=()
|
||||
declare TLS_CIPHER_OSSL_NAME=()
|
||||
declare TLS_CIPHER_RFC_NAME=()
|
||||
declare TLS_CIPHER_SSLVERS=()
|
||||
declare TLS_CIPHER_KX=()
|
||||
declare TLS_CIPHER_AUTH=()
|
||||
declare TLS_CIPHER_ENC=()
|
||||
declare TLS_CIPHER_EXPORT=()
|
||||
declare TLS_CIPHER_OSSL_SUPPORTED=()
|
||||
declare TLS13_OSSL_CIPHERS="TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"
|
||||
|
||||
########### Severity functions and globals
|
||||
#
|
||||
INFO=0
|
||||
OK=0
|
||||
LOW=1
|
||||
@ -406,21 +431,7 @@ show_finding() {
|
||||
( [[ "$severity" == "CRITICAL" ]] && [[ $SEVERITY_LEVEL -le $CRITICAL ]] )
|
||||
}
|
||||
|
||||
|
||||
###### Cipher suite information #####
|
||||
declare -i TLS_NR_CIPHERS=0
|
||||
declare TLS_CIPHER_HEXCODE=()
|
||||
declare TLS_CIPHER_OSSL_NAME=()
|
||||
declare TLS_CIPHER_RFC_NAME=()
|
||||
declare TLS_CIPHER_SSLVERS=()
|
||||
declare TLS_CIPHER_KX=()
|
||||
declare TLS_CIPHER_AUTH=()
|
||||
declare TLS_CIPHER_ENC=()
|
||||
declare TLS_CIPHER_EXPORT=()
|
||||
declare TLS_CIPHER_OSSL_SUPPORTED=()
|
||||
declare TLS13_OSSL_CIPHERS="TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"
|
||||
|
||||
###### output functions ######
|
||||
########### Output functions
|
||||
|
||||
# For HTML output, replace any HTML reserved characters with the entity name
|
||||
html_reserved(){
|
||||
@ -442,7 +453,7 @@ html_out() {
|
||||
# here and other printf's: a little bit of sanitzing with bash internal search&replace -- otherwise printf will hiccup at '%'. '--' and %b do the rest.
|
||||
}
|
||||
|
||||
# this is intentionally the same.
|
||||
# This is intentionally the same.
|
||||
safe_echo() { printf -- "%b" "${1//%/%%}"; }
|
||||
tm_out() { printf -- "%b" "${1//%/%%}"; }
|
||||
tmln_out() { printf -- "%b" "${1//%/%%}\n"; }
|
||||
@ -452,7 +463,7 @@ outln() { printf -- "%b" "${1//%/%%}\n"; html_out "$1\n"; }
|
||||
|
||||
#TODO: Still no shell injection safe but if just run it from the cmd line: that's fine
|
||||
|
||||
# color print functions, see also http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
|
||||
# Color print functions, see also http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
|
||||
tm_liteblue() { [[ "$COLOR" -ge 2 ]] && ( "$COLORBLIND" && tm_out "\033[0;32m$1" || tm_out "\033[0;34m$1" ) || tm_out "$1"; tm_off; } # not yet used
|
||||
pr_liteblue() { tm_liteblue "$1"; [[ "$COLOR" -ge 2 ]] && ( "$COLORBLIND" && html_out "<span style=\"color:#00cd00;\">$(html_reserved "$1")</span>" || html_out "<span style=\"color:#0000ee;\">$(html_reserved "$1")</span>" ) || html_out "$(html_reserved "$1")"; }
|
||||
tmln_liteblue() { tm_liteblue "$1"; tmln_out; }
|
||||
@ -897,7 +908,7 @@ json_header() {
|
||||
if "$APPEND"; then
|
||||
JSONHEADER=false
|
||||
else
|
||||
[[ -s "$JSONFILE" ]] && fatal "non-empty \"$JSONFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||
[[ -s "$JSONFILE" ]] && fatal "non-empty \"$JSONFILE\" exists. Either use \"--append\" or (re)move it" $ERR_FCREATE
|
||||
"$do_json" && echo "[" > "$JSONFILE"
|
||||
"$do_pretty_json" && echo "{" > "$JSONFILE"
|
||||
fi
|
||||
@ -937,7 +948,7 @@ csv_header() {
|
||||
if "$APPEND"; then
|
||||
CSVHEADER=false
|
||||
else
|
||||
[[ -s "$CSVFILE" ]] && fatal "non-empty \"$CSVFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||
[[ -s "$CSVFILE" ]] && fatal "non-empty \"$CSVFILE\" exists. Either use \"--append\" or (re)move it" $ERR_FCREATE
|
||||
echo "\"id\",\"fqdn/ip\",\"port\",\"severity\",\"finding\",\"cve\",\"cwe\",\"hint\"" > "$CSVFILE"
|
||||
fi
|
||||
return 0
|
||||
@ -980,7 +991,7 @@ html_header() {
|
||||
if "$APPEND"; then
|
||||
HTMLHEADER=false
|
||||
else
|
||||
[[ -s "$HTMLFILE" ]] && fatal "non-empty \"$HTMLFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||
[[ -s "$HTMLFILE" ]] && fatal "non-empty \"$HTMLFILE\" exists. Either use \"--append\" or (re)move it" $ERR_FCREATE
|
||||
html_out "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
|
||||
html_out "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
|
||||
html_out "<!-- This file was created with testssl.sh. https://testssl.sh -->\n"
|
||||
@ -1015,6 +1026,39 @@ html_footer() {
|
||||
|
||||
################# HTML FILE FORMATTING END ####################
|
||||
|
||||
prepare_logging() {
|
||||
# arg1: for testing mx records name we put a name of logfile in here, otherwise we get strange file names
|
||||
local fname_prefix="$1"
|
||||
local filename_provided=false
|
||||
|
||||
[[ -n "$LOGFILE" ]] && [[ ! -d "$LOGFILE" ]] && filename_provided=true
|
||||
|
||||
# Similar to html_header():
|
||||
! "$do_logging" && return 0
|
||||
"$do_mass_testing" && ! "$filename_provided" && return 0
|
||||
"$CHILD_MASS_TESTING" && "$filename_provided" && return 0
|
||||
|
||||
[[ -z "$fname_prefix" ]] && fname_prefix="${FNAME_PREFIX}${NODE}"_p"${PORT}"
|
||||
|
||||
if [[ -z "$LOGFILE" ]]; then
|
||||
LOGFILE="$fname_prefix-$(date +"%Y%m%d-%H%M".log)"
|
||||
elif [[ -d "$LOGFILE" ]]; then
|
||||
# actually we were instructed to place all files in a DIR instead of the current working dir
|
||||
LOGFILE="$LOGFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".log)"
|
||||
else
|
||||
: # just for clarity: a log file was specified, no need to do anything else
|
||||
fi
|
||||
|
||||
if ! "$APPEND"; then
|
||||
[[ -s "$LOGFILE" ]] && fatal "non-empty \"$LOGFILE\" exists. Either use \"--append\" or (re)move it" $ERR_FCREATE
|
||||
fi
|
||||
tmln_out "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>"$LOGFILE"
|
||||
tmln_out "## at $HNAME:$OPENSSL_LOCATION" >>"$LOGFILE"
|
||||
tmln_out "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>"$LOGFILE"
|
||||
tmln_out "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>"$LOGFILE"
|
||||
exec > >(tee -a -i "$LOGFILE")
|
||||
}
|
||||
|
||||
################### FILE FORMATTING END #########################
|
||||
|
||||
###### START helper function definitions ######
|
||||
@ -1592,8 +1636,8 @@ service_detection() {
|
||||
#
|
||||
connectivity_problem() {
|
||||
if [[ $1 -ge $2 ]]; then
|
||||
[[ $2 -eq 1 ]] && fatal "$3" -2
|
||||
fatal "$4" -2
|
||||
[[ $2 -eq 1 ]] && fatal "$3" $ERR_CONNECT
|
||||
fatal "$4" $ERR_CONNECT
|
||||
fi
|
||||
}
|
||||
|
||||
@ -2543,7 +2587,7 @@ prettyprint_local() {
|
||||
local re='^[0-9A-Fa-f]+$'
|
||||
|
||||
if [[ "$1" == 0x* ]] || [[ "$1" == 0X* ]]; then
|
||||
fatal "pls supply x<number> instead" 2
|
||||
fatal "pls supply x<number> instead" $ERR_CMDLINE
|
||||
fi
|
||||
|
||||
if [[ -z "$1" ]]; then
|
||||
@ -4976,7 +5020,7 @@ run_protocols() {
|
||||
if [[ ! "$PROTOS_OFFERED" =~ yes ]]; then
|
||||
outln
|
||||
ignore_no_or_lame "You should not proceed as no protocol was detected. If you still really really want to, say \"YES\"" "YES"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
|
||||
fi
|
||||
return $ret
|
||||
}
|
||||
@ -8595,10 +8639,10 @@ fd_socket() {
|
||||
starttls_imap_dialog
|
||||
;;
|
||||
ldap|ldaps) # LDAP, https://tools.ietf.org/html/rfc2830, https://tools.ietf.org/html/rfc4511
|
||||
fatal "FIXME: LDAP+STARTTLS over sockets not yet supported (try \"--ssl-native\")" -4
|
||||
fatal "FIXME: LDAP+STARTTLS over sockets not yet supported (try \"--ssl-native\")" $ERR_NOSUPPORT
|
||||
;;
|
||||
acap|acaps) # ACAP = Application Configuration Access Protocol, see https://tools.ietf.org/html/rfc2595
|
||||
fatal "ACAP Easteregg: not implemented -- probably never will" -4
|
||||
fatal "ACAP Easteregg: not implemented -- probably never will" $ERR_NOSUPPORT
|
||||
;;
|
||||
xmpp|xmpps) # XMPP, see https://tools.ietf.org/html/rfc6120
|
||||
starttls_just_read
|
||||
@ -8624,7 +8668,7 @@ EOF
|
||||
starttls_mysql_dialog
|
||||
;;
|
||||
*) # we need to throw an error here -- otherwise testssl.sh treats the STARTTLS protocol as plain SSL/TLS which leads to FP
|
||||
fatal "FIXME: STARTTLS protocol $STARTTLS_PROTOCOL is not yet supported" -4
|
||||
fatal "FIXME: STARTTLS protocol $STARTTLS_PROTOCOL is not yet supported" $ERR_NOSUPPORT
|
||||
esac
|
||||
fi
|
||||
[[ $? -eq 0 ]] && return 0
|
||||
@ -14596,7 +14640,7 @@ old_fart() {
|
||||
pr_url "https://github.com/PeterMosmans/openssl"
|
||||
outln "."
|
||||
fileout_insert_warning "old_fart" "WARN" "Your $OPENSSL $OSSL_VER version is an old fart... . It doesn\'t make much sense to proceed. Get precompiled bins or compile https://github.com/PeterMosmans/openssl ."
|
||||
fatal "Your $OPENSSL $OSSL_VER version is an old fart... . It doesn't make much sense to proceed." -5
|
||||
fatal "Your $OPENSSL $OSSL_VER version is an old fart... . It doesn't make much sense to proceed." $ERR_OSSLBIN
|
||||
}
|
||||
|
||||
# try very hard to determine the install path to get ahold of the mapping file and the CA bundles
|
||||
@ -14651,7 +14695,7 @@ get_install_dir() {
|
||||
outln "Please note from 2.9dev on $PROG_NAME needs files in \"\$TESTSSL_INSTALL_DIR/etc/\" to function correctly."
|
||||
outln
|
||||
ignore_no_or_lame "Type \"yes\" to ignore this warning and proceed at your own risk" "yes"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && exit $ERR_RESSOURCE
|
||||
fi
|
||||
|
||||
TLS_DATA_FILE="$TESTSSL_INSTALL_DIR/etc/tls_data.txt"
|
||||
@ -14660,7 +14704,7 @@ get_install_dir() {
|
||||
outln "Please note from 2.9dev on $PROG_NAME needs files in \"\$TESTSSL_INSTALL_DIR/etc/\" to function correctly."
|
||||
outln
|
||||
ignore_no_or_lame "Type \"yes\" to ignore this warning and proceed at your own risk" "yes"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && exit $ERR_RESSOURCE
|
||||
else
|
||||
: # see #705, in a nutshell: not portable to initialize a global array inside a function. Thus it'll be done in main part below
|
||||
fi
|
||||
@ -14718,7 +14762,7 @@ find_openssl_binary() {
|
||||
# no ERRFILE initialized yet, thus we use /dev/null for stderr directly
|
||||
$OPENSSL version -a 2>/dev/null >/dev/null
|
||||
if [[ $? -ne 0 ]] || [[ ! -x "$OPENSSL" ]]; then
|
||||
fatal "cannot exec or find any openssl binary" -5
|
||||
fatal "cannot exec or find any openssl binary" $ERR_OSSLBIN
|
||||
fi
|
||||
|
||||
# http://www.openssl.org/news/openssl-notes.html
|
||||
@ -14837,7 +14881,7 @@ find_openssl_binary() {
|
||||
outln
|
||||
prln_warning " Necessary binary \"timeout\" not found."
|
||||
ignore_no_or_lame " Continue without timeout? " "yes"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && exit $ERR_OSSLBIN
|
||||
unset OPENSSL_TIMEOUT
|
||||
fi
|
||||
fi
|
||||
@ -14870,7 +14914,7 @@ check4openssl_oldfarts() {
|
||||
fileout_insert_warning "too_old_openssl" "WARN" "Update openssl binaries or compile from https://github.com/PeterMosmans/openssl .";;
|
||||
esac
|
||||
ignore_no_or_lame " Type \"yes\" to accept false negatives or positives" "yes"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
|
||||
fi
|
||||
outln
|
||||
}
|
||||
@ -14883,7 +14927,7 @@ check_bsd_mount() {
|
||||
elif mount | grep '/dev/fd' | grep -q fdescfs; then
|
||||
:
|
||||
else
|
||||
fatal "You need to mount fdescfs on FreeBSD: \"mount -t fdescfs fdesc /dev/fd\"" -10
|
||||
fatal "You need to mount fdescfs on FreeBSD: \"mount -t fdescfs fdesc /dev/fd\"" $ERR_OTHERCLIENT
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@ -15012,12 +15056,12 @@ EOF
|
||||
}
|
||||
|
||||
maketempf() {
|
||||
TEMPDIR=$(mktemp -d /tmp/testssl.XXXXXX) || exit -6
|
||||
TMPFILE=$TEMPDIR/tempfile.txt || exit -6
|
||||
TEMPDIR=$(mktemp -d /tmp/testssl.XXXXXX) || exit $ERR_FCREATE
|
||||
TMPFILE=$TEMPDIR/tempfile.txt || exit $ERR_FCREATE
|
||||
if [[ "$DEBUG" -eq 0 ]]; then
|
||||
ERRFILE="/dev/null"
|
||||
else
|
||||
ERRFILE=$TEMPDIR/errorfile.txt || exit -6
|
||||
ERRFILE=$TEMPDIR/errorfile.txt || exit $ERR_FCREATE
|
||||
fi
|
||||
HOSTCERT=$TEMPDIR/host_certificate.pem
|
||||
}
|
||||
@ -15234,28 +15278,24 @@ cleanup() {
|
||||
|
||||
child_error() {
|
||||
cleanup
|
||||
exit 1
|
||||
exit $ERR_CHILD
|
||||
}
|
||||
|
||||
# arg1: string to print / to write to file
|
||||
# arg2: error code, is a global, see ERR_* above
|
||||
#
|
||||
fatal() {
|
||||
outln
|
||||
prln_magenta "Fatal error: $1" >&2
|
||||
fileout "fatal_error" "ERROR" "$1"
|
||||
exit $2
|
||||
# 1: cmd line error
|
||||
# 2: secondary/other cmd line error
|
||||
# -1: other user error
|
||||
# -2: network problem
|
||||
# -3: s.th. fatal is not supported in the client
|
||||
# -4: s.th. is not supported yet
|
||||
# -5: openssl problem
|
||||
}
|
||||
|
||||
|
||||
# for now only GOST engine
|
||||
initialize_engine(){
|
||||
grep -q '^# testssl config file' "$OPENSSL_CONF" 2>/dev/null && return 0 # have been here already
|
||||
|
||||
# for now only GOST engine
|
||||
grep -q '^# testssl config file' "$OPENSSL_CONF" 2>/dev/null && \
|
||||
return 0 # We have been here already
|
||||
if "$NO_ENGINE"; then
|
||||
return 1
|
||||
elif $OPENSSL engine gost -v 2>&1 | egrep -q 'invalid command|no such engine'; then
|
||||
@ -15272,7 +15312,7 @@ initialize_engine(){
|
||||
if [[ -n "$OPENSSL_CONF" ]]; then
|
||||
prln_warning "For now I am providing the config file to have GOST support"
|
||||
else
|
||||
OPENSSL_CONF=$TEMPDIR/gost.conf || exit -6
|
||||
OPENSSL_CONF=$TEMPDIR/gost.conf
|
||||
# see https://www.mail-archive.com/openssl-users@openssl.org/msg65395.html
|
||||
cat >$OPENSSL_CONF << EOF
|
||||
# testssl config file for openssl
|
||||
@ -15291,6 +15331,7 @@ default_algorithms = ALL
|
||||
CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet
|
||||
|
||||
EOF
|
||||
[[ $? -ne 0 ]] && exit $ERR_OSSLBIN
|
||||
export OPENSSL_CONF
|
||||
fi
|
||||
fi
|
||||
@ -15333,9 +15374,9 @@ parse_hn_port() {
|
||||
# if there's a trailing ':' probably a starttls/application protocol was specified
|
||||
if grep -q ':$' <<< "$NODE"; then
|
||||
if grep -wq http <<< "$NODE"; then
|
||||
fatal "\"http\" is not what you meant probably" 1
|
||||
fatal "\"http\" is not what you meant probably" $ERR_CMDLINE
|
||||
else
|
||||
fatal "\"$1\" is not a valid URI" 1
|
||||
fatal "\"$1\" is not a valid URI" $ERR_CMDLINE
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -15364,41 +15405,6 @@ parse_hn_port() {
|
||||
}
|
||||
|
||||
|
||||
# now do logging if instructed
|
||||
# arg1: for testing mx records name we put a name of logfile in here, otherwise we get strange file names
|
||||
prepare_logging() {
|
||||
local fname_prefix="$1"
|
||||
local filename_provided=false
|
||||
|
||||
[[ -n "$LOGFILE" ]] && [[ ! -d "$LOGFILE" ]] && filename_provided=true
|
||||
|
||||
# Similar to html_header():
|
||||
! "$do_logging" && return 0
|
||||
"$do_mass_testing" && ! "$filename_provided" && return 0
|
||||
"$CHILD_MASS_TESTING" && "$filename_provided" && return 0
|
||||
|
||||
[[ -z "$fname_prefix" ]] && fname_prefix="${FNAME_PREFIX}${NODE}"_p"${PORT}"
|
||||
|
||||
if [[ -z "$LOGFILE" ]]; then
|
||||
LOGFILE="$fname_prefix-$(date +"%Y%m%d-%H%M".log)"
|
||||
elif [[ -d "$LOGFILE" ]]; then
|
||||
# actually we were instructed to place all files in a DIR instead of the current working dir
|
||||
LOGFILE="$LOGFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".log)"
|
||||
else
|
||||
: # just for clarity: a log file was specified, no need to do anything else
|
||||
fi
|
||||
|
||||
if ! "$APPEND"; then
|
||||
[[ -s "$LOGFILE" ]] && fatal "non-empty \"$LOGFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||
fi
|
||||
tmln_out "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>"$LOGFILE"
|
||||
tmln_out "## at $HNAME:$OPENSSL_LOCATION" >>"$LOGFILE"
|
||||
tmln_out "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>"$LOGFILE"
|
||||
tmln_out "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>"$LOGFILE"
|
||||
exec > >(tee -a -i "$LOGFILE")
|
||||
}
|
||||
|
||||
|
||||
# args: string containing ip addresses
|
||||
filter_ip6_address() {
|
||||
local a
|
||||
@ -15459,7 +15465,7 @@ get_local_a() {
|
||||
# does a hard exit if no lookup binary is provided
|
||||
check_resolver_bins() {
|
||||
if ! type -p dig &> /dev/null && ! type -p host &> /dev/null && ! type -p drill &> /dev/null && ! type -p nslookup &>/dev/null; then
|
||||
fatal "Neither \"dig\", \"host\", \"drill\" or \"nslookup\" is present" "-3"
|
||||
fatal "Neither \"dig\", \"host\", \"drill\" or \"nslookup\" is present" $ERR_DNSBIN
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@ -15479,7 +15485,7 @@ get_a_record() {
|
||||
elif type -p dig &>/dev/null; then
|
||||
ip4=$(filter_ip4_address $(dig @224.0.0.251 -p 5353 +short -t a +notcp "$1" 2>/dev/null | sed '/^;;/d'))
|
||||
else
|
||||
fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." -3
|
||||
fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." $ERR_DNSBIN
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$ip4" ]]; then
|
||||
@ -15520,7 +15526,7 @@ get_aaaa_record() {
|
||||
elif type -p dig &>/dev/null; then
|
||||
ip6=$(filter_ip6_address $(dig @ff02::fb -p 5353 -t aaaa +short +notcp "$NODE"))
|
||||
else
|
||||
fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." -3
|
||||
fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." $ERR_DNSBIN
|
||||
fi
|
||||
elif type -p host &> /dev/null ; then
|
||||
ip6=$(filter_ip6_address $(host -t aaaa "$1" | awk '/address/ { print $NF }'))
|
||||
@ -15634,7 +15640,7 @@ get_mx_record() {
|
||||
elif type -p nslookup &> /dev/null; then
|
||||
mxs="$(strip_lf "$(nslookup -type=MX "$1" 2>/dev/null | awk '/mail exchanger/ { print $(NF-1), $NF }')")"
|
||||
else
|
||||
fatal "No dig, host, drill or nslookup" -3
|
||||
fatal "No dig, host, drill or nslookup" $ERR_DNSBIN
|
||||
fi
|
||||
OPENSSL_CONF="$saved_openssl_conf"
|
||||
echo "$mxs"
|
||||
@ -15664,7 +15670,7 @@ determine_ip_addresses() {
|
||||
elif is_ipv6addr "$NODEIP"; then
|
||||
ip6="$NODEIP"
|
||||
else
|
||||
fatal "couldn't identify supplied \"CMDLINE_IP\"" 2
|
||||
fatal "couldn't identify supplied \"CMDLINE_IP\"" $ERR_DNSLOOKUP
|
||||
fi
|
||||
elif is_ipv4addr "$NODE"; then
|
||||
ip4="$NODE" # only an IPv4 address was supplied as an argument, no hostname
|
||||
@ -15699,9 +15705,9 @@ determine_ip_addresses() {
|
||||
fi
|
||||
if [[ -z "$IPADDRs" ]]; then
|
||||
if [[ -n "$ip6" ]]; then
|
||||
fatal "Only IPv6 address(es) for \"$NODE\" available, maybe add \"-6\" to $0" -1
|
||||
fatal "Only IPv6 address(es) for \"$NODE\" available, maybe add \"-6\" to $0" $ERR_DNSLOOKUP
|
||||
else
|
||||
fatal "No IPv4/IPv6 address(es) for \"$NODE\" available" -1
|
||||
fatal "No IPv4/IPv6 address(es) for \"$NODE\" available" $ERR_DNSLOOKUP
|
||||
fi
|
||||
fi
|
||||
return 0 # IPADDR and IP46ADDR is set now
|
||||
@ -15741,20 +15747,20 @@ determine_rdns() {
|
||||
check_proxy() {
|
||||
if [[ -n "$PROXY" ]]; then
|
||||
if ! "$HAS_PROXY"; then
|
||||
fatal "Your $OPENSSL is too old to support the \"-proxy\" option" -5
|
||||
fatal "Your $OPENSSL is too old to support the \"-proxy\" option" $ERR_OSSLBIN
|
||||
fi
|
||||
if [[ "$PROXY" == "auto" ]]; then
|
||||
# get $ENV (https_proxy is the one we care about)
|
||||
PROXY="${https_proxy#*\/\/}"
|
||||
[[ -z "$PROXY" ]] && PROXY="${http_proxy#*\/\/}"
|
||||
[[ -z "$PROXY" ]] && fatal "you specified \"--proxy=auto\" but \"\$http(s)_proxy\" is empty" 2
|
||||
[[ -z "$PROXY" ]] && fatal "you specified \"--proxy=auto\" but \"\$http(s)_proxy\" is empty" $ERR_CMDLINE
|
||||
fi
|
||||
# strip off http/https part if supplied:
|
||||
PROXY="${PROXY/http\:\/\//}"
|
||||
PROXY="${PROXY/https\:\/\//}"
|
||||
PROXYNODE="${PROXY%:*}"
|
||||
PROXYPORT="${PROXY#*:}"
|
||||
is_number "$PROXYPORT" || fatal "Proxy port cannot be determined from \"$PROXY\"" 2
|
||||
is_number "$PROXYPORT" || fatal "Proxy port cannot be determined from \"$PROXY\"" $ERR_CMDLINE
|
||||
|
||||
#if is_ipv4addr "$PROXYNODE" || is_ipv6addr "$PROXYNODE" ; then
|
||||
# IPv6 via openssl -proxy: that doesn't work. Sockets does
|
||||
@ -15763,7 +15769,7 @@ check_proxy() {
|
||||
PROXYIP="$PROXYNODE"
|
||||
else
|
||||
PROXYIP="$(get_a_record "$PROXYNODE" 2>/dev/null | grep -v alias | sed 's/^.*address //')"
|
||||
[[ -z "$PROXYIP" ]] && fatal "Proxy IP cannot be determined from \"$PROXYNODE\"" "2"
|
||||
[[ -z "$PROXYIP" ]] && fatal "Proxy IP cannot be determined from \"$PROXYNODE\"" $ERR_CMDLINE
|
||||
fi
|
||||
PROXY="-proxy $PROXYIP:$PROXYPORT"
|
||||
fi
|
||||
@ -15853,7 +15859,7 @@ determine_optimal_proto() {
|
||||
if [[ "$OPTIMAL_PROTO" == "-ssl2" ]]; then
|
||||
prln_magenta "$NODEIP:$PORT appears to only support SSLv2."
|
||||
ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
|
||||
fi
|
||||
fi
|
||||
grep -q '^Server Temp Key' $TMPFILE && HAS_DH_BITS=true # FIX #190
|
||||
@ -15868,7 +15874,7 @@ determine_optimal_proto() {
|
||||
tmpfile_handle $FUNCNAME.txt
|
||||
prln_bold "doesn't seem to be a TLS/SSL enabled server";
|
||||
ignore_no_or_lame " The results might look ok but they could be nonsense. Really proceed ? (\"yes\" to continue)" "yes"
|
||||
[[ $? -ne 0 ]] && exit -2
|
||||
[[ $? -ne 0 ]] && $ERR_CLUELESS
|
||||
fi
|
||||
|
||||
# NOTE: The following code is only needed as long as draft versions of TLSv1.3 prior to draft 23
|
||||
@ -15903,8 +15909,8 @@ determine_service() {
|
||||
|
||||
if ! fd_socket; then # check if we can connect to $NODEIP:$PORT
|
||||
[[ -n "$PROXY" ]] && \
|
||||
fatal "You're sure $PROXYNODE:$PROXYPORT allows tunneling here? Can't connect to \"$NODEIP:$PORT\"" -2 || \
|
||||
fatal "Can't connect to \"$NODEIP:$PORT\"\nMake sure a firewall is not between you and your scanning target!" -2
|
||||
fatal "You're sure $PROXYNODE:$PROXYPORT allows tunneling here? Can't connect to \"$NODEIP:$PORT\"" $ERR_CONNECT || \
|
||||
fatal "Can't connect to \"$NODEIP:$PORT\"\nMake sure a firewall is not between you and your scanning target!" $ERR_CONNECT
|
||||
fi
|
||||
close_socket
|
||||
|
||||
@ -15934,7 +15940,7 @@ determine_service() {
|
||||
NODEIP="$NODE"
|
||||
if [[ -n "$XMPP_HOST" ]]; then
|
||||
if ! "$HAS_XMPP"; then
|
||||
fatal "Your $OPENSSL does not support the \"-xmpphost\" option" -5
|
||||
fatal "Your $OPENSSL does not support the \"-xmpphost\" option" $ERR_OSSLBIN
|
||||
fi
|
||||
STARTTLS="$STARTTLS -xmpphost $XMPP_HOST" # small hack -- instead of changing calls all over the place
|
||||
# see http://xmpp.org/rfcs/rfc3920.html
|
||||
@ -15947,26 +15953,26 @@ determine_service() {
|
||||
NODE=${rDNS%%.}
|
||||
NODEIP=${rDNS%%.}
|
||||
else
|
||||
fatal "No DNS supplied and no PTR record available which I can try for XMPP" -1
|
||||
fatal "No DNS supplied and no PTR record available which I can try for XMPP" $ERR_DNSLOOKUP
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif [[ "$protocol" == postgres ]]; then
|
||||
# Check if openssl version supports postgres.
|
||||
if ! "$HAS_POSTGRES"; then
|
||||
fatal "Your $OPENSSL does not support the \"-starttls postgres\" option" -5
|
||||
fatal "Your $OPENSSL does not support the \"-starttls postgres\" option" $ERR_OSSLBIN
|
||||
fi
|
||||
elif [[ "$protocol" == mysql ]]; then
|
||||
# Check if openssl version supports mysql.
|
||||
if ! "$HAS_MYSQL"; then
|
||||
fatal "Your $OPENSSL does not support the \"-starttls mysql\" option" -5
|
||||
fatal "Your $OPENSSL does not support the \"-starttls mysql\" option" $ERR_OSSLBIN
|
||||
fi
|
||||
fi
|
||||
$OPENSSL s_client $(s_client_options "-connect $NODEIP:$PORT $PROXY $BUGS $STARTTLS") 2>$ERRFILE >$TMPFILE </dev/null
|
||||
if [[ $? -ne 0 ]]; then
|
||||
debugme cat $TMPFILE | head -25
|
||||
outln
|
||||
fatal " $OPENSSL couldn't establish STARTTLS via $protocol to $NODEIP:$PORT" -2
|
||||
fatal " $OPENSSL couldn't establish STARTTLS via $protocol to $NODEIP:$PORT" $ERR_CONNECT
|
||||
fi
|
||||
grep -q '^Server Temp Key' $TMPFILE && HAS_DH_BITS=true # FIX #190
|
||||
out " Service set:$CORRECT_SPACES STARTTLS via "
|
||||
@ -15977,7 +15983,7 @@ determine_service() {
|
||||
outln
|
||||
;;
|
||||
*) outln
|
||||
fatal "momentarily only ftp, smtp, pop3, imap, xmpp, telnet, ldap, postgres, and mysql allowed" -4
|
||||
fatal "momentarily only ftp, smtp, pop3, imap, xmpp, telnet, ldap, postgres, and mysql allowed" $ERR_CMDLINE
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
@ -16237,12 +16243,12 @@ nmap_to_plain_file() {
|
||||
# yes, greppable
|
||||
if [[ $(grep -c Status "$FNAME") -ge 1 ]]; then
|
||||
[[ $(grep -c '\/open\/' "$FNAME") -eq 0 ]] && \
|
||||
fatal "Nmap file $FNAME should contain at least one open port" -1
|
||||
fatal "Nmap file $FNAME should contain at least one open port" $ERR_FNAMEPARSE
|
||||
else
|
||||
fatal "strange, nmap grepable misses \"Status\"" -1
|
||||
fi
|
||||
else
|
||||
fatal "Nmap file $FNAME is not in grep(p)able format (-oG filename.g(n)map)" -1
|
||||
fatal "Nmap file $FNAME is not in grep(p)able format (-oG filename.g(n)map)" $ERR_FNAMEPARSE
|
||||
fi
|
||||
# strip extension and create output file *.txt in same folder
|
||||
target_fname="${FNAME%.*}.txt"
|
||||
@ -16253,7 +16259,7 @@ nmap_to_plain_file() {
|
||||
target_fname="${target_fname##*\/}" # strip path (Unix)
|
||||
target_fname="${target_fname##*\\}" # strip path (Dos)
|
||||
target_fname="$TEMPDIR/$target_fname"
|
||||
> "${target_fname}" || fatal "Cannot create \"${target_fname}\"" -1
|
||||
> "${target_fname}" || fatal "Cannot create \"${target_fname}\"" $ERR_FCREATE
|
||||
fi
|
||||
|
||||
# Line x: "Host: AAA.BBB.CCC.DDD (<FQDN>) Status: Up"
|
||||
@ -16285,7 +16291,7 @@ nmap_to_plain_file() {
|
||||
[[ "$DEBUG" -ge 1 ]] && echo
|
||||
|
||||
[[ -s "$target_fname" ]] || \
|
||||
fatal "Couldn't find any open port in $FNAME" -3
|
||||
fatal "Couldn't find any open port in $FNAME" $ERR_FNAMEPARSE
|
||||
export FNAME=$target_fname
|
||||
}
|
||||
|
||||
@ -16296,7 +16302,7 @@ run_mass_testing() {
|
||||
local saved_fname="$FNAME"
|
||||
|
||||
if [[ ! -r "$FNAME" ]] && "$IKNOW_FNAME"; then
|
||||
fatal "Can't read file \"$FNAME\"" "2"
|
||||
fatal "Can't read file \"$FNAME\"" $ERR_FNAMEPARSE
|
||||
fi
|
||||
|
||||
if [[ "$(head -1 "$FNAME")" =~ (Nmap [4-8])(.*)( scan initiated )(.*) ]]; then
|
||||
@ -16369,7 +16375,7 @@ run_mass_testing_parallel() {
|
||||
local saved_fname="$FNAME"
|
||||
|
||||
if [[ ! -r "$FNAME" ]] && $IKNOW_FNAME; then
|
||||
fatal "Can't read file \"$FNAME\"" "2"
|
||||
fatal "Can't read file \"$FNAME\"" $ERR_FNAMEPARSE
|
||||
fi
|
||||
|
||||
if [[ "$(head -1 "$FNAME")" =~ (Nmap [4-8])(.*)( scan initiated )(.*) ]]; then
|
||||
@ -16663,7 +16669,7 @@ parse_cmd_line() {
|
||||
find_openssl_binary
|
||||
prepare_debug
|
||||
mybanner
|
||||
exit 0
|
||||
exit $ALLOK
|
||||
;;
|
||||
--mx)
|
||||
do_mx_all_ips=true
|
||||
@ -16689,7 +16695,7 @@ parse_cmd_line() {
|
||||
NODNS="$(parse_opt_equal_sign "$1" "$2")"
|
||||
[[ $? -eq 0 ]] && shift
|
||||
if [[ "$NODNS" != none ]] && [[ "$NODNS" != min ]]; then
|
||||
fatal "Value for nodns switch can be either \"min\" or \"none\""
|
||||
fatal "Value for nodns switch can be either \"min\" or \"none\"" $ERR_CMDLINE
|
||||
fi
|
||||
;;
|
||||
-V|-V=*|--local|--local=*) # attention, this could have a value or not!
|
||||
@ -16947,22 +16953,22 @@ parse_cmd_line() {
|
||||
do_logging=true
|
||||
;;
|
||||
--json)
|
||||
$do_pretty_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" 251
|
||||
$do_pretty_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" $ERR_CMDLINE
|
||||
do_json=true
|
||||
;; # DEFINITION of JSONFILE is not arg specified: automagically in parse_hn_port()
|
||||
# following does the same but we can specify a log location additionally
|
||||
--jsonfile|--jsonfile=*|-oj|-oj=*)
|
||||
$do_pretty_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" 251
|
||||
$do_pretty_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" $ERR_CMDLINE
|
||||
JSONFILE="$(parse_opt_equal_sign "$1" "$2")"
|
||||
[[ $? -eq 0 ]] && shift
|
||||
do_json=true
|
||||
;;
|
||||
--json-pretty)
|
||||
$do_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" 251
|
||||
$do_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" $ERR_CMDLINE
|
||||
do_pretty_json=true
|
||||
;;
|
||||
--jsonfile-pretty|--jsonfile-pretty=*|-oJ|-oJ=*)
|
||||
$do_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" 251
|
||||
$do_json && JSONHEADER=false && fatal "flat and pretty JSON output are mutually exclusive" $ERR_CMDLINE
|
||||
JSONFILE="$(parse_opt_equal_sign "$1" "$2")"
|
||||
[[ $? -eq 0 ]] && shift
|
||||
do_pretty_json=true
|
||||
@ -17075,19 +17081,20 @@ parse_cmd_line() {
|
||||
|
||||
# Show usage if no further options were specified
|
||||
if [[ -z "$1" ]] && [[ -z "$FNAME" ]] && ! "$do_display_only"; then
|
||||
fatal "URI missing" "1"
|
||||
fatal "URI missing" $ERR_CMDLINE
|
||||
else
|
||||
# left off here is the URI
|
||||
URI="$1"
|
||||
# parameter after URI supplied:
|
||||
[[ -n "$2" ]] && fatal "URI comes last" "1"
|
||||
[[ -n "$2" ]] && fatal "URI comes last" $ERR_CMDLINE
|
||||
fi
|
||||
[[ $CMDLINE_IP == one ]] && [[ "$NODNS" == none ]] && fatal "\"--ip=one\" and \"--nodns=none\" don't work together" 2
|
||||
"$do_mx_all_ips" && [[ "$NODNS" == none ]] && fatal "\"--mx\" and \"--nodns=none\" don't work together" 2
|
||||
[[ $CMDLINE_IP == one ]] && [[ "$NODNS" == none ]] && fatal "\"--ip=one\" and \"--nodns=none\" don't work together" $ERR_CMDLINE
|
||||
"$do_mx_all_ips" && [[ "$NODNS" == none ]] && fatal "\"--mx\" and \"--nodns=none\" don't work together" $ERR_CMDLINE
|
||||
|
||||
ADDITIONAL_CA_FILES="${ADDITIONAL_CA_FILES//,/ }"
|
||||
for fname in $ADDITIONAL_CA_FILES; do
|
||||
[[ -s "$fname" ]] || fatal "CA file \"$fname\" does not exist" -2
|
||||
grep -q "BEGIN CERTIFICATE" "$fname" || fatal "\"$fname\" is not CA file in PEM format" -2
|
||||
[[ -s "$fname" ]] || fatal "CA file \"$fname\" does not exist" $ERR_RESSOURCE
|
||||
grep -q "BEGIN CERTIFICATE" "$fname" || fatal "\"$fname\" is not CA file in PEM format" $ERR_RESSOURCE
|
||||
done
|
||||
|
||||
[[ "$DEBUG" -ge 5 ]] && debug_globals
|
||||
@ -17143,7 +17150,7 @@ lets_roll() {
|
||||
fi
|
||||
stopwatch initialized
|
||||
|
||||
[[ -z "$NODEIP" ]] && fatal "$NODE doesn't resolve to an IP address" 2
|
||||
[[ -z "$NODEIP" ]] && fatal "$NODE doesn't resolve to an IP address" $ERR_DNSLOOKUP
|
||||
nodeip_to_proper_ip6
|
||||
reset_hostdepended_vars
|
||||
determine_rdns # Returns always zero or has already exited if fatal error occurred
|
||||
@ -17153,8 +17160,8 @@ lets_roll() {
|
||||
determine_service "$1" # STARTTLS service? Other will be determined here too. Returns always 0 or has already exited if fatal error occurred
|
||||
|
||||
# "secret" devel options --devel:
|
||||
$do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets "" "true"; echo "$?" ; exit 0; }
|
||||
$do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER" "all"; echo "$?" ; exit 0; }
|
||||
$do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets "" "true"; echo "$?" ; exit $ALLOK; }
|
||||
$do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER" "all"; echo "$?" ; exit $ALLOK; }
|
||||
$do_cipher_match && { fileout_section_header $section_number false; run_cipher_match ${single_cipher}; }
|
||||
((section_number++))
|
||||
|
||||
@ -17302,7 +17309,7 @@ lets_roll() {
|
||||
prepare_logging
|
||||
|
||||
if ! determine_ip_addresses; then
|
||||
fatal "No IP address could be determined" 2
|
||||
fatal "No IP address could be determined" $ERR_DNSLOOKUP
|
||||
fi
|
||||
if [[ $(count_words "$IPADDRs") -gt 1 ]]; then # we have more than one ipv4 address to check
|
||||
pr_bold "Testing all IPv4 addresses (port $PORT): "; outln "$IPADDRs"
|
||||
|
Loading…
Reference in New Issue
Block a user