mirror of
				https://github.com/drwetter/testssl.sh.git
				synced 2025-11-03 17:11:00 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			233 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env bash
 | 
						|
 | 
						|
# bash socket implementation of checking the availability of SSLv2 protocol
 | 
						|
# and ciphers on a remote server (loosely based on my bash-heartbleed implementation).
 | 
						|
#
 | 
						|
# Author: Dirk Wetter, GPLv2 see https://testssl.sh/LICENSE.txt 
 | 
						|
 | 
						|
# it helps to wireshark:
 | 
						|
# /<path>/openssl s_client -state -ssl2 -connect AA.BB.YYY.XXX:443 </dev/null
 | 
						|
# /<path>/openssl s_client -state -debug -ssl2 -connect AA.BB.YYY.XXX:443 </dev/null
 | 
						|
 | 
						|
V2_HELLO_CIPHERSPEC_LENGTH=0	# initialize
 | 
						|
IFILE=./mapping-rfc.txt
 | 
						|
NODE=""
 | 
						|
COL_WIDTH=32
 | 
						|
DEBUG=${DEBUG:-0}
 | 
						|
USLEEP_REC=${USLEEP_REC:-0.2}
 | 
						|
USLEEP_SND=${USLEEP_SND:-0.1}	# 1 second wait until otherwise specified
 | 
						|
MAX_WAITSOCK=2
 | 
						|
SOCK_REPLY_FILE=""
 | 
						|
NW_STR=""
 | 
						|
 | 
						|
 | 
						|
# 9 cipher specs SSLv2:
 | 
						|
SSLv2_CIPHER_SPECS="
 | 
						|
05 00 80 
 | 
						|
03 00 80 
 | 
						|
01 00 80 
 | 
						|
07 00 c0 
 | 
						|
08 00 80 
 | 
						|
06 00 40 
 | 
						|
04 00 80 
 | 
						|
02 00 80 
 | 
						|
00 00 00"
 | 
						|
 | 
						|
# SSLV2 chello:
 | 
						|
SSLv2_CLIENT_HELLO="
 | 
						|
,80,34    # length (here: 52)
 | 
						|
,01       # Client Hello 
 | 
						|
,00,02    # SSLv2
 | 
						|
,00,1b    # cipher spec length (here: 27 )
 | 
						|
,00,00    # session ID length
 | 
						|
,00,10    # challenge length
 | 
						|
,05,00,80 # 1st cipher
 | 
						|
,03,00,80 # 2nd
 | 
						|
,01,00,80 # 3rd
 | 
						|
,07,00,c0 # 4th
 | 
						|
,08,00,80 # 5th
 | 
						|
,06,00,40 # 6th
 | 
						|
,04,00,80 # 7th
 | 
						|
,02,00,80 # 8th
 | 
						|
,00,00,00 # 9th
 | 
						|
,29,22,be,b3,5a,01,8b,04,fe,5f,80,03,a0,13,eb,c4 # Challenge
 | 
						|
"
 | 
						|
 | 
						|
# only classical V2 ciphers are used here, see  http://max.euston.net/d/tip_sslciphers.html
 | 
						|
 | 
						|
# there are v3 in v2!!! : https://tools.ietf.org/html/rfc6101#appendix-E
 | 
						|
# Cipher specifications introduced in version 3.0 can be included in version 2.0 client hello messages using
 | 
						|
# the syntax below. [..] 
 | 
						|
# V2CipherSpec (see Version 3.0 name) = { 0x00, CipherSuite }; !!!!
 | 
						|
 | 
						|
# see:
 | 
						|
#   http://max.euston.net/d/tip_ssldump.html
 | 
						|
#   https://idea.popcount.org/2012-06-16-dissecting-ssl-handshake/
 | 
						|
#   https://books.google.de/books?id=LfsC03f8oGsC&pg=PA592&lpg=PA592&dq=sslv2+server+hello+struct&source=bl&ots=JWeSD-9pwH&sig=lMzhxTdybJ3tfWC2p9ltIOKlIso&hl=en&sa=X&ei=U3WmVKzyNoTgOOeigNAP&ved=0CDUQ6AEwAw
 | 
						|
 | 
						|
 | 
						|
help() {
 | 
						|
	echo
 | 
						|
	echo "Syntax $0 <hostname>"
 | 
						|
	echo
 | 
						|
	exit 1
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
parse_hn_port() {
 | 
						|
	PORT=443       # unless otherwise auto-determined, see below
 | 
						|
	NODE="$1"
 | 
						|
 | 
						|
	# strip "https", supposed it was supplied additionally
 | 
						|
	echo $NODE | grep -q 'https://' && NODE=`echo $NODE | sed -e 's/https\:\/\///' `
 | 
						|
 | 
						|
	# strip trailing urlpath
 | 
						|
	NODE=`echo $NODE | sed -e 's/\/.*$//'`
 | 
						|
 | 
						|
	# determine port, supposed it was supplied additionally
 | 
						|
	echo $NODE | grep -q ':' && PORT=`echo $NODE | sed 's/^.*\://'` && NODE=`echo $NODE | sed
 | 
						|
	's/\:.*$//'`
 | 
						|
}
 | 
						|
 | 
						|
# arg1: formatted string here in the code
 | 
						|
code2network() {
 | 
						|
	NW_STR=`echo "$1" | sed -e 's/,/\\\x/g' | sed -e 's/# .*$//g' -e 's/ //g' -e '/^$/d' | tr -d '\n' | tr -d '\t'`
 | 
						|
}
 | 
						|
 | 
						|
socksend_clienthello() {
 | 
						|
	code2network "$SSLv2_CLIENT_HELLO"
 | 
						|
	data=`echo $NW_STR`
 | 
						|
	[[ "$DEBUG" -ge 3 ]] && echo "\"$data\""
 | 
						|
	printf -- "$data" >&5 2>/dev/null &
 | 
						|
	sleep $USLEEP_SND
 | 
						|
}
 | 
						|
 | 
						|
sockread_serverhello() {
 | 
						|
     [[ "x$2" = "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2
 | 
						|
     ret=0
 | 
						|
 | 
						|
     SOCK_REPLY_FILE=`mktemp /tmp/ddreply.XXXXXX` || exit 7
 | 
						|
     dd bs=$1 of=$SOCK_REPLY_FILE count=1 <&5 2>/dev/null &
 | 
						|
     pid=$!
 | 
						|
 | 
						|
     while true; do
 | 
						|
          if ! ps ax | grep -v grep | grep -q $pid; then
 | 
						|
               break  # didn't reach maxsleep yet
 | 
						|
               kill $pid >&2 2>/dev/null
 | 
						|
          fi
 | 
						|
          sleep $USLEEP_REC
 | 
						|
          maxsleep=$(($maxsleep - 1))
 | 
						|
          [[ $maxsleep -le 0 ]] && break
 | 
						|
     done
 | 
						|
 | 
						|
     if ps ax | grep -v grep | grep -q $pid; then
 | 
						|
          # time's up and dd is still alive --> timeout
 | 
						|
          kill $pid >&2 2>/dev/null
 | 
						|
          wait $pid 2>/dev/null
 | 
						|
          ret=3 # means killed
 | 
						|
     fi
 | 
						|
 | 
						|
     return $ret
 | 
						|
}
 | 
						|
 | 
						|
display_sslv2serverhello() {
 | 
						|
 | 
						|
# server hello:									in hex representation, see below
 | 
						|
# byte 1+2: length of server hello						0123
 | 
						|
# 3:        04=Handshake message, server hello			45
 | 
						|
# 4:        session id hit or not (boolean: 00=false, this  67
 | 
						|
#           is the normal case)						
 | 
						|
# 5:        certificate type, 01 = x509					89
 | 
						|
# 6+7       version (00 02 = SSLv2)					10-13
 | 
						|
# 8+9       certificate length						14-17
 | 
						|
# 10+11     cipher spec length						17-20
 | 
						|
# 12+13     connection id length						
 | 
						|
# [certificate length] ==> certificate				
 | 
						|
# [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY!
 | 
						|
 | 
						|
	v2_hello_ascii=`hexdump -v -e '16/1 "%02X"' $1`
 | 
						|
	[[ "$DEBUG" -eq 4 ]] && echo $v2_hello_ascii 	# one line without any blanks
 | 
						|
	[[ -z $v2_hello_ascii ]] && return 0			# no server hello received
 | 
						|
 | 
						|
	# now scrape two bytes out of the reply per byte
 | 
						|
	v2_hello_initbyte="${v2_hello_ascii:0:1}"  # normally this belongs to the next, should be 8!
 | 
						|
	v2_hello_length="${v2_hello_ascii:1:3}"  # + 0x8000 see above
 | 
						|
	v2_hello_handshake="${v2_hello_ascii:4:2}"
 | 
						|
	v2_hello_cert_length="${v2_hello_ascii:14:4}"
 | 
						|
	v2_hello_cipherspec_length="${v2_hello_ascii:18:4}"
 | 
						|
	V2_HELLO_CIPHERSPEC_LENGTH=`printf "%d\n" "0x$v2_hello_cipherspec_length"`
 | 
						|
 | 
						|
	if [[ $v2_hello_initbyte != "8" ]] || [[ $v2_hello_handshake != "04" ]]; then
 | 
						|
		[[ $DEBUG -ge 1 ]] && echo "$v2_hello_initbyte / $v2_hello_handshake"
 | 
						|
		return 1
 | 
						|
	fi
 | 
						|
 | 
						|
	if [[ $DEBUG -ge 2 ]]; then
 | 
						|
		echo "SSLv2 server hello length: 0x0$v2_hello_length"
 | 
						|
		echo "SSLv2 certificate length:  0x$v2_hello_cert_length"
 | 
						|
		echo "SSLv2 cipher spec length:  0x$v2_hello_cipherspec_length"
 | 
						|
	fi
 | 
						|
	return 0
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#### main
 | 
						|
 | 
						|
[[ -z "$1" ]] && help  # hostname
 | 
						|
 | 
						|
echo
 | 
						|
parse_hn_port "$1"
 | 
						|
 | 
						|
	if ! exec 5<> /dev/tcp/$NODE/$PORT; then
 | 
						|
		echo "`basename $0`: unable to connect to $NODE:$PORT"
 | 
						|
		exit 2
 | 
						|
	fi
 | 
						|
	# socket is now open with fd 5
 | 
						|
 | 
						|
	[[ "$DEBUG" -ge 1 ]] && printf "sending client hello...\n\n"
 | 
						|
	socksend_clienthello 
 | 
						|
 | 
						|
	sockread_serverhello 32768 0
 | 
						|
	[[ "$DEBUG" -ge 1 ]] && printf "\nreading server hello...\n\n"
 | 
						|
	if [[ "$DEBUG" -eq 3 ]]; then
 | 
						|
		#xxd -c$COL_WIDTH $SOCK_REPLY_FILE  | head -3
 | 
						|
		#hexdump -v -e '"%04_ax:  " 16/1 "%02X " "\n"' $SOCK_REPLY_FILE | head -6
 | 
						|
		hexdump -C $SOCK_REPLY_FILE | head -6
 | 
						|
		echo
 | 
						|
	fi
 | 
						|
 | 
						|
	display_sslv2serverhello "$SOCK_REPLY_FILE"
 | 
						|
 | 
						|
	# see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL
 | 
						|
	lines=`cat "$SOCK_REPLY_FILE" 2>/dev/null | hexdump -C | wc -l` 
 | 
						|
 | 
						|
	printf "Protocol: "; tput bold
 | 
						|
	if [[ "$lines" -gt 1 ]] ;then
 | 
						|
		tput setaf 1; printf "available with $(($V2_HELLO_CIPHERSPEC_LENGTH / 3 )) ciphers"
 | 
						|
		ret=0
 | 
						|
	else
 | 
						|
		tput setaf 2; printf "NOT available"
 | 
						|
		ret=1
 | 
						|
	fi
 | 
						|
	tput sgr0
 | 
						|
 | 
						|
 | 
						|
	[[ "$DEBUG" -ge 2 ]] && printf "  ($lines lines)"
 | 
						|
	echo
 | 
						|
 | 
						|
 | 
						|
	# closing fd:
 | 
						|
	exec 5<&-
 | 
						|
	exec 5>&-
 | 
						|
 | 
						|
	rm $SOCK_REPLY_FILE
 | 
						|
 | 
						|
echo
 | 
						|
exit 0
 | 
						|
 | 
						|
#test: dragon,  simhq.com=gryphon1.gryphoninternet.com  misim.gov.il,   shop4-heating.co.uk, service.hamburgwasser.de
 | 
						|
#                74.116.0.167                           147.237.80.2    85.92.77.27
 | 
						|
 | 
						|
#  vim:tw=110:ts=5:sw=5
 | 
						|
#  $Id: prototype.ssl2proto-check.bash,v 1.10 2015/09/25 19:02:24 dirkw Exp $ 
 |