mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-01-11 03:00:57 +01:00
parent
dce019488f
commit
f2bbba3b99
157
testssl.sh
157
testssl.sh
@ -83,7 +83,7 @@ readonly PS4='${LINENO}> ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
|||||||
# make sure that temporary files are cleaned up after use in ANY case
|
# make sure that temporary files are cleaned up after use in ANY case
|
||||||
trap "cleanup" QUIT EXIT
|
trap "cleanup" QUIT EXIT
|
||||||
|
|
||||||
readonly VERSION="2.8pre1"
|
readonly VERSION="2.8"
|
||||||
readonly SWCONTACT="dirk aet testssl dot sh"
|
readonly SWCONTACT="dirk aet testssl dot sh"
|
||||||
egrep -q "dev|rc" <<< "$VERSION" && \
|
egrep -q "dev|rc" <<< "$VERSION" && \
|
||||||
SWURL="https://testssl.sh/dev/" ||
|
SWURL="https://testssl.sh/dev/" ||
|
||||||
@ -162,6 +162,7 @@ APPEND=${APPEND:-false} # append to csv/json file instead of ove
|
|||||||
HAS_IPv6=${HAS_IPv6:-false} # if you have OpenSSL with IPv6 support AND IPv6 networking set it to yes
|
HAS_IPv6=${HAS_IPv6:-false} # if you have OpenSSL with IPv6 support AND IPv6 networking set it to yes
|
||||||
UNBRACKTD_IPV6=${UNBRACKTD_IPV6:-false} # some versions of OpenSSL (like Gentoo) don't support [bracketed] IPv6 addresses
|
UNBRACKTD_IPV6=${UNBRACKTD_IPV6:-false} # some versions of OpenSSL (like Gentoo) don't support [bracketed] IPv6 addresses
|
||||||
SERVER_SIZE_LIMIT_BUG=false # Some servers have either a ClientHello total size limit or cipher limit of ~128 ciphers (e.g. old ASAs)
|
SERVER_SIZE_LIMIT_BUG=false # Some servers have either a ClientHello total size limit or cipher limit of ~128 ciphers (e.g. old ASAs)
|
||||||
|
CHILD_MASS_TESTING=${CHILD_MASS_TESTING:-false} # child of $do_mass_testing
|
||||||
|
|
||||||
# tuning vars, can not be set by a cmd line switch
|
# tuning vars, can not be set by a cmd line switch
|
||||||
EXPERIMENTAL=${EXPERIMENTAL:-false}
|
EXPERIMENTAL=${EXPERIMENTAL:-false}
|
||||||
@ -566,6 +567,13 @@ fileout_section_header() {
|
|||||||
"$2" && str="$(fileout_section_footer false)"
|
"$2" && str="$(fileout_section_footer false)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileout_separator() {
|
||||||
|
if "$JSONHEADER"; then
|
||||||
|
"$do_json" && echo -n "," >> "$JSONFILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fileout_section_footer() {
|
fileout_section_footer() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -587,6 +595,8 @@ fileout_json_print_parameter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileout_json_finding() {
|
fileout_json_finding() {
|
||||||
|
local target
|
||||||
|
|
||||||
if "$do_json"; then
|
if "$do_json"; then
|
||||||
"$FIRST_FINDING" || echo -n "," >> "$JSONFILE"
|
"$FIRST_FINDING" || echo -n "," >> "$JSONFILE"
|
||||||
echo -e " {" >> "$JSONFILE"
|
echo -e " {" >> "$JSONFILE"
|
||||||
@ -601,6 +611,7 @@ fileout_json_finding() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
##################### FILE FORMATING #########################
|
##################### FILE FORMATING #########################
|
||||||
|
|
||||||
fileout_footer() {
|
fileout_footer() {
|
||||||
@ -624,19 +635,21 @@ fileout() {
|
|||||||
"$FIRST_FINDING" && FIRST_FINDING=false
|
"$FIRST_FINDING" && FIRST_FINDING=false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
json_header() {
|
json_header() {
|
||||||
local fname_prefix
|
local fname_prefix
|
||||||
|
local filename_provided=false
|
||||||
|
|
||||||
# Similar to HTML: Don't create headers and footers in the following scenarios:
|
[[ -n "$JSONFILE" ]] && [[ ! -d "$JSONFILE" ]] && filename_provided=true
|
||||||
|
|
||||||
|
# Don't create headers and footers in the following scenarios:
|
||||||
# * no JSON/CSV output is being created.
|
# * no JSON/CSV output is being created.
|
||||||
# * mass testing is being performed and each test will have its own file.
|
# * mass testing is being performed and each test will have its own file.
|
||||||
# * this is an individual test within a mass test and all output is being placed in a single file.
|
# * this is an individual test within a mass test and all output is being placed in a single file.
|
||||||
if ! "$do_json" || \
|
! "$do_json" && JSONHEADER=false && return 0
|
||||||
( "$do_mass_testing" && ( [[ -z "$JSONFILE" ]] || [[ -d "$JSONFILE" ]] ) ) || \
|
"$do_mass_testing" && ! "$filename_provided" && JSONHEADER=false && return 0
|
||||||
( "$APPEND" && [[ -n "$JSONFILE" ]] && [[ ! -d "$JSONFILE" ]] ); then
|
"$CHILD_MASS_TESTING" && "$filename_provided" && JSONHEADER=false && return 0
|
||||||
JSONHEADER=false
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if "$do_display_only"; then
|
if "$do_display_only"; then
|
||||||
fname_prefix="local-ciphers"
|
fname_prefix="local-ciphers"
|
||||||
elif "$do_mass_testing"; then
|
elif "$do_mass_testing"; then
|
||||||
@ -644,32 +657,36 @@ json_header() {
|
|||||||
elif "$do_mx_all_ips"; then
|
elif "$do_mx_all_ips"; then
|
||||||
fname_prefix="mx-$URI"
|
fname_prefix="mx-$URI"
|
||||||
else
|
else
|
||||||
( [[ -z "$JSONFILE" ]] || [[ -d "$JSONFILE" ]] ) && parse_hn_port "${URI}"
|
! "$filename_provided" && [[ -z "$NODE" ]] && parse_hn_port "${URI}"
|
||||||
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
||||||
fname_prefix="${NODE}"_"${PORT}"
|
fname_prefix="${NODE}"_"${PORT}"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$JSONFILE" ]] && [[ ! -d "$JSONFILE" ]]; then
|
if [[ -z "$JSONFILE" ]]; then
|
||||||
rm -f "$JSONFILE"
|
|
||||||
elif [[ -z "$JSONFILE" ]]; then
|
|
||||||
JSONFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
JSONFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
||||||
else
|
elif [[ -d "$JSONFILE" ]]; then
|
||||||
JSONFILE=$JSONFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
JSONFILE=$JSONFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".json)
|
||||||
fi
|
fi
|
||||||
"$do_json" && printf "[\n" > "$JSONFILE"
|
if "$APPEND"; then
|
||||||
#FIRST_FINDING=false
|
JSONHEADER=false
|
||||||
|
else
|
||||||
|
[[ -e "$JSONFILE" ]] && outln && fatal "\"$JSONFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||||
|
"$do_json" && printf "[\n" > "$JSONFILE"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
csv_header() {
|
csv_header() {
|
||||||
local fname_prefix
|
local fname_prefix
|
||||||
|
local filename_provided=false
|
||||||
|
|
||||||
|
[[ -n "$CSVFILE" ]] && [[ ! -d "$CSVFILE" ]] && filename_provided=true
|
||||||
|
|
||||||
|
# CSV similar to JSON:
|
||||||
|
! "$do_csv" && CSVHEADER=false && return 0
|
||||||
|
"$do_mass_testing" && ! "$filename_provided" && CSVHEADER=false && return 0
|
||||||
|
"$CHILD_MASS_TESTING" && "$filename_provided" && CSVHEADER=false && return 0
|
||||||
|
|
||||||
# CSV similar:
|
|
||||||
if ! "$do_csv" || \
|
|
||||||
( "$do_mass_testing" && ( [[ -z "$CSVFILE" ]] || [[ -d "$CSVFILE" ]] ) ) || \
|
|
||||||
( "$APPEND" && [[ -n "$CSVFILE" ]] && [[ ! -d "$CSVFILE" ]] ); then
|
|
||||||
CSVHEADER=false
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if "$do_display_only"; then
|
if "$do_display_only"; then
|
||||||
fname_prefix="local-ciphers"
|
fname_prefix="local-ciphers"
|
||||||
elif "$do_mass_testing"; then
|
elif "$do_mass_testing"; then
|
||||||
@ -677,18 +694,22 @@ csv_header() {
|
|||||||
elif "$do_mx_all_ips"; then
|
elif "$do_mx_all_ips"; then
|
||||||
fname_prefix="mx-$URI"
|
fname_prefix="mx-$URI"
|
||||||
else
|
else
|
||||||
( [[ -z "$CSVFILE" ]] || [[ -d "$CSVFILE" ]] ) && parse_hn_port "${URI}"
|
! "$filename_provided" && [[ -z "$NODE" ]] && parse_hn_port "${URI}"
|
||||||
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
# NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now --> wrong place
|
||||||
fname_prefix="${NODE}"_"${PORT}"
|
fname_prefix="${NODE}"_"${PORT}"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$CSVFILE" ]] && [[ ! -d "$CSVFILE" ]]; then
|
|
||||||
rm -f "$CSVFILE"
|
if [[ -z "$CSVFILE" ]]; then
|
||||||
elif [[ -z "$CSVFILE" ]]; then
|
|
||||||
CSVFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
CSVFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
||||||
else
|
elif [[ -d "$CSVFILE" ]]; then
|
||||||
CSVFILE=$CSVFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
CSVFILE=$CSVFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".csv)
|
||||||
fi
|
fi
|
||||||
"$do_csv" && echo "\"id\",\"fqdn/ip\",\"port\",\"severity\",\"finding\",\"cve\",\"cwe\",\"hint\"" > "$CSVFILE"
|
if "$APPEND"; then
|
||||||
|
CSVHEADER=false
|
||||||
|
else
|
||||||
|
[[ -e "$CSVFILE" ]] && fatal "\"$CSVFILE\" exists. Either use \"--append\" or (re)move it" 1
|
||||||
|
echo "\"id\",\"fqdn/ip\",\"port\",\"severity\",\"finding\",\"cve\",\"cwe\",\"hint\"" > "$CSVFILE"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7868,7 +7889,8 @@ mybanner() {
|
|||||||
local openssl_location="$(which $OPENSSL)"
|
local openssl_location="$(which $OPENSSL)"
|
||||||
local cwd=""
|
local cwd=""
|
||||||
|
|
||||||
$QUIET && return
|
"$QUIET" && return
|
||||||
|
"$CHILD_MASS_TESTING" && return
|
||||||
OPENSSL_NR_CIPHERS=$(count_ciphers "$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>/dev/null)")
|
OPENSSL_NR_CIPHERS=$(count_ciphers "$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>/dev/null)")
|
||||||
[[ -z "$GIT_REL" ]] && \
|
[[ -z "$GIT_REL" ]] && \
|
||||||
idtag="$CVS_REL" || \
|
idtag="$CVS_REL" || \
|
||||||
@ -8036,27 +8058,34 @@ parse_hn_port() {
|
|||||||
# arg1: for testing mx records name we put a name of logfile in here, otherwise we get strange file names
|
# arg1: for testing mx records name we put a name of logfile in here, otherwise we get strange file names
|
||||||
prepare_logging() {
|
prepare_logging() {
|
||||||
local fname_prefix="$1"
|
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="$NODE"
|
[[ -z "$fname_prefix" ]] && fname_prefix="$NODE"
|
||||||
|
|
||||||
if "$do_logging"; then
|
if [[ -z "$LOGFILE" ]]; then
|
||||||
if [[ -z "$LOGFILE" ]]; then
|
LOGFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
||||||
LOGFILE=$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
elif [[ -d "$LOGFILE" ]]; then
|
||||||
elif [[ -d "$LOGFILE" ]]; then
|
# actually we were instructed to place all files in a DIR instead of the current working dir
|
||||||
# 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)
|
||||||
LOGFILE=$LOGFILE/$fname_prefix-$(date +"%Y%m%d-%H%M".log)
|
else
|
||||||
else
|
: # just for clarity: a log file was specified, no need to do anything else
|
||||||
: # just for clarity: a log file was specified, no need to do anything else
|
|
||||||
fi
|
|
||||||
>$LOGFILE
|
|
||||||
outln "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE}
|
|
||||||
outln "## at $HNAME:$OPENSSL_LOCATION" >>${LOGFILE}
|
|
||||||
outln "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>${LOGFILE}
|
|
||||||
outln "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>${LOGFILE}
|
|
||||||
exec > >(tee -a ${LOGFILE})
|
|
||||||
# not decided yet. Maybe good to have a separate file or none at all
|
|
||||||
#exec 2> >(tee -a ${LOGFILE} >&2)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! "$APPEND"; then
|
||||||
|
[[ -e $LOGFILE ]] && fatal "\"$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 ${LOGFILE})
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8556,35 +8585,9 @@ run_mx_all_ips() {
|
|||||||
return $ret
|
return $ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
run_mass_testing_parallel() {
|
|
||||||
local cmdline=""
|
|
||||||
local global_cmdline=${CMDLINE%%--file*}
|
|
||||||
|
|
||||||
if [[ ! -r "$FNAME" ]] && $IKNOW_FNAME; then
|
|
||||||
fatal "Can't read file \"$FNAME\"" "2"
|
|
||||||
fi
|
|
||||||
pr_reverse "====== Running in parallel file batch mode with file=\"$FNAME\" ======"; outln
|
|
||||||
outln "(output is in ....\n)"
|
|
||||||
#FIXME: once this function is being called we need a handler which does the right thing
|
|
||||||
# ==> not overwrite
|
|
||||||
while read cmdline; do
|
|
||||||
cmdline=$(filter_input "$cmdline")
|
|
||||||
[[ -z "$cmdline" ]] && continue
|
|
||||||
[[ "$cmdline" == "EOF" ]] && break
|
|
||||||
cmdline="$0 $global_cmdline --warnings=batch -q $cmdline"
|
|
||||||
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
|
||||||
determine_logfile
|
|
||||||
outln "$cmdline"
|
|
||||||
$cmdline >$LOGFILE &
|
|
||||||
sleep $PARALLEL_SLEEP
|
|
||||||
done < "$FNAME"
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
run_mass_testing() {
|
run_mass_testing() {
|
||||||
local cmdline=""
|
local cmdline=""
|
||||||
|
local first=true
|
||||||
local global_cmdline=${CMDLINE%%--file*}
|
local global_cmdline=${CMDLINE%%--file*}
|
||||||
|
|
||||||
if [[ ! -r "$FNAME" ]] && "$IKNOW_FNAME"; then
|
if [[ ! -r "$FNAME" ]] && "$IKNOW_FNAME"; then
|
||||||
@ -8592,21 +8595,21 @@ run_mass_testing() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
pr_reverse "====== Running in file batch mode with file=\"$FNAME\" ======"; outln "\n"
|
pr_reverse "====== Running in file batch mode with file=\"$FNAME\" ======"; outln "\n"
|
||||||
APPEND=false # Make sure we close out our files
|
|
||||||
while read cmdline; do
|
while read cmdline; do
|
||||||
cmdline=$(filter_input "$cmdline")
|
cmdline=$(filter_input "$cmdline")
|
||||||
[[ -z "$cmdline" ]] && continue
|
[[ -z "$cmdline" ]] && continue
|
||||||
[[ "$cmdline" == "EOF" ]] && break
|
[[ "$cmdline" == "EOF" ]] && break
|
||||||
cmdline="$0 $global_cmdline --warnings=batch -q --append $cmdline"
|
cmdline="$0 $global_cmdline --warnings=batch $cmdline"
|
||||||
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
draw_line "=" $((TERM_WIDTH / 2)); outln;
|
||||||
outln "$cmdline"
|
outln "$cmdline"
|
||||||
$cmdline
|
"$first" || fileout_separator
|
||||||
|
CHILD_MASS_TESTING=true $cmdline
|
||||||
|
first=false
|
||||||
done < "${FNAME}"
|
done < "${FNAME}"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# This initializes boolean global do_* variables. They keep track of what to do
|
# This initializes boolean global do_* variables. They keep track of what to do
|
||||||
# -- as the name insinuates
|
# -- as the name insinuates
|
||||||
initialize_globals() {
|
initialize_globals() {
|
||||||
|
Loading…
Reference in New Issue
Block a user