@@ -759,6 +759,10 @@ debugme() {
759759 [[ "$DEBUG" -ge 2 ]] && "$@"
760760 return 0
761761}
762+ debugme1() {
763+ [[ "$DEBUG" -ge 1 ]] && "$@"
764+ return 0
765+ }
762766
763767hex2dec() {
764768 echo $((16#$1))
@@ -7436,9 +7440,14 @@ determine_tls_extensions() {
74367440 [[ $success -eq 0 ]] && extract_new_tls_extensions $TMPFILE
74377441 tmpfile_handle ${FUNCNAME[0]}.txt
74387442 fi
7443+
7444+ # Keep it "on file" for debugging purposes
7445+ debugme1 safe_echo "$TLS_EXTENSIONS" >"$TEMPDIR/$NODE.$NODEIP.tls_extensions.txt"
7446+
74397447 return $success
74407448}
74417449
7450+
74427451extract_certificates() {
74437452 local version="$1"
74447453 local savedir
@@ -8774,7 +8783,7 @@ certificate_info() {
87748783 prln_italic "$(out_row_aligned_max_width "$all_san" "$indent " $TERM_WIDTH)"
87758784 fileout "${jsonID}${json_postfix}" "INFO" "$all_san"
87768785 else
8777- if [[ $SERVICE == " HTTP" ]] || "$ASSUME_HTTP"; then
8786+ if [[ $SERVICE == HTTP ]] || "$ASSUME_HTTP"; then
87788787 pr_svrty_high "missing (NOT ok)"; outln " -- Browsers are complaining"
87798788 fileout "${jsonID}${json_postfix}" "HIGH" "No SAN, browsers are complaining"
87808789 else
@@ -8869,7 +8878,7 @@ certificate_info() {
88698878 pr_svrty_high "$trustfinding"
88708879 trust_sni_finding="HIGH"
88718880 elif ( [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]] ); then
8872- if [[ $SERVICE == " HTTP" ]] || "$ASSUME_HTTP"; then
8881+ if [[ $SERVICE == HTTP ]] || "$ASSUME_HTTP"; then
88738882 # https://bugs.chromium.org/p/chromium/issues/detail?id=308330
88748883 # https://bugzilla.mozilla.org/show_bug.cgi?id=1245280
88758884 # https://www.chromestatus.com/feature/4981025180483584
@@ -8932,7 +8941,7 @@ certificate_info() {
89328941 fi
89338942 if [[ -n "$sni_used" ]] || [[ $trust_nosni -eq 0 ]] || ( [[ $trust_nosni -ne 4 ]] && [[ $trust_nosni -ne 8 ]] ); then
89348943 outln "$trustfinding_nosni"
8935- elif [[ $SERVICE == " HTTP" ]] || "$ASSUME_HTTP"; then
8944+ elif [[ $SERVICE == HTTP ]] || "$ASSUME_HTTP"; then
89368945 prln_svrty_high "$trustfinding_nosni"
89378946 else
89388947 prln_svrty_medium "$trustfinding_nosni"
@@ -10150,6 +10159,8 @@ run_fs() {
1015010159 fi
1015110160 CURVES_OFFERED="$curves_offered"
1015210161 CURVES_OFFERED=$(strip_trailing_space "$CURVES_OFFERED")
10162+ # Keep it "on file" for debugging purposes
10163+ debugme1 safe_echo "$CURVES_OFFERED" >"$TEMPDIR/$NODE.$NODEIP.curves_offered.txt"
1015310164
1015410165 # find out what groups are supported.
1015510166 if "$using_sockets" && ( "$fs_tls13_offered" || "$ffdhe_offered" ); then
@@ -13333,6 +13344,7 @@ parse_tls_serverhello() {
1333313344 [[ $DEBUG -ge 1 ]] && tmpfile_handle ${FUNCNAME[0]}.txt
1333413345 return 1
1333513346 fi
13347+ # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
1333613348 case $extension_type in
1333713349 0000) tls_extensions+="TLS server extension \"server name\" (id=0), len=$extension_len\n" ;;
1333813350 0001) tls_extensions+="TLS server extension \"max fragment length\" (id=1), len=$extension_len\n" ;;
@@ -17447,26 +17459,33 @@ run_beast(){
1744717459# This vulnerability affected all SChannel services -- most notably RDP (port 3398 normally). See
1744817460# https://support.microsoft.com/en-us/help/2992611/ms14-066-vulnerability-in-schannel-could-allow-remote-code-execution-n
1744917461# and http://www.securitysift.com/exploiting-ms14-066-cve-2014-6321-aka-winshock for "exploiting"/crashing lsass.exe.
17462+ # What we do here is giving a strong hint.
1745017463#
17451- # What we do here is giving a hint, as with the Rollup patch MS introduced later is to supply the additional ciphers
17464+ # First we check whether TLS 1.3 is available. Then with the fix MS introduced came additional ciphers
1745217465# TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_GCM_SHA256
1745317466# = DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-GCM-SHA256.
17454- # We check for those (in sockets only to avoid overhead) and for port 443 we also grab the server banner to be more sure.
17455- # Also we check whether TLS 1.3 is available and some ciphers (ARIA, CCM, CAMELLIA and CHACHAPOLY). Those ciphers could
17456- # also be retrieved from our array TLS_CIPHER_RFC_NAME[i] and using TLS_CIPHER_HEXCODE[i]. The latter will be done later.
17467+ # We also check for the absence of ciphers which came in way later (ECDHE-RSA-AES128-GCM-SHA256 / ECDHE-RSA-AES256-GCM-SHA384), or
17468+ # more ciphers like ARIA, CCM, CAMELLIA and CHACHAPOLY. (Those ciphers could also be retrieved from our array TLS_CIPHER_RFC_NAME[i]
17469+ # and using TLS_CIPHER_HEXCODE[i]. We may want to # do that later. We check for all this in sockets only to avoid overhead.)
17470+ # Then we check for absence of elliptical curves and TLS extensions.
17471+ # That all should minimize false # positives because of middle boxes, proxies and later Windows versions.
17472+ # The last straw then is to check for webserver banners (http.sys, IIS/8.0 and IIS/8.5).
1745717473#
1745817474run_winshock() {
17459- local ws_ciphers_hex ='00,9F, 00,9D, 00,9E, 00,9C'
17475+ local wsfixed_ciphers ='00,9F, 00,9D, 00,9E, 00,9C'
1746017476 local aria_ciphers='C0,3D,C0,3F,C0,41,C0,43,C0,45,C0,47,C0,49,C0,4B,C0,4D,C0,4F,C0,51,C0,53,C0,55,C0,57,C0,59,C0,5B,C0,5D,C0,5F,C0,61,C0,63,C0,65,C0,67,C0,69,C0,6B,C0,6D,C0,6F,C0,71,C0,3C,C0,3E,C0,40,C0,42,C0,44,C0,46,C0,48,C0,4A,C0,4C,C0,4E,C0,50,C0,52,C0,54,C0,56,C0,58,C0,5A,C0,5C,C0,5E,C0,60,C0,62,C0,64,C0,66,C0,68,C0,6A,C0,6C,C0,6E,C0,70'
1746117477 local camellia_ciphers='C0,9B,C0,99,C0,97,C0,95,C0,77,C0,73,00,C4,00,C3,00,C2,00,C1,00,88,00,87,00,86,00,85,00,C5,00,89,C0,79,C0,75,00,C0,00,84,C0,7B,C0,7D,C0,7F,C0,81,C0,83,C0,85,C0,87,C0,89,C0,8B,C0,8D,C0,8F,C0,91,C0,93,C0,76,C0,72,00,BE,00,BD,00,BC,00,BB,00,45,00,44,00,43,00,42,00,BF,00,46,C0,78,C0,74,00,BA,00,41,C0,9A,C0,98,C0,96,C0,94,C0,7A,C0,7C,C0,7E,C0,80,C0,82,C0,84,C0,86,C0,88,C0,8A,C0,8C,C0,8E,C0,90,C0,92'
1746217478 local chacha_ccm_ciphers='CC,14,CC,13,CC,15,CC,A9,CC,A8,CC,AA,C0,AF,C0,AD,C0,A3,C0,9F,CC,AE,CC,AD,CC,AC,C0,AB,C0,A7,C0,A1,C0,9D,CC,AB,C0,A9,C0,A5,16,B7,16,B8,13,04,13,05,C0,AE,C0,AC,C0,A2,C0,9E,C0,AA,C0,A6,C0,A0,C0,9C,C0,A8,C0,A4'
1746317479 # TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 / TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = ECDHE-RSA-AES128-GCM-SHA256 / ECDHE-RSA-AES256-GCM-SHA384
1746417480 # came in Server 2016, see https://notsomany.com/2016/08/26/achieve-a-on-sslabs-iis-8-5-windows-2012-r2/
1746517481 # https://docs.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel
17466- local more_excluded_ciphers='C0,2f, C0,30'
17482+ local more_excluded_ciphers='C0,2F, C0,30'
17483+ # These are the three NIST curves allowed only. Keep in mind prime256v1=secp256r1 and MS labels them as P256, P384 and P521
17484+ local allowed_curves="prime256v1 secp384r1 secp521r1"
17485+ local curve="" tls_ext=""
1746717486 local -i sclient_success=0
17468- local is_iis8=true
1746917487 local server_banner=""
17488+ local check_patches=" - check patches locally to confirm"
1747017489 local cve="CVE-2014-6321"
1747117490 local cwe="CWE-94"
1747217491 local jsonID="winshock"
@@ -17481,62 +17500,112 @@ run_winshock() {
1748117500 if [[ "$(has_server_protocol "tls1_3")" -eq 0 ]] ; then
1748217501 # There's no MS server supporting TLS 1.3. Winshock was way back in time
1748317502 pr_svrty_best "not vulnerable (OK)"
17484- debugme echo " - TLS 1.3 found"
17503+ debugme1 echo " - TLS 1.3 found"
1748517504 fileout "$jsonID" "OK" "not vulnerable " "$cve" "$cwe"
1748617505 outln
1748717506 return 0
1748817507 fi
17489-
17490- # Next we weed out is whether we run HTTP or RDP (on standard port)
17491- if [[ $SERVICE != HTTP ]] && [[ $PORT != 3389 ]]; then
17492- prln_svrty_best "not vulnerable (OK) - no HTTP or RDP"
17493- fileout "$jsonID" "OK" "not vulnerable - no HTTP or RDP" "$cve" "$cwe"
17494- return 0
17508+ if ( [[ "$STARTTLS_PROTOCOL" =~ ldap ]] || [[ "$STARTTLS_PROTOCOL" =~ irc ]] ); then
17509+ prln_local_problem "STARTTLS/$STARTTLS_PROTOCOL and --ssl-native collide here"
17510+ return 1
1749517511 fi
1749617512
1749717513 # Now we check whether any CAMELLIA, ARIA, CCM or CHACHA cipher is available.
1749817514 # We do this in two shots in order to stay below the 128 cipher limit
1749917515 tls_sockets "03" "${aria_ciphers},${chacha_ccm_ciphers}, 00,ff"
1750017516 sclient_success=$?
1750117517 if [[ $sclient_success -eq 0 ]] || [[ "$sclient_success" -eq 2 ]]; then
17502- pr_svrty_best "not vulnerable (OK)"
17503- debugme echo " - ARIA, CHACHA or CCM ciphers found"
17518+ pr_svrty_best "not vulnerable (OK)" ; outln " - ARIA, CHACHA or CCM ciphers found"
1750417519 fileout "$jsonID" "OK" "not vulnerable " "$cve" "$cwe"
17505- outln
1750617520 return 0
1750717521 fi
1750817522 tls_sockets "03" "${camellia_ciphers},${more_excluded_ciphers}, 00,ff"
1750917523 sclient_success=$?
1751017524 if [[ $sclient_success -eq 0 ]] || [[ "$sclient_success" -eq 2 ]]; then
17511- pr_svrty_best "not vulnerable (OK)"
17512- debugme echo " - CAMELLIA or ECDHE_RSA GCM ciphers found"
17525+ pr_svrty_best "not vulnerable (OK)"; outln " - CAMELLIA or ECDHE_RSA GCM ciphers found"
1751317526 fileout "$jsonID" "OK" "not vulnerable " "$cve" "$cwe"
17514- outln
1751517527 return 0
1751617528 fi
1751717529
17518- # Now we have RDP and HTTP left and need to check the fixed ciphers
17519- tls_sockets "03" "${ws_ciphers_hex }, 00,ff"
17530+ # Now we need to check the fixed ciphers
17531+ tls_sockets "03" "${wsfixed_ciphers }, 00,ff"
1752017532 sclient_success=$?
1752117533 if [[ $sclient_success -eq 0 ]] || [[ "$sclient_success" -eq 2 ]]; then
1752217534 # has rollup ciphers
17523- pr_svrty_best "not vulnerable (OK)"
17524- debugme echo " - GCM rollup ciphers found"
17535+ pr_svrty_best "not vulnerable (OK)"; outln " - GCM rollup ciphers found"
1752517536 fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe"
17526- outln
1752717537 return 0
1752817538 elif [[ $sclient_success -ne 1 ]]; then
1752917539 prln_warning "check failed, connect problem"
1753017540 fileout "$jsonID" "WARN" "check failed, connect problem" "$cve" "$cwe"
1753117541 return 1
1753217542 fi
1753317543
17544+ # Basic idea: https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations#Supported_elliptic_curves
17545+ # [[ -z "$CURVES_OFFERED" ]] && sub_check_curves
17546+ if [[ -n "$CURVES_OFFERED" ]]; then
17547+ # Check whether there are any additional curves besides $allowed_curves
17548+ for curve in $CURVES_OFFERED; do
17549+ if ! [[ $allowed_curves =~ $curve ]]; then
17550+ pr_svrty_best "not vulnerable (OK)"; outln " - curve $curve detected"
17551+ fileout "$jsonID" "OK" "not vulnerable - curve $curve detected" "$cve" "$cwe"
17552+ return 0
17553+ fi
17554+ done
17555+ fi
17556+ #FIXME: The catch is that when a user didn't invoke run_fs() before, this wasn't processed + CURVES_OFFERED
17557+ # is empty. So we could call it like above but need to move curves detection into a seperate function
17558+ # (~ sub_check_curves) which is some work. But also for the sake of clean code this needs to be done.
17559+
17560+
17561+ [[ -z "$TLS_EXTENSIONS" ]] && determine_tls_extensions
17562+ # Basis of the following https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations#Extensions
17563+ # Our standard: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
17564+
17565+ # According to Wikipedia above these are the ones which can be detected unders version of Windows
17566+ # Secure Renegotiation, Server Name Indication, Certificate Status Request, Supplemental Data, Extended Master Secret, ALPN
17567+ # supplemental_data(23) (RFC 4680) seems to have been overwritten by extended master secret(23) RFC 7627
17568+ # local -a allowed_tls_ext=("server name" "status_request" "extended master secret" "application layer protocol negotiation")
17569+ # Instead we rather focus on the ones which according to that source weren't available
17570+ # Encrypt-then-MAC, Maximum Fragment Length, Keying Material Exporter, TLS Fallback SCSV, ClientHello Padding
17571+ # Padding is client side. Don't know what they mean by the fallback SCSV. That is not an extension
17572+ local -a forbidden_tls_ext=("encrypt-then-mac" "max fragment length")
17573+ # Open whether ec_point_formats, supported_groups(=elliptic_curves), heartbeat are supported under windows <=2012
17574+ # key_share and supported_versions are extensions which came with TLS 1.3. We checked the protocol before.
17575+ if [[ -n "$TLS_EXTENSIONS" ]]; then
17576+ # Check whether there are any TLS extension which should not be available under <= Windows 2012 R2
17577+ for tls_ext in $TLS_EXTENSIONS; do
17578+ # We use the whole array, got to be careful when the array becomes bigger (unintented match)
17579+ if [[ ${forbidden_tls_ext[@]} =~ $tls_ext ]]; then
17580+ pr_svrty_best "not vulnerable (OK)"; outln " - TLS extension $tls_ext detected"
17581+ fileout "$jsonID" "OK" "not vulnerable - TLS extension $tls_ext detected" "$cve" "$cwe"
17582+ return 0
17583+ fi
17584+ done
17585+ fi
17586+
17587+ # More would be possible if we look @ the following:
17588+ # See also https://github.com/cisco/joy/blob/master/fingerprinting/resources/fingerprint_db.json.gz
17589+ # https://resources.sei.cmu.edu/asset_files/Presentation/2019_017_001_539902.pdf
17590+ # https://raw.githubusercontent.com/cisco/joy/master/doc/using-joy-fingerprinting-00.pdf
17591+
17592+
17593+
17594+ # Now the solid determination more or less done. What's left now is to detect the service
17595+ # and perform an educated guess.
17596+
17597+ # Next we weed out is whether we run HTTP or RDP (on standard port).
17598+ # Using the experimental flag we can test it also on other ports / services
17599+ if [[ $SERVICE != HTTP ]] && [[ $PORT != 3389 ]] && ! "$EXPERIMENTAL"; then
17600+ pr_svrty_best "not vulnerable (OK)"; outln " - no HTTP or RDP"
17601+ fileout "$jsonID" "OK" "not vulnerable - no HTTP or RDP" "$cve" "$cwe"
17602+ return 0
17603+ fi
17604+
1753417605 if [[ $SERVICE != HTTP ]] && [[ $PORT == 3389 ]]; then
17535- # We take a guess here for RDP as we don't have a banner
17536- out "probably "
17537- pr_svrty_critical "vulnerable (NOT ok)"
17538- outln " - check patches locally to confirm"
17539- fileout "${jsonID}" "CRITICAL" "probably vulnerable (NOT OK). Check patches locally to confirm"
17606+ # We take a security guess here (better safe than sorry) for RDP as we don't have a banner
17607+ out "probably "; pr_svrty_critical "vulnerable (NOT ok)"; outln "$check_patches"
17608+ fileout "${jsonID}" "CRITICAL" "probably vulnerable (NOT OK) $check_patches"
1754017609 return 0
1754117610 fi
1754217611
@@ -17547,6 +17616,9 @@ run_winshock() {
1754717616 server_banner="$(grep -Eai '^Server:' $HEADERFILE)"
1754817617 elif [[ -s "$TEMPDIR/$NODEIP.service_detection.txt" ]]; then
1754917618 server_banner="$(grep -Eai '^Server:' "$TEMPDIR/$NODEIP.service_detection.txt")"
17619+ elif "$EXPERIMENTAL"; then
17620+ # If testing e.g. an SMTP server
17621+ :
1755017622 else
1755117623 # We can't use run_http_header here as it messes up the screen. We could automatically
1755217624 # run it when --winshock is requested though but this should suffice here.
@@ -17556,15 +17628,30 @@ run_winshock() {
1755617628 fi
1755717629 if [[ $server_banner =~ Microsoft-IIS\/8.5 ]]; then
1755817630 # Windows 2012 R2 is less likely than Windows 2012
17559- out "probably "
17560- pr_svrty_critical "vulnerable (NOT ok)"
17561- outln " - check patches locally to confirm"
17562- fileout "${jsonID}" "CRITICAL" "probably vulnerable (NOT OK). Check patches locally to confirm"
17631+ out "probably "; pr_svrty_critical "vulnerable (NOT ok)"; outln "$check_patches"
17632+ fileout "${jsonID}" "CRITICAL" "probably vulnerable (NOT OK) $check_patches"
1756317633 elif [[ $server_banner =~ Microsoft-IIS\/8.0 ]]; then
17564- out "likely "
17565- pr_svrty_critical "VULNERABLE (NOT ok)"
17566- outln " - check patches locally to confirm"
17567- fileout "${jsonID}" "CRITICAL" "likely vulnerable (NOT OK). Check patches locally to confirm"
17634+ out "likely "; pr_svrty_critical "VULNERABLE (NOT ok)"; outln "$check_patches"
17635+ fileout "${jsonID}" "CRITICAL" "likely vulnerable (NOT OK) $check_patches"
17636+ elif [[ $server_banner =~ Microsoft-HTTPAPI\/2.0 ]]; then
17637+ # This is http.sys. It may or may not indicate a 2012 server. IIS is not yet configured though.
17638+ # So we have a peek on port 80
17639+ http_get $NODE "$TEMPDIR/$NODE.$NODEIP.http-header.txt"
17640+ server_banner="$(grep -Eai '^Server:' $TEMPDIR/$NODE.$NODEIP.http-header.txt)"
17641+ if [[ $server_banner =~ Microsoft-IIS\/8.5 ]]; then
17642+ out "probably "; pr_svrty_critical "vulnerable (NOT ok)"; outln "$check_patches"
17643+ fileout "${jsonID}" "CRITICAL" "probably vulnerable (NOT OK) $check_patches"
17644+ elif [[ $server_banner =~ Microsoft-IIS\/8.0 ]]; then
17645+ out "likely "; pr_svrty_critical "VULNERABLE (NOT ok)"; outln "$check_patches"
17646+ fileout "${jsonID}" "CRITICAL" "likely vulnerable (NOT OK) $check_patches"
17647+ else
17648+ out "likely "; prln_svrty_best "not vulnerable (OK)"
17649+ fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe"
17650+ outln
17651+ fi
17652+ elif "$EXPERIMENTAL"; then
17653+ out "seems "; pr_svrty_critical "vulnerable (NOT ok)"; outln "$check_patches"
17654+ fileout "${jsonID}" "CRITICAL" "seems vulnerable (NOT OK) $check_patches"
1756817655 else
1756917656 pr_svrty_best "not vulnerable (OK)"
1757017657 outln " - doesn't seem to be IIS 8.x"
0 commit comments