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. }
  36. # Enum to represent the Host Status Field
  37. class Status(Enum):
  38. Up = 1
  39. Down = 2
  40. Unknown = 3
  41. def from_string(status):
  42. if status.lower() == "up":
  43. return Status.Up
  44. if status.lower() == "down":
  45. return Status.Down
  46. if status.lower() == "unknown":
  47. return Status.Unknown
  48. # Class to represent all the host attributes
  49. class Host:
  50. ip = ""
  51. status = None
  52. hostname = ""
  53. ports = [] # Array of Port() items
  54. def todict(self, full):
  55. return {
  56. "ip":self.ip,
  57. "hostname":self.hostname,
  58. "ports":[port.todict(full) for port in self.ports],
  59. "status":str(self.status.value)
  60. }
  61. def open_gnmap(filename):
  62. with open(filename, "r") as gnmap:
  63. # split into lines and only take the ones that begin with "Host:"
  64. lines = gnmap.read().strip().split("\n")
  65. lines = [l for l in lines if not l.startswith("#") and l.startswith("Host:")]
  66. return lines
  67. # parse every single line
  68. def parse_line(line):
  69. global hosts
  70. # split line into different fields
  71. fields = line.split("\t")
  72. # parse the different fields
  73. out_host = parse_fields(fields)
  74. merge_hosts(out_host)
  75. def parse_host_field(field):
  76. host = Host()
  77. subfields = field.split(" (")
  78. host.ip = subfields[0]
  79. host.hostname =subfields[1].replace(")", "")
  80. if DEBUG: print(f"DEBUG: parse_host_field::ip={host.ip};hostname={host.hostname}")
  81. return host
  82. def parse_ports_field(host, field):
  83. portlist = field.split("/,")
  84. # loop through the ports and append them to the host
  85. for p in portlist:
  86. port = Port()
  87. portparts = p.split("/")
  88. port.port_number = portparts[0]
  89. port.state = portparts[1]
  90. port.protocol = portparts[2]
  91. port.owner = portparts[3]
  92. port.service = portparts[4]
  93. port.sunRPCinfo = portparts[5]
  94. port.version = portparts[6]
  95. host.ports.append(port)
  96. return host
  97. def parse_status_field(host, field):
  98. host.status = Status.from_string(field)
  99. return host
  100. # Jumptable for the different fields
  101. field_parser = {
  102. "Host": parse_host_field,
  103. "Ports": parse_ports_field,
  104. "Status": parse_status_field,
  105. }
  106. # if no parser for that type of field is implemented
  107. def not_implemented(host, field_type):
  108. return host
  109. def merge_hosts(host):
  110. global hosts
  111. for ih in hosts:
  112. if ih.ip == host.ip:
  113. ih.ports = host.ports
  114. break
  115. else:
  116. hosts.append(host)
  117. # parsed the different fields, each separeted by a space
  118. def parse_fields(fields):
  119. # create a Host instance
  120. host = Host()
  121. # loop each field that is present
  122. for field in fields:
  123. field_type, field_value = field.split(": ")
  124. if DEBUG: print(f"DEBUG: field_type={field_type}")
  125. if DEBUG: print(f"DEBUG: field_content={field_value}")
  126. # Host Field is the most important one
  127. if field_type == "Host":
  128. host = parse_host_field(field_value)
  129. else:
  130. host = field_parser.get(field_type, not_implemented)(host, field_value)
  131. return host
  132. def hosts_to_json(full_output):
  133. global hosts
  134. out = []
  135. for host in hosts:
  136. out.append(host.todict(full_output))
  137. return out
  138. # check usage
  139. if len(sys.argv) == 1:
  140. print(f"usage: {sys.argv[0]} <scan.gnmap>")
  141. exit(1)
  142. elif len(sys.argv) == 3 and sys.argv[2] == "--full":
  143. full_output = True
  144. # Open the gnmap file
  145. lines = open_gnmap(sys.argv[1])
  146. # parse file
  147. for line in lines:
  148. parse_line(line)
  149. # dump as json
  150. print(json.dumps(hosts_to_json(full_output)))