4

I would like to find a way to print for each IP address found to have at least one open port, to print that IP address, followed by a list of open ports separated by commas. The ports and IP address should be separated by a tab delimiter.

I can do this in an ugly fashion, by grepping only the ip address, writing that to file, then grepping the nmap file again using the ip address result file as the input file, and then trimming down the open ports with cut and sed, writing that to file, and then joining both files. This is an ugly process, and it does not work reliably for fringe situations.

Is there an easy way to do this in one line with awk? I would think I would need to have a function in awk to find all open ports and return them so they could be printed along with the IP address, but I have not found how to do that.

Example source data:

Host: 10.0.0.101 ()Ports: 21/closed/tcp//ftp///, 22/closed/tcp//ssh///, 23/closed/tcp//telnet///, 25/closed/tcp//smtp///, 53/closed/tcp//domain///, 110/closed/tcp//pop3///, 139/open/tcp//netbios-ssn///, 143/closed/tcp//imap///, 445/open/tcp//microsoft-ds///, 3389/closed/tcp//ms-wbt-server///

Expected output data:

10.0.0.101    139,445
2
  • I don't know that the title edit adds clarity, as greppable nmap output is the only output file suited to this type of text processing. That could be mentioned in the question maybe.
    – Jason Kidd
    Jul 11, 2016 at 17:43
  • "This type of text processing" is called "parsing", that is why I added the word "Parse" in the title to make it more search-friendly. Jul 11, 2016 at 20:52

1 Answer 1

2

This awk program should do it:

$ echo "Host: 10.0.0.101 ()Ports: 21/closed/tcp//ftp///, 22/closed/tcp//ssh///, 23/closed/tcp//telnet///, 25/closed/tcp//smtp///, 53/closed/tcp//domain///, 110/closed/tcp//pop3///, 139/open/tcp//netbios-ssn///, 143/closed/tcp//imap///, 445/open/tcp//microsoft-ds///, 3389/closed/tcp//ms-wbt-server///" |
awk '{printf "%s\t", $2;
      for (i=4;i<=NF;i++) {
        split($i,a,"/");
        if (a[2]=="open") printf ",%s",a[1];}
      print ""}' |
sed -e 's/,//'

10.0.0.101  139,445

Before you edited your question, I had assumed, your output would be from shell nmap, so I had prepared this answer:

$ nmap -sT 127.0.0.1-3 |
  awk '/^Nmap scan report/{cHost=$5;}
       /open/ { split($1,a,"/"); result[cHost][a[1]]=""}
       END {
       for (i in result) {
         printf i;
         for (j in result[i])
           printf ",%s", j ;
         print ""} }' |
  sed -e 's/,/\t/'   

localhost   445,25,139,631,22,80
127.0.0.2   445,139,22,80
127.0.0.3   445,139,22,80

If you need explanations for them, leave a comment. If you can help eliminate the trailing sed calls, or can enhance any of the invocations, please edit.

3
  • Second snippet gives awk: line 3: syntax error at or near [ awk: line 11: syntax error at or near [
    – Suncatcher
    Jul 22, 2017 at 16:57
  • @Suncatcher: I just tried it again here on ancient Debian awk, and it works. Problem must be on your end. Jul 22, 2017 at 17:47
  • No, it gives error on square bracket. My nmap version is 7.01, it seems they changed output format. Anyway, I made more concise parser
    – Suncatcher
    Jul 23, 2017 at 18:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .