mirror of
				https://github.com/drwetter/testssl.sh.git
				synced 2025-10-31 13:55:25 +01:00 
			
		
		
		
	working prototype for SSLv2 client hello + parsing server hello in bash
This commit is contained in:
		
							
								
								
									
										229
									
								
								utils/prototype.ssl2proto-check.bash
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										229
									
								
								utils/prototype.ssl2proto-check.bash
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,229 @@ | ||||
| #!/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 | ||||
|  | ||||
| #  vim:tw=110:ts=5:sw=5 | ||||
| #  $Id: prototype.ssl2proto-check.bash,v 1.9 2015/01/07 22:56:22 dirkw Exp $  | ||||
		Reference in New Issue
	
	Block a user
	 Dirk
					Dirk