Search code examples
bashawknmap

Awk: extracting ports from nmap output


I wrote the following script which goes through the Nmap's output and then parses ports grouped as TCP/UDP:

#!/bin/bash

TC=0;   #TCP Count
UC=0;   #UDP Count
if [ $# -eq 1 ];then

    cat $1 | gawk '/[0-9]+\/(tcp|udp)/{ match($1,/([0-9]+)\/(tcp|udp)/,arr); \
    if ( arr[2] == 'tcp') {
            if ( arr[1] in T == 0){         \   
    print "Insert ",arr[1]," to T"; \
    T[TC]=arr[1];
    TC++; 
            }   
    }   
    else if ( arr[2] == 'udp' && (arr[1] in U == 0)){       \   
    print "Insert ",arr[1]," to U"; 
    U[UC]=arr[1];
    UC++;
    }   
    }       
    END{
    print "U:"
    for (i in U){print U[i]}
    print "T:"
    for (j in T){print T[i]}
    }'  


    else
          echo 'nmap2ports <NMAP output File>'
    fi

The if condition statements in awk are never executing neither for TCP nor for UDP. All I was trying is if the port is TCP (or UDP) and not present in the TCP (or UDP) array, then Insert, and print the array at the end. Thus output would be like [Expected Output]

U:
631
5353
17946
20031
T:
22
80

But insertion is never taking place. What I have tried so far:

if (! arr[1] in T)

if ( arr[1] not in T)

if ( arr[1] in T == 0)

Sample Input file:

Nmap scan report for xx.xx.xx.xx                                                                                                                                                     
Host is up (0.47s latency).
Not shown: 1995 closed ports
PORT      STATE         SERVICE  VERSION
22/tcp    open          ssh      OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
80/tcp    open          http     Apache httpd 2.4.18 ((Ubuntu))
631/udp   open|filtered ipp
5353/udp  open|filtered zeroconf
17946/udp open|filtered unknown
MAC Address: 00:50:56:87:9A:10 (VMware)
Aggressive OS guesses: Linux 3.12 (95%), Linux 3.13 (95%), Linux 3.16 (95%), Linux 3.2 - 4.9 (95%), Linux 4.4 (95%), Linux 4.8 (95%), Linux 4.9 (95%), Linux 3.18 (95%), Linux 3.8 - 3.11 (95%), Linux 4.2 (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Nmap scan report for xx.xx.xx.xx
Host is up (0.47s latency).
Not shown: 1996 closed ports
PORT      STATE         SERVICE         VERSION
80/tcp    open          http            Apache httpd 2.4.18 ((Ubuntu))
631/udp   open|filtered ipp
5353/udp  open|filtered zeroconf
20031/udp open|filtered bakbonenetvault
MAC Address: 00:50:56:87:E4:54 (VMware)
Aggressive OS guesses: Linux 3.13 (95%), Linux 3.16 (95%), Linux 3.2 - 4.9 (95%), Linux 4.2 (95%), Linux 3.18 (95%), Linux 4.8 (95%), ASUS RT-N56U WAP (Linux 3.4) (95%), Linux 4.9 (95%), Linux 3.12 (94%), Linux 3.8 - 3.11 (94%)
No exact OS matches for host (test conditions non-ideal).

[Current output]

U:
T:

Solution

  • Could you please try following.

    awk '
    /^[0-9]+\/tcp/{
      sub(/\/.*/,"",$1)
      if(!tcpVal[$1]++){ a=""    }
    }
    /^[0-9]+\/udp/{
      sub(/\/.*/,"",$1)
      if(!udpVal[$1]++){ a=""    }
    }
    END{
      print "U:"
      for(i in udpVal) { print i }
      print "T:"
      for(j in tcpVal) { print j }
    }' Input_file
    

    Explanation: Adding detailed explanation for above.

    awk '                             ##Starting awk program from here.
    /^[0-9]+\/tcp/{                   ##Checking condition if line starts from digits then / and tcp then do following.
      sub(/\/.*/,"",$1)               ##Substituting from / till everything will NULL in 1st field.
      if(!tcpVal[$1]++){ a=""    }    ##Checking condition if $1 is NOT present in tcpVal array then place 
                                      ##it as an index in it and as a placeholder mentioning a to NULL.
    }
    /^[0-9]+\/udp/{                   ##Checking condition if line starts from digits / udp then do following.
      sub(/\/.*/,"",$1)               ##Substituting everything from / till last of line with NULL in $1.
      if(!udpVal[$1]++){ a=""    }    ##Checking condition if $1 is NOT present in udpVal array then place
                                      ##it as an index in it and as a placeholder mentioning a to NULL.
    }
    END{                              ##Starting END block of this specific awk program.
      print "U:"                      ##Printing U: here as per requested output.
      for(i in udpVal) { print i }    ##Traversing through array udpVal and printing index value(i).
      print "T:"                      ##Printing T: here as per requested output.
      for(j in tcpVal) { print j }    ##Traversing through array tcpVal and printing index value(i).
    }' Input_file                     ##Mentioning Input_file name here.