Agentless predictive asset scan on networks

This is an agent less solution to scan complete network and build an asset report. All you need is a Linux host with python3 and pythonping, nmap and ipaddress python modules along with nmap Linux package. Since we are not authenticating to hosts and just doing a predictive scan using underline nmap tool, so report may not be 100% accurate. But still it gives fair enough idea of what all you have on your network.

This works as following

  • Explode network into IP addresses.
  • Ping 5 packets to IP, and see the result of 3rd ping.
  • If 3rd ping is successful then run nmap scan with “-O” option to scan operating system on remote host.
  • if return result is not “None”, then parse the returned json data to extract fields of interest.
  • We are extracting OS type, vendor, OS family, OS version, accuracy of prediction, cpe, hardware vendor and MAC address.
  • Out put will be displayed on screen and will get written in CSV file like <network.csv>, for eg 192.168.0.0.csv.

Depending upon firewall rules, this will try to extract max information it can.

Here is the code


#!/usr/local/bin/python3
from pythonping import ping
from multiprocessing import Pool
import sys
import ipaddress
import nmap
import socket
import os

network = sys.argv[1]
ipList = [str(ip) for ip in ipaddress.IPv4Network(network)][1:-1]

path = os.getcwd()+"/"
fname = network.split('/')[0]+".csv"
if os.path.exists(path+fname):
      os.remove(path+fname)

def CommitData(LogMessage):
    try:
         fopen = open(path+fname, "a")
         try:
                fopen.write(LogMessage)
                fopen.close()
         except IOError as e:
                print("Failed to write ",e)
    except IOError as e:
         print("failed to open file", e)

def nmapcheck(host):
   pingErr = ping(host, count=5)._responses[3].error_message
   if pingErr is None:
#        print(pingErr, iphost)
        hostscan = nmap.PortScanner()
        results = hostscan.scan(hosts=host, arguments='-O')
        return(results)
   else:
        return

#ipList = [str(ip) for ip in ipaddress.IPv4Network(network)][1:-1]
#for iphost in ipList:
def ScanHost(iphost):
     results = nmapcheck(iphost)

     if results is not None:
         if 'mac' in results['scan'][iphost]['addresses']:
              macaddr = str(results['scan'][iphost]['addresses']['mac'])
         else:
              macaddr = "None"

         try:
              DNSname = socket.gethostbyaddr(iphost)[0]
         except:
              DNSname = "NotFound"

#         print("HWVendor", results['scan'][iphost])
         if str(results['scan'][iphost]['vendor']):
              hwvendor = str(results['scan'][iphost]['vendor'])
         else:
              hwvendor = "None"

         if results['scan'][iphost]['osmatch'] != []:
              results = results['scan'][iphost]['osmatch'][0]['osclass'][0]
              keys, values = zip(*results.items())
              type, vendor, osfamily, osgen, accuracy, cpe = values[0], values[1], values[2], values[3], values[4], values[5]
              LogMessage = str(iphost)+";"+DNSname+";"+str(type)+";"+str(vendor)+";"+str(osfamily)+";"+str(osgen)+";"+str(accuracy)+";"+str(cpe)+";"+hwvendor+";"+macaddr+"\n"
              CommitData(LogMessage)
              print(LogMessage)
         else:
              type, vendor, osfamily, osgen, accuracy, cpe = "", "", "", "", "", ""
              LogMessage = str(iphost)+";"+DNSname+";"+str(type)+";"+str(vendor)+";"+str(osfamily)+";"+str(osgen)+";"+str(accuracy)+";"+str(cpe)+";"+hwvendor+";"+macaddr+"\n"
              CommitData(LogMessage)
              print(LogMessage)
     else:
         LogMessage = iphost+";"+"ping or nmap failed"+"\n"
         CommitData(LogMessage)
         print(LogMessage)

with Pool(5) as p:
    p.map(ScanHost, ipList)

Save above code as scanAsset.py and give execution permission. Remember this has to executed as “root” user. Lets give a try….


root@scorpio:~#./scanAssets.py 192.168.0.0/24

root@scorpio:~#cat 192.168.0.0.csv
192.168.0.1;host1;general purpose;Linux;Linux;3.X;100;['cpe:/o:linux:linux_kernel:3'];{};EC:xxxxxxxxx
192.168.0.2;general purpose;Linux;Linux;2.6.X;100;['cpe:/o:linux:linux_kernel:2.6'];{'84:xxxxxxxxx': 'Tp-link Technologies'};84:xxxxxxxxxx
192.168.0.3;NotFound;general purpose;Linux;Linux;2.6.X;100;['cpe:/o:linux:linux_kernel:2.6'];{'BC:xxxxxxxxxx': 'Hangzhou Hikvision Digital Technology'};BC:xxxxxxxx
192.168.0.4;ping or nmap failed
192.168.0.5;ping or nmap failed
......
......
192.168.0.17;host17;general purpose;Linux;Linux;3.X;100;['cpe:/o:linux:linux_kernel:3'];{};None
192.168.0.23;general purpose;Linux;Linux;3.X;100;['cpe:/o:linux:linux_kernel:3'];{'B8:xxxxxxxxxxx': 'Raspberry Pi Foundation'};B8:xxxxxxxxxx
192.168.0.24;host24;general purpose;Linux;Linux;3.X;100;['cpe:/o:linux:linux_kernel:3'];{'B8:xxxxxxxxx': 'Raspberry Pi Foundation'};B8:xxxxxxxx
192.168.0.101;host101;specialized;Philips;embedded;None;100;['cpe:/h:philips:hue_bridge'];{};CC:xxxxxxxxxx
192.168.0.102;NotFound;;;;;;;;{'38:xxxxxxxxxxx': 'Xiaomi Communications'};38:xxxxxxxxxxx
192.168.0.111;host111;general purpose;Linux;Linux;2.6.X;100;['cpe:/o:linux:linux_kernel:2.6'];{'54:xxxxxxxxxx': 'Google'};54:xxxxxxxxxxxx
192.168.0.116;NotFound;general purpose;Microsoft;Windows;XP;85;['cpe:/o:microsoft:windows_xp::sp2'];{'E4:xxxxxxxxxxx': 'Intel Corporate'};E4:xxxxxxxxxxxxx