123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- import json
- import sys
- from enum import Enum
- DEBUG = False
- full_output = False
- hosts = []
- class Port:
- port_number = 0
- state = ""
- protocol = ""
- owner = ""
- service = ""
- sunRPCinfo = ""
- version = ""
- def __str__(self):
- return f"Port {self.port_number} - Version: {self.version}"
- def todict(self, full=False):
- if full:
- return {
- "port":self.port_number,
- "state":self.state,
- "protocol":self.protocol,
- "owner":self.owner,
- "service":self.service,
- "RPCInfo":self.sunRPCinfo,
- "version":self.version,
- }
- return {
- "port":self.port_number,
- "protocol":self.protocol,
- "service":self.service,
- "version":self.version,
- }
- class Status(Enum):
- Up = 1
- Down = 2
- Unknown = 3
- def from_string(status):
- if status.lower() == "up":
- return Status.Up
- if status.lower() == "down":
- return Status.Down
- if status.lower() == "unknown":
- return Status.Unknown
- class Host:
- ip = ""
- status = None
- hostname = ""
- ports = []
- def todict(self, full):
- return {
- "ip":self.ip,
- "hostname":self.hostname,
- "ports":[port.todict(full) for port in self.ports],
- "status":str(self.status.value)
- }
- def open_gnmap(filename):
- with open(filename, "r") as gnmap:
-
- lines = gnmap.read().strip().split("\n")
- lines = [l for l in lines if not l.startswith("#") and l.startswith("Host:")]
- return lines
- def parse_line(line):
- global hosts
-
- fields = line.split("\t")
-
- out_host = parse_fields(fields)
- merge_hosts(out_host)
- def parse_host_field(field):
- host = Host()
- subfields = field.split(" (")
- host.ip = subfields[0]
- host.hostname =subfields[1].replace(")", "")
- if DEBUG: print(f"DEBUG: parse_host_field::ip={host.ip};hostname={host.hostname}")
- return host
- def parse_ports_field(host, field):
- portlist = field.split("/,")
-
- for p in portlist:
- port = Port()
- portparts = p.split("/")
- port.port_number = portparts[0]
- port.state = portparts[1]
- port.protocol = portparts[2]
- port.owner = portparts[3]
- port.service = portparts[4]
- port.sunRPCinfo = portparts[5]
- port.version = portparts[6]
- host.ports.append(port)
- return host
- def parse_status_field(host, field):
- host.status = Status.from_string(field)
- return host
- field_parser = {
- "Host": parse_host_field,
- "Ports": parse_ports_field,
- "Status": parse_status_field,
- }
- def not_implemented(host, field_type):
- return host
- def merge_hosts(host):
- global hosts
- for ih in hosts:
- if ih.ip == host.ip:
- ih.ports = host.ports
- break
- else:
- hosts.append(host)
- def parse_fields(fields):
-
- host = Host()
-
- for field in fields:
- field_type, field_value = field.split(": ")
- if DEBUG: print(f"DEBUG: field_type={field_type}")
- if DEBUG: print(f"DEBUG: field_content={field_value}")
-
- if field_type == "Host":
- host = parse_host_field(field_value)
- else:
- host = field_parser.get(field_type, not_implemented)(host, field_value)
- return host
- def hosts_to_json(full_output):
- global hosts
- out = []
- for host in hosts:
- out.append(host.todict(full_output))
- return out
- if len(sys.argv) == 1:
- print(f"usage: {sys.argv[0]} <scan.gnmap>")
- exit(1)
- elif len(sys.argv) == 3 and sys.argv[2] == "--full":
- full_output = True
- lines = open_gnmap(sys.argv[1])
- for line in lines:
- parse_line(line)
- print(json.dumps(hosts_to_json(full_output)))
|