nmap-to-json.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/python3
  2. import json
  3. import sys
  4. from enum import Enum
  5. DEBUG = False
  6. full_output = False
  7. hosts = []
  8. # Describe the port fields
  9. class Port:
  10. port_number = 0
  11. state = ""
  12. protocol = ""
  13. owner = ""
  14. service = ""
  15. sunRPCinfo = ""
  16. version = ""
  17. def __str__(self):
  18. return f"Port {self.port_number} - Version: {self.version}"
  19. def todict(self, full=False):
  20. if full:
  21. return {
  22. "port":self.port_number,
  23. "state":self.state,
  24. "protocol":self.protocol,
  25. "owner":self.owner,
  26. "service":self.service,
  27. "RPCInfo":self.sunRPCinfo,
  28. "version":self.version,
  29. }
  30. return {
  31. "port":self.port_number,
  32. "protocol":self.protocol,
  33. "service":self.service,
  34. "version":self.version,
  35. "state":self.state,
  36. }
  37. # Class to represent all the host attributes
  38. class Host:
  39. ip = ""
  40. status = ""
  41. hostname = ""
  42. ports = [] # Array of Port() items
  43. def merge_ports(self, host):
  44. local_ports = [p.port_number for p in self.ports]
  45. for p in host.ports:
  46. if p.port_number not in local_ports:
  47. self.ports.append(p)
  48. def todict(self, full):
  49. return {
  50. "ip":self.ip,
  51. "hostname":self.hostname,
  52. "ports":[port.todict(full) for port in self.ports],
  53. "status":self.status
  54. }
  55. def open_gnmap(filename):
  56. with open(filename, "r") as gnmap:
  57. # split into lines and only take the ones that begin with "Host:"
  58. lines = gnmap.read().strip().split("\n")
  59. lines = [l for l in lines if not l.startswith("#") and l.startswith("Host:")]
  60. return lines
  61. # parse every single line
  62. def parse_line(line):
  63. global hosts
  64. # Create new Instance
  65. host = Host()
  66. host.ports = [] # needs to get reset
  67. # Split line into different fields
  68. fields = line.split("\t")
  69. # parse the different fields
  70. parse_fields(host, fields)
  71. # merge known hosts
  72. merge_hosts(host)
  73. # delete instance
  74. del host
  75. def parse_host_field(host, field):
  76. subfields = field.split(" (")
  77. host.ip = subfields[0]
  78. host.hostname =subfields[1].replace(")", "")
  79. if DEBUG: print(f"DEBUG: parse_host_field::ip={host.ip};hostname={host.hostname}")
  80. def parse_ports_field(host, field):
  81. portlist = [s.strip() for s in field.split("/,")]
  82. # loop through the ports and append them to the host
  83. for p in portlist:
  84. port = Port()
  85. portparts = p.split("/")
  86. port.port_number = portparts[0]
  87. port.state = portparts[1]
  88. port.protocol = portparts[2]
  89. port.owner = portparts[3]
  90. port.service = portparts[4]
  91. port.sunRPCinfo = portparts[5]
  92. port.version = portparts[6]
  93. host.ports.append(port)
  94. del port
  95. def parse_status_field(host, field):
  96. host.status = field
  97. return host
  98. # Jumptable for the different fields
  99. field_parser = {
  100. "Ports": parse_ports_field,
  101. "Status": parse_status_field,
  102. }
  103. # if no parser for that type of field is implemented
  104. def not_implemented(host, field_type):
  105. return host
  106. def merge_hosts(host):
  107. global hosts
  108. for ih in hosts:
  109. # hosts already present in list
  110. if ih.ip == host.ip:
  111. ih.merge_ports(host)
  112. break
  113. else:
  114. hosts.append(host)
  115. # parsed the different fields, each separeted by a space
  116. def parse_fields(host, fields):
  117. # create a Host instance
  118. # loop each field that is present
  119. for field in fields:
  120. field_parts = field.split(": ")
  121. field_type = field_parts[0]
  122. field_value = "".join(field_parts[1:])
  123. if DEBUG: print(f"DEBUG: field_type={field_type}")
  124. if DEBUG: print(f"DEBUG: field_content={field_value}")
  125. # Host Field is the most important one
  126. if field_type == "Host":
  127. parse_host_field(host, field_value)
  128. else:
  129. field_parser.get(field_type, not_implemented)(host, field_value)
  130. return host
  131. def hosts_to_json(full_output):
  132. global hosts
  133. out = []
  134. for host in hosts:
  135. out.append(host.todict(full_output))
  136. return out
  137. # check usage
  138. if len(sys.argv) == 1:
  139. print(f"usage: {sys.argv[0]} <scan.gnmap>")
  140. exit(1)
  141. elif len(sys.argv) == 3 and sys.argv[2] == "--full":
  142. full_output = True
  143. # Open the gnmap file
  144. lines = open_gnmap(sys.argv[1])
  145. # parse file
  146. for line in lines:
  147. parse_line(line)
  148. # dump as json
  149. print(json.dumps(hosts_to_json(full_output)))