hostscan

NMAP Host Generator
git clone git@jamesshield.xyz:repos/hostscan.git
Log | Files | Refs | README | LICENSE

nmap-scan.py (7922B)


      1 #! /usr/bin/env python3
      2 """
      3 Usage: nmap-scan [options] <network>
      4 
      5 Options:
      6     --mongo-host MONGO_HOST                Mongo Host(default: localhost)
      7     --mongo-port MONGO_PORT                Mongo Port(default: 3001)
      8     --database DB                          Add records to mongo db
      9     --collection COLLECTION                Add records to mongo collection
     10     -H, --hosts                            Print *nix hosts file format [default].
     11     -R, --raw                              Print raw collection database
     12     -I, --insert                           Performs insert instead of in place update
     13     -S, --snmp                             Make SNMP calls
     14     -A, --ansible                          Make Ansible inventory
     15     -D, --debug                            Print debug information
     16 
     17 """
     18 from pysnmp.hlapi import *
     19 import xml.etree.ElementTree as ET
     20 from docopt import docopt
     21 from pprint import pprint
     22 from pymongo import MongoClient
     23 import datetime
     24 import os
     25 import sys
     26 
     27 from pprint import pprint
     28 
     29 if os.name == 'posix' and sys.version_info[0] < 3:
     30     import subprocess32 as subprocess
     31     from subprocess32 import CalledProcessError
     32 else:
     33     import subprocess
     34 
     35 out = ""
     36 
     37 def debug(msg, obj):
     38     if obj is not None:
     39         print("DEBUG: {0} {1}\n".format(msg, pprint(obj)))
     40 
     41 def run_nmap(net):
     42     try:
     43         out = subprocess.check_output(["nmap", "-oX", "-" , "-R", "-p", "22-443", "-sV" , net])
     44     except CalledProcessError:
     45         print("Error in caller\n")
     46         exit(1)
     47     return out
     48 
     49 def parsexml(f):
     50   _host = {}
     51   tree = ET.fromstring(f)
     52   hosts = tree.findall('host')
     53   for host in hosts:
     54     if ET.iselement(host):
     55       for addr in host.findall("address"):
     56           _address_type = addr.get('addrtype')
     57           if _address_type == 'ipv4':
     58             _ipaddress = addr.get('addr')
     59             _ipaskey = _ipaddress.replace(".", "-")
     60             _macaddress = None
     61             _vendor = None
     62             # _host[_ipaskey] = []
     63           if _address_type == 'mac':
     64             _macaddress = addr.get('addr')
     65             _vendor = addr.get('vendor')
     66           if args["--snmp"]:
     67             if debug:
     68               print("Run SNMPGET for {}".format(_ipaddress))
     69               varBind = snmpget(_ipaddress)
     70 
     71 
     72 
     73       hostname = host.find("./hostnames/hostname").get('name') if ET.iselement(host.find("./hostnames/hostname")) else _ipaskey
     74       # Per Host
     75       _host[_ipaskey] = { '_id': _ipaskey, 'name': hostname, 'ip': _ipaddress, 'mac': _macaddress, 'vendor': _vendor}
     76       _services = {}
     77       for port in host.findall("./ports/port"):
     78           if ET.iselement(port):
     79             if port.find(".//state/[@state='open']") is not None:
     80               #Per open Port
     81               state = port.find(".//state/[@state='open']")
     82               service = port.find('service')
     83 
     84               if port.get("portid") == "443":
     85                 common_name = port.find("./script/[@id='ssl-cert']/table/[@key='subject']/elem/[@key='commonName']").text \
     86                   if ET.iselement(port.find("./script/[@id='ssl-cert']/table/[@key='subject']/elem/[@key='commonName']")) else None
     87                 valid_after = port.find("./script/[@id='ssl-cert']/table/[@key='validity']/elem/[@key='notAfter']").text \
     88                   if ET.iselement(port.find("./script/[@id='ssl-cert']/table/[@key='validity']/elem/[@key='notAfter']")) else None
     89                 orgname     = port.find("./script/[@id='ssl-cert']/table/[@key='subject']/elem/[@key='organizationName']").text \
     90                   if ET.iselement(port.find("./script/[@id='ssl-cert']/table/[@key='subject']/elem/[@key='organizationName']")) else None
     91                 _service = {'protocol'            :  port.get("protocol"),
     92                                'portid'           :  port.get("portid"),
     93                                'product'          :  service.get("product"),
     94                                'service_name'     :  service.get("name"),
     95                                'ssl_cn'           :  common_name,
     96                                'ssl_orgname'      :  orgname,
     97                                'ssl_valid'        :  valid_after,}
     98               else: 
     99                 _service =    {'protocol'        :  port.get("protocol"),
    100                                'portid'           :  port.get("portid"),
    101                                'product'          :  service.get("product"),
    102                                'service_name'     :  service.get("name"),}
    103 
    104               if port.get("portid") not in list(_services.values()):
    105                   _services.setdefault('services',[]).append(_service)
    106 
    107 
    108     _host[_ipaskey].update(_services)
    109     del _services
    110 
    111   if args["--debug"]:
    112     debug("_host Object", _host)
    113 
    114   return _host
    115 
    116 
    117 def snmpget(host):
    118 
    119   cmdGen = cmdgen.CommandGenerator()
    120 
    121   errorIndication, errorStatus, errorIndex, varBinds = next(
    122       getCmd(SnmpEngine(),
    123              CommunityData('public'),
    124              UdpTransportTarget((host, 161)),
    125              ContextData(),
    126              ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))
    127   )
    128 
    129   # Check for errors and print out results
    130   if errorIndication:
    131       print(("Found ErrorI: {}".format(errI)))
    132       return None
    133   elif errorStatus:
    134       errS = errorStatus
    135       print(("Found ErrorS: {}".format(errorStatus)))
    136       return None
    137   else:
    138       for v in varBinds:
    139           if debug:
    140               print(("Varbinds: {}".format(pprint(varBinds))))
    141         #   print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))
    142       return varBinds
    143 
    144 def print_hosts(collection):
    145    for k,v in collection.items():
    146        print("%s\t%s" % (v['ip'],v['name']))
    147 
    148 
    149 def print_ansible(collection):
    150   print("[hosts]")
    151   for i in collection:
    152     print("%s\tansible_ssh_user=%s\tansible_ssh_pass=%s" % (i, 'root', '#password#'))
    153 
    154 def print_raw(collection):
    155     pprint(collection)
    156 
    157 def update_collection(collection,  col):
    158   timestamp = str(datetime.datetime.now())
    159 
    160   for i in collection:
    161     collection[i].update({'updated': timestamp})
    162     query = { "_id" : i }
    163   # query_one = { ip : i }, {{ ip : 1 }
    164     if args['--insert']:
    165       insert(collection[i], col)
    166     else:
    167       find_and_modify(query, collection[i],  col)
    168 
    169 
    170 def get_mongo_handle(client, database, collection):
    171     """
    172     Get a collections handle in a database returns database and collection object
    173     """
    174     db = getattr(client,database) 
    175     col = getattr(db,collection)
    176     return (db, col)
    177 
    178 def find_and_modify(query, record, col):
    179     """
    180     Find a document in collection based on index and update
    181     """
    182     retval = col.find_and_modify(query, update={'$set' : record}, upsert=True,  new=True)
    183 
    184     return retval
    185 
    186 def find(query, col):
    187     """
    188     Find a document in collection based on query
    189     """
    190     retval = col.find(query).count()
    191 
    192     if retval > 1:
    193       return True
    194     else:
    195       return False
    196 
    197 def find_one(query, col):
    198     """
    199     Find a document in collection based on query
    200     """
    201     retval = col.find_one(query)
    202     if retval is not None:  
    203       return True
    204     else:
    205       return False
    206 
    207 def insert(record, col):
    208     """
    209     Find a document in collection based on query
    210     """
    211     retval = col.insert(record, manipulate=True)
    212 
    213     if retval is not None:
    214       return True
    215     else:
    216       return False
    217 
    218 
    219 if __name__ == "__main__":
    220    args = docopt(__doc__)
    221    network = args["<network>"]
    222    output = run_nmap(network)
    223    records = parsexml(output)
    224 
    225    if args["--hosts"]:
    226     print_hosts(records)   
    227    elif args["--ansible"]:
    228     print_ansible(records)
    229    elif args["--raw"]:
    230     print_raw(records)
    231 
    232    elif args["--mongo-host"]:
    233     url = "mongodb://{host}:{port}/".format(host=args["--mongo-host"], port=args["--mongo-port"])
    234     client = MongoClient(url)
    235     (db, col)  = get_mongo_handle(client, args["--database"], args["--collection"])
    236     update_collection(records, col)
    237     client.close()
    238    else:
    239       print("Printing host records\n")
    240       print_hosts(records)
    241 
    242 
    243