1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
#!/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 <filename>": looks for <filename> (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 (<FQDN>) Status: Up"
# Line x+1: "Host: AAA.BBB.CCC.DDD (<FQDN>) Ports: 443/open/tcp//https///"
# (or): Host: AAA.BBB.CCC.DDD (<FQDN>) Ports: 22/open/tcp//ssh//<banner>/, 25/open/tcp//smtp//<banner>/, 443/open/tcp//ssl|http//<banner>
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//<banner>/,
[[ "$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
|