#!/usr/bin/env bash # Utility which converts grepable nmap output to testssl's file input # It is just borrowed from testssl.sh # License see testssl.sh echo A | sed -E 's/A//' >/dev/null 2>&1 && \ declare -r HAS_SED_E=true || \ declare -r HAS_SED_E=false usage() { cat << EOF usage: "$0 ": looks for (nmap gmap format) and converts into basename \$(filename)-testssl.txt" EOF exit 0 } fatal () { echo "$1" >&2 exit $2 } is_ipv4addr() { local octet="(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])" local ipv4address="$octet\\.$octet\\.$octet\\.$octet" [[ -z "$1" ]] && return 1 # Check that $1 contains an IPv4 address and nothing else [[ "$1" =~ $ipv4address ]] && [[ "$1" == $BASH_REMATCH ]] && \ return 0 || \ return 1 } filter_ip4_address() { local a for a in "$@"; do if ! is_ipv4addr "$a"; then continue fi if "$HAS_SED_E"; then sed -E 's/[^[:digit:].]//g' <<< "$a" | sed -e '/^$/d' else sed -r 's/[^[:digit:].]//g' <<< "$a" | sed -e '/^$/d' fi done } # arg1: a host name. Returned will be 0-n IPv4 addresses # watch out: $1 can also be a cname! --> all checked get_a_record() { local ip4="" local noidnout="" ip4=$(filter_ip4_address $(dig -r +short +timeout=2 +tries=2 -t a "$1" 2>/dev/null | awk '/^[0-9]/ { print $1 }')) if [[ -z "$ip4" ]]; then ip4=$(filter_ip4_address $(host -t a "$1" 2>/dev/null | awk '/address/ { print $NF }')) fi if [[ -z "$ip4" ]]; then ip4=$(filter_ip4_address $(drill a "$1" | awk '/ANSWER SECTION/,/AUTHORITY SECTION/ { print $NF }' | awk '/^[0-9]/')) fi echo "$ip4" } ports2starttls() { local tcp_port=$1 local ret=0 # https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers case $tcp_port in 21) echo "-t ftp " ;; 23) echo "-t telnet " ;; 119|433) echo "-t nntp " ;; # to come 25|587) echo "-t smtp " ;; 110) echo "-t pop3 " ;; 143) echo "-t imap " ;; 389) echo "-t ldap ";; 3306) echo "-t mysql " ;; 5222) echo "-t xmpp " ;; # domain of jabber server maybe needed 5432) echo "-t postgres " ;; 563) ;; # NNTPS 636) ;; # LDAP 1443|8443|443|981) ;; # HTTPS 465) ;; # HTTPS | SMTP 631) ;; # CUPS 853) ;; # DNS over TLS 995|993) ;; # POP3|IMAP 3389) ;; # RDP *) ret=1 ;; # we don't know this ports so we rather do not scan it esac return $ret } nmap_to_plain_file () { local fname="$1" local target_fname="" local oneline="" local ip hostdontcare round_brackets ports_specs starttls local tmp port host_spec protocol ssl_hint dontcare dontcare1 # Ok, since we are here we are sure to have an nmap file. To avoid questions we make sure it's the right format too if [[ "$(head -1 "$fname")" =~ ( -oG )(.*) ]] || [[ "$(head -1 "$fname")" =~ ( -oA )(.*) ]] ; then # yes, greppable if [[ $(grep -c Status "$fname") -ge 1 ]]; then [[ $(grep -c '\/open\/' "$fname") -eq 0 ]] && \ fatal "Nmap file $fname should contain at least one open port" 250 else fatal "strange, nmap grepable misses \"Status\"" 251 fi else fatal "Nmap file $fname is not in grep(p)able format (-oG filename.g(n)map)" 250 fi target_fname="${fname%.*}"-testssl.txt [[ -e $target_fname ]] && fatal "$target_fname already exists" 3 > "${target_fname}" || fatal "Cannot create \"${target_fname}\"" 252 # Line x: "Host: AAA.BBB.CCC.DDD () Status: Up" # Line x+1: "Host: AAA.BBB.CCC.DDD () Ports: 443/open/tcp//https///" # (or): Host: AAA.BBB.CCC.DDD () Ports: 22/open/tcp//ssh///, 25/open/tcp//smtp///, 443/open/tcp//ssl|http// while read -r hostdontcare ip round_brackets tmp ports_specs; do [[ "$ports_specs" =~ "Status: " ]] && continue # we don't need this [[ "$ports_specs" =~ '/open/tcp/' ]] || continue # no open tcp at all for this IP --> move host_spec="$ip" fqdn="${round_brackets/\(/}" fqdn="${fqdn/\)/}" if [[ -n "$fqdn" ]]; then tmp="$(get_a_record "$fqdn")" if [[ "$tmp" == "$ip" ]]; then host_spec="$fqdn" fi fi while read -r oneline; do # 25/open/tcp//smtp///, [[ "$oneline" =~ '/open/tcp/' ]] || continue # no open tcp for this port on this IP --> move on IFS=/ read -r port dontcare protocol ssl_hint dontcare1 <<< "$oneline" if [[ "$ssl_hint" =~ ^(ssl|https) ]] || [[ "$dontcare1" =~ ^(ssl|https) ]]; then echo "${host_spec}:${port}" >>"$target_fname" else starttls="$(ports2starttls $port)" [[ $? -eq 1 ]] && continue # nmap got a port but we don't know how to speak to echo "${starttls}${host_spec}:${port}" >>"$target_fname" fi done < <(tr ',' '\n' <<< "$ports_specs") done < "$fname" [[ -s "$target_fname" ]] || fatal "Couldn't find any open port in $fname" 253 echo "$target_fname written successfully" return 0 } [[ -z "$1" ]] && usage FNAME="$1" [[ ! -e $FNAME ]] && echo "$FNAME not readable" && exit 2 nmap_to_plain_file "$FNAME" exit $? # vim:ts=5:sw=5:expandtab