Merge pull request #5 from mzeltner/master

Cleaned up options and documented custom OpenSSL build
This commit is contained in:
Julien Vehent 2014-04-04 21:26:59 -04:00
commit afcc92db02
2 changed files with 146 additions and 68 deletions

View file

@ -2,32 +2,47 @@ CipherScan
==========
A very simple way to find out which SSL ciphersuites are supported by a target.
Run: ./cipherscan www.google.com:443
And watch.
On Linux x86_64 run: ./cipherscan www.google.com:443
On any other *nix or *tux run: ./cipherscan -o /path/to/openssl www.google.com:443
and watch.
The newer your version of openssl, the better results you'll get. Older versions
of OpenSSL don't support TLS1.2 ciphers, elliptic curves, etc... Build Your Own!
The newer your version of openssl, the better results you'll get. Versions
of OpenSSL below 1.0.1 don't support TLS1.2 ciphers, elliptic curves, etc... Build your own or test what your system's OpenSSL supports.
Cipherscan should work fine on Linux, Mac OS X, Solaris, Illumos, SmartOS, OpenIndiana if you specify a an openssl binary with -o.
Build OpenSSL with ChaCha20-Poly1305 support (Optional)
-------------------------------------------------------
The OpenSSL binary in this repository is built for 64bit Linux. If you wish to build a version with the same features for your own platform, [the snapshot from the OpenSSL gitweb view](http://git.openssl.org/gitweb/?p=openssl.git;a=tree;h=161b23361778c155f9c174694b1db2506a2e0b52;hb=9a8646510b) and build it like this:
```
./config no-shared
make
```
And get the binary from `app/openssl`. (`./config` will ask you to run `make depend` which will fail - for our purposes this step is not required)
Options
-------
Enable benchmarking by setting DOBENCHMARK to 1 at the top of the script.
You can use one of the options below (only one. yes, I know...)
Use '-v' to get more stuff to read.
Use '-a' to force openssl to test every single cipher it know.
Use '-json' to output the results in json format
```
$ ./cipherscan -json www.google.com:443
-a | --allciphers Test all known ciphers individually at the end.
-b | --benchmark Activate benchmark mode.
-d | --delay Pause for n seconds between connections
-D | --debug Output ALL the information.
-h | --help Shows this help text.
-j | --json Output results in JSON format.
-o | --openssl path/to/your/openssl binary you want to use.
-v | --verbose Increase verbosity.
```
Example
-------
Testing plain SSL/TLS:
```
$ ./cipherscan www.google.com:443
linux $ ./cipherscan www.google.com:443
...................
prio ciphersuite protocols pfs_keysize
1 ECDHE-RSA-CHACHA20-POLY1305 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits
@ -48,7 +63,11 @@ prio ciphersuite protocols pfs_keysize
16 ECDHE-RSA-AES128-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits
17 AES128-SHA256 SSLv3,TLSv1,TLSv1.1,TLSv1.2
18 AES128-SHA SSLv3,TLSv1,TLSv1.1,TLSv1.2
$ ./cipherscan -starttls xmpp jabber.ccc.de:5222
```
Testing STARTTLS:
```
darwin $ ./cipherscan -o ./openssl-mine -starttls xmpp jabber.ccc.de:5222
.........
prio ciphersuite protocols pfs_keysize
1 DHE-RSA-AES256-SHA SSLv3,TLSv1 DH,1024bits

View file

@ -8,28 +8,17 @@
DOBENCHMARK=0
BENCHMARKITER=30
OPENSSLBIN="$(dirname $0)/openssl"
TIMEOUT=10
CIPHERSUITE="ALL:COMPLEMENTOFALL"
HOST=$(sed -e 's/:.*//'<<<"${@: -1}")
PORT=$(sed -e 's/.*://'<<<"${@: -1}")
if [ "$HOST" = "$PORT" ]; then
PORT=443
fi
TARGET=$HOST:$PORT
SCLIENTARGS=$(sed -e "s/${@: -1}//" -e "s/-v//" -e "s/-a//" -e "s/-json//" <<<"$@")
DEBUG=0
VERBOSE=0
DELAY=0
ALLCIPHERS=0
OUTPUTFORMAT="terminal"
REQUEST="GET / HTTP/1.1
Host: $TARGET
Connection: close
"
usage() {
echo -e "usage: $0 [-a|-v|-json] [openssl s_client args] <target:port>
echo -e "usage: $0 [-a|--allciphers] [-b|--benchmark] [-d|--delay seconds] [-D|--debug] [-j|--json] [-v|--verbose] [-o|--openssl file] [openssl s_client args] <target:port>
usage: $0 -h|--help
$0 attempts to connect to a target site using all the ciphersuites it knowns.
Julien Vehent [:ulfr] - https://github.com/jvehent/cipherscan
@ -38,29 +27,36 @@ Port defaults to 443
example: $ $0 www.google.com:443
Use one of the options below as the first argument:
-v increase verbosity
-a test all known ciphers individually at the end
-json output results in json format
Use one of the options below:
-a | --allciphers Test all known ciphers individually at the end.
-b | --benchmark Activate benchmark mode.
-d | --delay Pause for n seconds between connections
-D | --debug Output ALL the information.
-h | --help Shows this help text.
-j | --json Output results in JSON format.
-o | --openssl path/to/your/openssl binary you want to use.
-v | --verbose Increase verbosity.
The rest of the arguments will be interpreted as openssl s_client argument.
This enables checking smtp/imap/pop3/ftp/xmpp via -starttls
example: $0 -starttls xmpp jabber.ccc.de:5222
OpenSSL path can be changed in the OPENSSLBIN variable
Benchmarking can be enabled in the DOBENCHMARK variable
EXAMPLES: $0 -starttls xmpp jabber.ccc.de:5222
"
exit 1
}
verbose() {
if [ $VERBOSE -eq 1 ];then
echo $@
if [ $VERBOSE != 0 ]; then
echo "$@" >&2
fi
}
debug(){
if [ $DEBUG == 1 ]; then
echo Debug: "$@" >&2
fi
}
# Connect to a target host with the selected ciphersuite
test_cipher_on_target() {
@ -70,16 +66,13 @@ test_cipher_on_target() {
pfs=""
for tls_version in "-ssl2" "-ssl3" "-tls1" "-tls1_1" "-tls1_2"
do
local tmp=$(mktemp)
$sslcommand $tls_version 1>"$tmp" 2>/dev/null << EOF
$REQUEST
EOF
current_cipher=$(grep "New, " $tmp|awk '{print $5}')
current_pfs=$(grep 'Server Temp Key' $tmp|awk '{print $4$5$6$7}')
current_protocol=$(grep -E "^\s+Protocol\s+:" $tmp|awk '{print $3}')
debug echo \"quit\\n\" \| $sslcommand $tls_version
local tmp=$(echo "quit\n" | $sslcommand $tls_version 1>/dev/stdout 2>/dev/null)
current_cipher=$(grep "New, " <<<"$tmp"|awk '{print $5}')
current_pfs=$(grep 'Server Temp Key' <<<"$tmp"|awk '{print $4$5$6$7}')
current_protocol=$(egrep "^\s+Protocol\s+:" <<<"$tmp"|awk '{print $3}')
if [[ -z "$current_protocol" || "$current_cipher" == '(NONE)' ]]; then
# connection failed, try again with next TLS version
rm "$tmp"
continue
fi
# connection succeeded, add TLS version to positive results
@ -91,7 +84,6 @@ EOF
cipher=$current_cipher
pfs=$current_pfs
# grab the cipher and PFS key size
rm "$tmp"
done
# if cipher is empty, that means none of the TLS version worked with
# the current cipher
@ -118,13 +110,12 @@ EOF
# Calculate the average handshake time for a specific ciphersuite
bench_cipher() {
local ciphersuite="$1"
local sslcommand="timeout $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
local sslcommand="$OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
local t="$(date +%s%N)"
verbose "Benchmarking handshake on '$TARGET' with ciphersuite '$ciphersuite'"
for i in $(seq 1 $BENCHMARKITER); do
$sslcommand 2>/dev/null 1>/dev/null << EOF
$REQUEST
EOF
debug Connection $i
(echo "quit\n" | $sslcommand 2>/dev/null 1>/dev/null)
if [ $? -gt 0 ]; then
break
fi
@ -140,9 +131,9 @@ EOF
# Connect to the target and retrieve the chosen cipher
# recursively until the connection fails
get_cipher_pref() {
[ "$OUTPUTFORMAT" == "terminal" ] && echo -n '.'
[ "$OUTPUTFORMAT" == "terminal" ] && [ $DEBUG -lt 1 ] && echo -n '.'
local ciphersuite="$1"
local sslcommand="timeout $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
local sslcommand="$OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $ciphersuite"
verbose "Connecting to '$TARGET' with ciphersuite '$ciphersuite'"
test_cipher_on_target "$sslcommand"
local success=$?
@ -153,6 +144,7 @@ get_cipher_pref() {
get_cipher_pref "!$pciph:$ciphersuite"
return 0
fi
sleep $DELAY
}
@ -203,20 +195,85 @@ display_results_in_json() {
echo ']}'
}
# UNKNOWNOPTIONS=""
while :
do
case $1 in
-h | --help | -\?)
usage
exit 0 # This is not an error, User asked help. Don't do "exit 1"
;;
-o | --openssl)
OPENSSLBIN=$2 # You might want to check if you really got FILE
shift 2
;;
-a | --allciphers)
ALLCIPHERS=1
shift
;;
-v | --verbose)
# Each instance of -v adds 1 to verbosity
VERBOSE=$((VERBOSE+1))
shift
;;
-j | -json | --json | --JSON)
OUTPUTFORMAT="json"
shift
;;
-b | --benchmark)
DOBENCHMARK=1
shift
;;
-D | --debug)
DEBUG=1
shift
;;
-d | --delay)
DELAY=$2
shift 2
;;
--) # End of all options
shift
break
;;
# -*)
# UNKNOWNOPTIONS=$((UNKNOWNOPTIONS+$1))
# # echo "WARN: Unknown option (ignored): $1" >&2
# shift
# ;;
*) # no more options we understand.
break
;;
esac
done
[[ -z $1 || "$1" == "-h" || "$1" == "--help" ]] && usage
if [ ! -z $2 ]; then
if [ "$1" == "-v" ]; then
VERBOSE=1
echo "Loading $($OPENSSLBIN ciphers -v $CIPHERSUITE 2>/dev/null|grep Kx|wc -l) ciphersuites from $(echo -n $($OPENSSLBIN version 2>/dev/null))"
$OPENSSLBIN ciphers ALL 2>/dev/null
elif [ "$1" == "-a" ]; then
ALLCIPHERS=1
elif [ "$1" == "-json" ]; then
OUTPUTFORMAT="json"
fi
if [ $VERBOSE != 0 ] ; then
echo "Loading $($OPENSSLBIN ciphers -v $CIPHERSUITE 2>/dev/null|grep Kx|wc -l) ciphersuites from $(echo -n $($OPENSSLBIN version 2>/dev/null))"
$OPENSSLBIN ciphers ALL 2>/dev/null
fi
# echo paramters left: $@
TEMPTARGET=$(sed -e 's/^.* //'<<<"${@}")
HOST=$(sed -e 's/:.*//'<<<"${TEMPTARGET}")
PORT=$(sed -e 's/.*://'<<<"${TEMPTARGET}")
# Default to https if no port given
if [ "$HOST" = "$PORT" ]; then
PORT=443
fi
debug "host: $HOST"
debug "Port: $PORT"
TARGET=$HOST:$PORT
debug "target: $TARGET"
SCLIENTARGS=$(sed -e s,${TEMPTARGET},,<<<"${@}")
debug "sclientargs: $SCLIENTARGS"
cipherspref=();
results=()
@ -235,11 +292,13 @@ if [ $ALLCIPHERS -gt 0 ]; then
echo; echo "All accepted ciphersuites"
for c in $($OPENSSLBIN ciphers -v ALL:COMPLEMENTOFALL 2>/dev/null |awk '{print $1}'|sort|uniq); do
r="fail"
osslcommand="timeout $TIMEOUT $OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $c"
osslcommand="$OPENSSLBIN s_client $SCLIENTARGS -connect $TARGET -cipher $c"
test_cipher_on_target "$osslcommand"
if [ $? -eq 0 ]; then
r="pass"
fi
echo "$c $r"|awk '{printf "%-35s %s\n",$1,$2}'
debug "Sleeping for $DELAY."
sleep $DELAY
done
fi