mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-01-03 23:39:45 +01:00
Merge pull request #487 from dcooper16/full_parse_sslv2
Add option for extract data from SSLv2 ServerHello
This commit is contained in:
commit
db4cbd1276
173
testssl.sh
173
testssl.sh
@ -641,6 +641,38 @@ else
|
|||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# arg1: An ASCII-HEX string
|
||||||
|
# arg2: file name
|
||||||
|
# Append $arg1 in binary format to $arg2
|
||||||
|
asciihex_to_binary_file(){
|
||||||
|
local string="$1"
|
||||||
|
local file="$2"
|
||||||
|
local -i len
|
||||||
|
local -i i ip2 ip4 ip6 ip8 ip10 ip12 ip14
|
||||||
|
local -i remainder
|
||||||
|
|
||||||
|
len=${#string}
|
||||||
|
[[ $len%2 -ne 0 ]] && return 1
|
||||||
|
|
||||||
|
for (( i=0; i <= len-16 ; i=i+16 )); do
|
||||||
|
ip2=$i+2; ip4=$i+4; ip6=$i+6; ip8=$i+8; ip10=$i+10; ip12=$i+12; ip14=$i+14
|
||||||
|
echo -e -n "\x${string:i:2}\x${string:ip2:2}\x${string:ip4:2}\x${string:ip6:2}\x${string:ip8:2}\x${string:ip10:2}\x${string:ip12:2}\x${string:ip14:2}" >> "$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
ip2=$i+2; ip4=$i+4; ip6=$i+6; ip8=$i+8; ip10=$i+10; ip12=$i+12; ip14=$i+14
|
||||||
|
remainder=$len-$i
|
||||||
|
case $remainder in
|
||||||
|
2) echo -e -n "\x${string:i:2}" >> "$file" ;;
|
||||||
|
4) echo -e -n "\x${string:i:2}\x${string:ip2:2}" >> "$file" ;;
|
||||||
|
6) echo -e -n "\x${string:i:2}\x${string:ip2:2}\x${string:ip4:2}" >> "$file" ;;
|
||||||
|
8) echo -e -n "\x${string:i:2}\x${string:ip2:2}\x${string:ip4:2}\x${string:ip6:2}" >> "$file" ;;
|
||||||
|
10) echo -e -n "\x${string:i:2}\x${string:ip2:2}\x${string:ip4:2}\x${string:ip6:2}\x${string:ip8:2}" >> "$file" ;;
|
||||||
|
12) echo -e -n "\x${string:i:2}\x${string:ip2:2}\x${string:ip4:2}\x${string:ip6:2}\x${string:ip8:2}\x${string:ip10:2}" >> "$file" ;;
|
||||||
|
14) echo -e -n "\x${string:i:2}\x${string:ip2:2}\x${string:ip4:2}\x${string:ip6:2}\x${string:ip8:2}\x${string:ip10:2}\x${string:ip12:2}" >> "$file" ;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
###### check code starts here ######
|
###### check code starts here ######
|
||||||
|
|
||||||
# determines whether the port has an HTTP service running or not (plain TLS, no STARTTLS)
|
# determines whether the port has an HTTP service running or not (plain TLS, no STARTTLS)
|
||||||
@ -5416,8 +5448,114 @@ sockread_serverhello() {
|
|||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_pub_key_size() {
|
||||||
|
local pubkey pubkeybits
|
||||||
|
local -i i len1 len
|
||||||
|
local tmppubkeyfile
|
||||||
|
|
||||||
|
# OpenSSL displays the number of bits for RSA and ECC
|
||||||
|
pubkeybits=$($OPENSSL x509 -noout -pubkey -in $HOSTCERT | $OPENSSL pkey -pubin -text | grep -aw "Public-Key:" | sed -e 's/.*(//' -e 's/)//')
|
||||||
|
if [[ -n $pubkeybits ]]; then
|
||||||
|
echo "Server public key is $pubkeybits" >> $TMPFILE
|
||||||
|
else
|
||||||
|
# This extracts the public key for DSA, DH, and GOST
|
||||||
|
tmppubkeyfile=$(mktemp $TEMPDIR/pubkey.XXXXXX) || return 7
|
||||||
|
$OPENSSL x509 -noout -pubkey -in $HOSTCERT | $OPENSSL pkey -pubin -outform DER -out "$tmppubkeyfile"
|
||||||
|
pubkey=$(hexdump -v -e '16/1 "%02X"' "$tmppubkeyfile")
|
||||||
|
rm $tmppubkeyfile
|
||||||
|
# Skip over tag and length of subjectPublicKeyInfo
|
||||||
|
i=2
|
||||||
|
len1="0x${pubkey:i:2}"
|
||||||
|
if [[ $len1 -lt 0x80 ]]; then
|
||||||
|
i=$i+2
|
||||||
|
else
|
||||||
|
len1=$len1-0x80
|
||||||
|
i=$i+2*$len1+2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Skip over algorithm field
|
||||||
|
i=$i+2
|
||||||
|
len1="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
if [[ $len1 -lt 0x80 ]]; then
|
||||||
|
i=$i+2*$len1
|
||||||
|
else
|
||||||
|
case $len1 in
|
||||||
|
129) len="0x${pubkey:i:2}" ;;
|
||||||
|
130) len="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
;;
|
||||||
|
131) len="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
;;
|
||||||
|
132) len="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
i=$i+2+2*$len
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Next is the public key BIT STRING. Skip over tag, length, and number of unused bits.
|
||||||
|
i=$i+2
|
||||||
|
len1="0x${pubkey:i:2}"
|
||||||
|
if [[ $len1 -lt 0x80 ]]; then
|
||||||
|
i=$i+4
|
||||||
|
else
|
||||||
|
len1=$len1-0x80
|
||||||
|
i=$i+2*$len1+4
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Now get the length of the public key
|
||||||
|
i=$i+2
|
||||||
|
len1="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
if [[ $len1 -lt 0x80 ]]; then
|
||||||
|
len=$len1
|
||||||
|
else
|
||||||
|
case $len1 in
|
||||||
|
129) len="0x${pubkey:i:2}" ;;
|
||||||
|
130) len="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
;;
|
||||||
|
131) len="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*$len+"0x${pubkey:i:2}"
|
||||||
|
;;
|
||||||
|
132) len="0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*"0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*"0x${pubkey:i:2}"
|
||||||
|
i=$i+2
|
||||||
|
len=256*"0x${pubkey:i:2}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
len=8*$len # convert from bytes to bits
|
||||||
|
pubkeybits="$(printf "%d" $len)"
|
||||||
|
echo "Server public key is $pubkeybits bit" >> $TMPFILE
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# arg1: name of file with socket reply
|
# arg1: name of file with socket reply
|
||||||
|
# arg2: true if entire server hello should be parsed
|
||||||
parse_sslv2_serverhello() {
|
parse_sslv2_serverhello() {
|
||||||
|
local ret v2_hello_ascii v2_hello_initbyte v2_hello_length
|
||||||
|
local v2_hello_handshake v2_cert_type v2_hello_cert_length
|
||||||
|
local v2_hello_cipherspec_length tmp_der_certfile
|
||||||
|
local -i certificate_len nr_ciphers_detected offset i
|
||||||
# server hello: in hex representation, see below
|
# server hello: in hex representation, see below
|
||||||
# byte 1+2: length of server hello 0123
|
# byte 1+2: length of server hello 0123
|
||||||
# 3: 04=Handshake message, server hello 45
|
# 3: 04=Handshake message, server hello 45
|
||||||
@ -5432,6 +5570,9 @@ parse_sslv2_serverhello() {
|
|||||||
# [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY!
|
# [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY!
|
||||||
|
|
||||||
local ret=3
|
local ret=3
|
||||||
|
if [[ "$2" == "true" ]]; then
|
||||||
|
echo "======================================" > $TMPFILE
|
||||||
|
fi
|
||||||
|
|
||||||
v2_hello_ascii=$(hexdump -v -e '16/1 "%02X"' $1)
|
v2_hello_ascii=$(hexdump -v -e '16/1 "%02X"' $1)
|
||||||
[[ "$DEBUG" -ge 5 ]] && echo "$v2_hello_ascii"
|
[[ "$DEBUG" -ge 5 ]] && echo "$v2_hello_ascii"
|
||||||
@ -5443,6 +5584,7 @@ parse_sslv2_serverhello() {
|
|||||||
v2_hello_initbyte="${v2_hello_ascii:0:1}" # normally this belongs to the next, should be 8!
|
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_length="${v2_hello_ascii:1:3}" # + 0x8000 see above
|
||||||
v2_hello_handshake="${v2_hello_ascii:4:2}"
|
v2_hello_handshake="${v2_hello_ascii:4:2}"
|
||||||
|
v2_cert_type="${v2_hello_ascii:8:2}"
|
||||||
v2_hello_cert_length="${v2_hello_ascii:14:4}"
|
v2_hello_cert_length="${v2_hello_ascii:14:4}"
|
||||||
v2_hello_cipherspec_length="${v2_hello_ascii:18:4}"
|
v2_hello_cipherspec_length="${v2_hello_ascii:18:4}"
|
||||||
|
|
||||||
@ -5460,10 +5602,36 @@ parse_sslv2_serverhello() {
|
|||||||
|
|
||||||
if [[ $DEBUG -ge 3 ]]; then
|
if [[ $DEBUG -ge 3 ]]; then
|
||||||
echo "SSLv2 server hello length: 0x0$v2_hello_length"
|
echo "SSLv2 server hello length: 0x0$v2_hello_length"
|
||||||
|
echo "SSLv2 certificate type: 0x$v2_cert_type"
|
||||||
echo "SSLv2 certificate length: 0x$v2_hello_cert_length"
|
echo "SSLv2 certificate length: 0x$v2_hello_cert_length"
|
||||||
echo "SSLv2 cipher spec length: 0x$v2_hello_cipherspec_length"
|
echo "SSLv2 cipher spec length: 0x$v2_hello_cipherspec_length"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
certificate_len=2*$(hex2dec "$v2_hello_cert_length")
|
||||||
|
[[ -e $HOSTCERT ]] && rm $HOSTCERT
|
||||||
|
[[ -e $TEMPDIR/intermediatecerts.pem ]] && rm $TEMPDIR/intermediatecerts.pem
|
||||||
|
if [[ "$2" == "true" ]] && [[ "$v2_cert_type" == "01" ]] && [[ "$v2_hello_cert_length" != "00" ]]; then
|
||||||
|
tmp_der_certfile=$(mktemp $TEMPDIR/der_cert.XXXXXX) || return $ret
|
||||||
|
asciihex_to_binary_file "${v2_hello_ascii:26:certificate_len}" "$tmp_der_certfile"
|
||||||
|
$OPENSSL x509 -inform DER -in $tmp_der_certfile -outform PEM -out $HOSTCERT
|
||||||
|
rm $tmp_der_certfile
|
||||||
|
get_pub_key_size
|
||||||
|
echo "======================================" >> $TMPFILE
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output list of supported ciphers
|
||||||
|
if [[ "$2" == "true" ]]; then
|
||||||
|
let offset=26+$certificate_len
|
||||||
|
nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3))
|
||||||
|
for (( i=0 ; i<nr_ciphers_detected; i++ )); do
|
||||||
|
echo "Supported cipher: x$(echo ${v2_hello_ascii:offset:6} | tr 'A-Z' 'a-z')" >> $TMPFILE
|
||||||
|
let offset=$offset+6
|
||||||
|
done
|
||||||
|
echo "======================================" >> $TMPFILE
|
||||||
|
|
||||||
|
tmpfile_handle $FUNCNAME.txt
|
||||||
|
fi
|
||||||
return $ret
|
return $ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5751,6 +5919,7 @@ parse_tls_serverhello() {
|
|||||||
|
|
||||||
|
|
||||||
#arg1: list of ciphers suites or empty
|
#arg1: list of ciphers suites or empty
|
||||||
|
#arg2: "true" if full server response should be parsed.
|
||||||
sslv2_sockets() {
|
sslv2_sockets() {
|
||||||
local ret
|
local ret
|
||||||
local client_hello cipher_suites len_client_hello
|
local client_hello cipher_suites len_client_hello
|
||||||
@ -5801,7 +5970,7 @@ sslv2_sockets() {
|
|||||||
outln
|
outln
|
||||||
fi
|
fi
|
||||||
|
|
||||||
parse_sslv2_serverhello "$SOCK_REPLY_FILE"
|
parse_sslv2_serverhello "$SOCK_REPLY_FILE" "$2"
|
||||||
ret=$?
|
ret=$?
|
||||||
|
|
||||||
close_socket
|
close_socket
|
||||||
@ -9160,7 +9329,7 @@ lets_roll() {
|
|||||||
determine_rdns
|
determine_rdns
|
||||||
determine_service "$1" # any starttls service goes here
|
determine_service "$1" # any starttls service goes here
|
||||||
|
|
||||||
$do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets; echo "$?" ; exit 0; }
|
$do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets "" "true"; echo "$?" ; exit 0; }
|
||||||
$do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER"; echo "$?" ; exit 0; }
|
$do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER"; echo "$?" ; exit 0; }
|
||||||
$do_test_just_one && test_just_one ${single_cipher}
|
$do_test_just_one && test_just_one ${single_cipher}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user