#!/bin/bash # -*- mode: sh; fill-column: 75; tab-width: 8; coding: utf-8-unix -*- . /usr/local/bin/usr_local_tput.bash || exit 2 PREFIX=/usr/local ROLE=proxy NOW=$( date -u +%y-%m-%d_%H%m ) DEBUG=1 PROXY_WLAN=wlan4 prog=$( basename $0 .bash ) # SocksPolicy Accept in /etc/tor/torrc - required and works with sslscan ip route | grep ^default || { ERROR "not connected" ; exit 1 ; } PATH=$PATH:/sbin BADSSL_SITES=( self-signed.badssl.com expired.badssl.com mixed.badssl.com rc4.badssl.com hsts.badssl.com ) badssl=0 [ "$#" -eq 0 ] && badssl=1 # tests="$MODE" tests="" nodig=1 verbosity=2 outdir=/tmp timeout=20 #[ -f /usr/local/etc/testforge/testforge.bash ] && \ # . /usr/local/etc/testforge/testforge.bash . /usr/local/bin/proxy_ping_lib.bash || \ { ERROR loading /usr/local/bin/proxy_ping_lib.bash ; exit 2; } if [ -f /usr/local/etc/ssl/cacert-testforge.pem ] ; then CAFILE=/usr/local/etc/ssl/cacert-testforge.pem else CERT=$( proxy_ping_update_cacert ) [ "$?" -ne 0 -o -n "$CERT" ] && CAFILE=$CERT || \ CAFILE=/usr/local/etc/ssl/cacert-testforge.pem fi [ -z "$MODE" ] || MODE=`proxy_ping_mode` if [ "$MODE" = tor ] ; then [ -z "PROXY_WLAN" ] && PROXY_WLAN=`proxy_get_if` [ -z "PROXY_WLAN" ] && { ERROR " error getting device $?" ; exit 3 ; } if ip route | grep ^def ; then PROXY_WLAN_IP=$( proxy_get_wlan_ip ) [ -n "$PROXY_WLAN_IP" ] || { ERROR "no PROXY_WLAN_IP" ; exit 4 ; } fi fi usage() { echo "Usage: $0 [OPTIONS] dirs-or-files" echo echo " -B | --badssl - test badssl.org sites" echo " -D | --nodig - no dig sites" echo " -T | --tests - ping tests to run first" echo " -o | --outdir=/tmp - output directory" echo " -v | --verbosity=$verbosity - verbosity 0 least 5 most" echo echo " -V | --version - print version of this script" echo " -h | --help - print this help" } SHORTOPTS="hVBDT:v:" LONGOPTS="help,version:,badssl,nodig,tests:,verbosity:" HOSTS= ARGS=$(getopt --options $SHORTOPTS --longoptions $LONGOPTS -- "$@") [ $? != 0 ] && { ERROR "error parsing getopt" ; exit 5 ; } eval set -- "$ARGS" while true; do case "$1" in # -t --tests -o|--outdir) shift outdir="$1" ;; -v|--verbosity) shift verbosity="$1" ;; -B|--badssl) badssl=1 ;; -D|--nodig) nodig=1 ;; -T|--tests) shift tests="$1" ;; -V|--version) usage exit 0 ;; -h|--help) usage exit 0 ;; '--') shift HOSTS="$*" break ;; *) { ERROR "unrecognized arguments $*" ; exit 6 ; } break ;; esac shift done [ $badssl -ne 0 ] && HOSTS="${BADSSL_SITES[*]}" [ -z "$HOSTS" ] && { ERROR "no arguments $*" ; exit 0 ; } [ -d "$outdir" ] || mkdir -p "$outdir" || { ERROR "mkdir $outdir" ; exit 7 ; } kill_time=$( expr $timeout + 10 ) [ -z "$tests" ] || \ for elt in $tests ; do /usr/local/bin/proxy_ping_test.bash $elt || exit 9$? done if which sslscan 2>/dev/null ; then sslscan='sslscan' SSLSCAN_ARGS="-4 --show-client-cas --show-certificate --bugs --timeout $timeout --tlsall --show-ciphers --no-colour --verbose" else # no proxy support sslscan='' fi # sslscan --show-client-cas - no proxy openssl=openssl OPENSSL_ARGS="-4 -bugs -showcerts" if [ -e /dev/tcp ] && which testssl.bash 2>/dev/null ; then testssl='testssl.bash' TESTSSL_ARGS="--connect-timeout $timeout --openssl-timeout $timeout --standard --vulnerable" #? --ssl-native TESTSSL_ARGS="$TESTSSL_ARGS --add-ca $CAFILE --assume-http --hints --color=0 --append" else # no proxy support testssl='' fi if [ -f /usr/local/bin/scurl.bash ] ; then curl="/usr/local/bin/scurl.bash -- -s -S" else curl='curl -s -S' fi CURL_ARGS="-vvv --cacert $CAFILE --cert-status --connect-timeout $timeout" if [ -f /var/local/bin/analyze-ssl.pl.bash ] ; then analyze=/var/local/bin/analyze-ssl.pl.bash ANALYZE_ARGS="-v --timeout $timeout --CApath $CAFILE --all-ciphers" else analyze="" fi warns=0 OUTR=$outdir/$prog-$NOW if [ $nodig -eq 0 ] ; then for item in $HOSTS ; do i=0 OUTRF=$OUTR.$item if [ $MODE = tor ] ; then torresolve $item > $OUTRF.dig.out 2>&1 retval=$? [ $retval -ne 0 ] && ERROR "torresolve $item $? - see $OUTRF.dig.out" && exit 1$? elif false ; then nslookup $item > $OUTRF.nslookup.out 2>&1 #?[ $? -eq 0 ] || WARN "nslookup $item $? - see $OUTRF.nslookup.out" #?grep NXDOMAIN "$OUTRF.nslookup.out" && WARN "nslookup $item NXDOMAIN - see $OUTRF.nslookup.out" else dig $item > $OUTRF.dig.out 2>&1 [ $? -ne 0 ] && ERROR "dig $item $? - see $OUTRF.dig.out" && exit 1$? grep 'ANSWER: 1' "$OUTRF.dig.out" || ERROR "dig $item no ANSWER - see $OUTRF.dig.out" && exit 2$? fi done fi # [ -r /etc/tor/torrc ] # was https take precedence over socks if [ -n "$socks_proxy" ] ; then SOCKS_HOST=$( echo $socks_proxy|sed -e 's/.*@//' -e 's@/@@g' -e 's/:/ /g' -e 's/socks5* //' -e 's/ .*//' ) SOCKS_PORT=$( echo $socks_proxy|sed -e 's@/@@g' -e 's/:/ /g' -e 's/.* //' ) openssl='torsocks openssl' # --interface lo --dns-interface lo [ -n "$analyze" ] && analyze="torsocks $analyze" [ -n "$testssl" ] && testssl="torsocks $testssl" [ -n "$sslscan" ] && sslscan="torsocks $sslscan" if [ $MODE = tor -o $MODE = selektor ] ; then sudo grep -q "SocksPolicy *accept *$PROXY_WLAN_IP" /etc/tor/torrc || \ { WARN "need SocksPolicy accept $PROXY_WLAN_IP in /etc/tor/torrc" ; } fi CURL_ARGS="$CURL_ARGS --proxy $socks_proxy " if [ ${HTTPS_HOST} = 127.0.0.1 ] ; then CURL_ARGS="$CURL_ARGS --interface" fi if netstat -nle4 | grep 127.0.1:53 ; then CURL_ARGS="$CURL_ARGS --dns-interface lo" fi elif [ -n "$https_proxy" ] ; then HTTPS_HOST=$( echo $https_proxy|sed -e 's@/@@g' -e 's/:/ /g' -e 's/https* //' -e 's/ .*//' ) HTTPS_PORT=$( echo $https_proxy|sed -e 's@/@@g' -e 's/:/ /g' -e 's/.* //' ) OPENSSL_ARGS="$OPENSSL_ARGS -proxy ${HTTPS_HOST}:$HTTPS_PORT" TESTSSL_ARGS="$TESTSSL_ARGS --proxy=auto" CURL_ARGS="$CURL_ARGS --proxy http://${HTTPS_HOST}:$HTTPS_PORT" ANALYZE_ARGS="$ANALYZE_ARGS --starttls http_proxy:${HTTPS_HOST}:$HTTPS_PORT" [ -n "$testssl" ] && testssl="torsocks $testssl" [ -n "$sslscan" ] && sslscan="torsocks $sslscan" else : direct fi TENVS="DNS_VIA_PROXY=true" errs=0 for CAFILE in /etc/ssl/certs/ca-certificates.crt /usr/local/etc/ssl/cacert-testforge.pem ; do [ -f $CAFILE ] || { ERROR "CAfile not found $CAFILE" ; exit 8; } for item in $HOSTS ; do i=0 OUTRF=$OUTR.$item if [ -n "$openssl" ] ; then INFO "$openssl s_client -connect ${item}:443 -servername $item $OPENSSL_ARGS --CAfile $CAFILE" echo $openssl s_client \ -connect ${item}:443 -servername $item $OPENSSL_ARGS --CAfile $CAFILE \ < /dev/null > $OUTRF.s_client.out timeout ${kill_time}s \ $openssl s_client \ -connect ${item}:443 -servername $item $OPENSSL_ARGS --CAfile $CAFILE \ < /dev/null >> $OUTRF.s_client.out 2>&1 # :error:\| if [ $? -eq 124 ] ; then echo "DEBUG: timeout openssl s_client failed $? see $OUTRF.s_client.out" elif [ $? -ne 0 ] ; then WARN "openssl s_client failed $? see $OUTRF.s_client.out" i=$( expr $i + 1 ) elif str='unable to get local issuer certificate' && \ grep "$str" $OUTRF.s_client.out; then WARN "openssl s_client failed - $str see $OUTRF.s_client.out" i=$( expr $i + 1 ) elif str='Cipher is (NONE)' && \ grep "$str" $OUTRF.s_client.out; then WARN "openssl s_client failed - $str see $OUTRF.s_client.out" i=$( expr $i + 1 ) elif str='SSL handshake has read 0 bytes' && \ grep "$str" $OUTRF.s_client.out; then WARN "openssl s_client failed - $str see $OUTRF.s_client.out" i=$( expr $i + 1 ) else echo "DEBUG: openssl s_client -showcerts $OPENSSL_ARGS --CAfile $CAFILE $item" timeout ${kill_time}s \ $openssl s_client -showcerts \ -connect ${item}:443 -servername $item $OPENSSL_ARGS --CAfile $CAFILE < /dev/null \ > $OUTRF.s_client.certs 2>&1 fi fi if [ -n "$sslscan" ] ; then echo $sslscan $SSLSCAN_ARGS --certs $CAFILE --sni-name $item $item > $OUTRF.sslscan.out timeout ${kill_time}s \ $sslscan $SSLSCAN_ARGS --sni-name $item $item >> $OUTRF.sslscan.out 2>&1 if [ $? -eq 124 ] ; then echo "DEBUG: timeout sslscan failed $? see $OUTRF.sslscan.out " elif [ $? -ne 0 ] ; then WARN "sslscan failed $? see $OUTRF.sslscan.out " i=$( expr $i + 1 ) elif grep 'SSL Certificate' $OUTRF.sslscan.out ; then WARN "sslscan failed see $OUTRF.sslscan.out " i=$( expr $i + 1 ) elif grep 'Connection failed' $OUTRF.sslscan.out ; then # tail -1 $OUTRF.sslscan.out | grep 'Supported Server Cipher' WARN "sslscan failed see $OUTRF.sslscan.out " i=$( expr $i + 1 ) else INFO "$sslscan $SSLSCAN_ARGS $item" fi fi if [ -n "$testssl" -a -n "$https_proxy" ] ; then # rDNS (140.82.114.3): lb-140-82-114-3-iad.github.com.testssl.sh: line 10330: /dev/tcp/140.82.114.3/443: No such file or directory echo $TENVS $testssl $TESTSSL_ARGS $item > $OUTRF.testssl.out env $TENVS $testssl $TESTSSL_ARGS $item >> $OUTRF.testssl.out 2>&1 if [ $? -ne 0 ] ; then WARN "testssl failed $? see $OUTRF.testssl.out" i=$( expr $i + 1 ) elif grep ': unable to\| error:\|doesn.t seem to be a TLS/SSL enabled server' $OUTRF.testssl.out; then WARN "testssl failure see $OUTRF.testssl.out" i=$( expr $i + 1 ) else INFO "$testssl $TESTSSL_ARGS $item" echo "DEBUG: $testssl $TESTSSL_ARGS --jsonfile-pretty $OUTRF.testssl.json $item" env $TENVS $testssl $TESTSSL_ARGS --jsonfile-pretty $OUTRF.testssl.json $item > $OUTRF.testssl-json.out 2>&1 fi fi if [ -n "$curl" ] ; then DBUG $TENVS $curl $CURL_ARGS -o /dev/null https://$item/ env $TENVS $curl $CURL_ARGS -o /dev/null https://$item/ > $OUTRF.curl-vvv.out 2>&1 if [ $? -eq 0 ] ; then grep 'SSL certificate problem:' $OUTRF.curl-vvv.out && \ { WARN "curl -vvv failed $? see $OUTRF.curl-vvv.out" ; i=$( expr $i + 1 ) ; } || \ INFO $curl $CURL_ARGS $item else INFO $curl $CURL_ARGS $item fi fi if [ -n "$analyze" ] ; then timeout ${kill_time}s \ $analyze $ANALYZE_ARGS --name $item ${item}:443 \ > $OUTRF.analyze-ssl.out 2>&1 # certificate verified : ok if [ $? -eq 124 ] ; then echo "DEBUG: timeout $analyze $ANALYZE_ARGS $item" elif [ $? -eq 0 ] ; then INFO "$analyze $ANALYZE_ARGS $item" else WARN "$analyze failed $? see $OUTRF.analyze-ssl.out" i=$( expr $i + 1 ) fi fi [ $i -eq 0 ] && continue WARN "$i failures for $item" errs=$(expr $errs + $i ) DBUG $OUTRF.*.out done done find $OUTRF.* -type f -empty -delete exit $errs