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
  • 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 '16 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. – Alex Stragies Jul 11 '16 at 20:52
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.

  • Second snippet gives awk: line 3: syntax error at or near [ awk: line 11: syntax error at or near [ – Suncatcher Jul 22 '17 at 16:57
  • @Suncatcher: I just tried it again here on ancient Debian awk, and it works. Problem must be on your end. – Alex Stragies Jul 22 '17 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 '17 at 18:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.