A project to familiarize myself that I'm working on is to parse through an nmap
result.
(I know of the -oG
option, but I'm working with grep
, awk
, for
, and while
loops here).
Below is what I'm trying to parse through:
Starting Nmap 7.60 ( https://nmap.org ) at 2017-12-05 11:26 EST
Nmap scan report for house.router.nick (192.168.1.1)
Host is up (0.00059s latency).
Not shown: 995 closed ports
PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
427/tcp open svrloc
1900/tcp open upnp
MAC Address: 50:C7:BF:A8:CF:C8 (Tp-link Technologies)
Nmap scan report for 192.168.1.2
Host is up (0.00034s latency).
Not shown: 996 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
139/tcp open netbios-ssn
445/tcp open microsoft-ds
MAC Address: 48:F8:B3:C9:AE:BB (Cisco-Linksys)
What I want to get is this:
22/ssh
====
192.168.1.1
192.168.1.2
http
===
192.168.1.2
So far, I have this:
grep -E "tcp.*open" nmap.txt | awk '{ print $3 }' | sort | uniq
For the life of me, I can't figure out how to get this into a loop of sorts and get the desired output from above.
Can you please help me learn and explain why you came to the solution you did? No point in getting a potential solution if I can't understand the logic behind it.
You'd be better served using a general purpose programming language (python, perl, awk) where you can capture the IP address when you see the "scan report for" keywords, and then maintain a data structure mapping the service names to the list of IP addresses running those services.
For example, given that output, this perl one-liner (offered without explanation)
perl -ne '
if (/Nmap scan report for .*?(\d+\.\d+\.\d+\.\d+)/) {
$ip = $1
}
elsif (/^(\d+)\/tcp\s+open\s+(.*)/) {
push @{$services{"$1/$2"}}, $ip
}
END {
for $svc (sort {$a <=> $b} keys %services) {
printf "%s\n%s\n\n", $svc, join("\n", @{$services{$svc}})
}
}
'
produces
22/ssh
192.168.1.1
192.168.1.2
53/domain
192.168.1.1
80/http
192.168.1.2
139/netbios-ssn
192.168.1.2
427/svrloc
192.168.1.1
445/microsoft-ds
192.168.1.2
1900/upnp
192.168.1.1
$ cat tst.awk
BEGIN { FS="[[:space:]/]+" }
/Nmap scan report/ {
ip = $NF
gsub(/[()]/,"",ip)
}
/tcp.*open/ {
key = $1 "/" $4
ips[key] = (key in ips ? ips[key] ORS : "") ip
}
END {
for (key in ips) {
print key
print "===="
print ips[key]
print ""
}
}
.
$ awk -f tst.awk file
80/http
====
192.168.1.2
1900/upnp
====
192.168.1.1
427/svrloc
====
192.168.1.1
445/microsoft-ds
====
192.168.1.2
53/domain
====
192.168.1.1
22/ssh
====
192.168.1.1
192.168.1.2
139/netbios-ssn
====
192.168.1.2
I think it's extremely obvious what it's doing but if you have any questions after maybe a few glances at the awk man page then feel free to ask.
The above will work using any awk in any shell on every UNIX system.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With