123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- #!/usr/bin/python3
- import json
- import sys
- from enum import Enum
- DEBUG = False
- full_output = False
- hosts = []
- # Describe the port fields
- class Port:
- def __init__(self):
- self.port_number = 0
- self.state = ""
- self.protocol = ""
- self.owner = ""
- self.service = ""
- self.sunRPCinfo = ""
- self.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,
- "state":self.state,
- }
- # Class to represent all the host attributes
- class Host:
- def __init__(self):
- self.ip = ""
- self.status = ""
- self.hostname = ""
- self.ports = [] # Array of Port() items
- def merge_ports(self, host):
- local_ports = [p.port_number for p in self.ports]
- for p in host.ports:
- if p.port_number not in local_ports:
- self.ports.append(p)
- def todict(self, full):
- return {
- "ip":self.ip,
- "hostname":self.hostname,
- "ports":[port.todict(full) for port in self.ports],
- "status":self.status
- }
- def open_gnmap(filename):
- with open(filename, "r") as gnmap:
- # split into lines and only take the ones that begin with "Host:"
- lines = gnmap.read().strip().split("\n")
- lines = [l for l in lines if not l.startswith("#") and l.startswith("Host:")]
- return lines
- # parse every single line
- def parse_line(line):
- global hosts
- # Create new Instance
- host = Host()
- # Split line into different fields
- fields = line.split("\t")
- # parse the different fields
- parse_fields(host, fields)
- # merge known hosts
- merge_hosts(host)
- # delete instance
- del host
- def parse_host_field(host, field):
- 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}")
- def parse_ports_field(host, field):
- portlist = [s.strip() for s in field.split("/,")]
- # loop through the ports and append them to the host
- 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)
- del port
- def parse_status_field(host, field):
- host.status = field
- return host
- # Jumptable for the different fields
- field_parser = {
- "Ports": parse_ports_field,
- "Status": parse_status_field,
- }
- # if no parser for that type of field is implemented
- def not_implemented(host, field_type):
- return host
- def merge_hosts(host):
- global hosts
- for ih in hosts:
- # hosts already present in list
- if ih.ip == host.ip:
- ih.merge_ports(host)
- break
- else:
- hosts.append(host)
- # parsed the different fields, each separeted by a space
- def parse_fields(host, fields):
- # create a Host instance
- # loop each field that is present
- for field in fields:
- field_parts = field.split(": ")
- field_type = field_parts[0]
- field_value = "".join(field_parts[1:])
- if DEBUG: print(f"DEBUG: field_type={field_type}")
- if DEBUG: print(f"DEBUG: field_content={field_value}")
- # Host Field is the most important one
- if field_type == "Host":
- parse_host_field(host, field_value)
- else:
- 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
- # check usage
- 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
- # Open the gnmap file
- lines = open_gnmap(sys.argv[1])
- # parse file
- for line in lines:
- parse_line(line)
- # dump as json
- print(json.dumps(hosts_to_json(full_output)))
|