diff options
Diffstat (limited to 'Monitoring/plugins/nmap_discovery_runner.py')
-rwxr-xr-x | Monitoring/plugins/nmap_discovery_runner.py | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/Monitoring/plugins/nmap_discovery_runner.py b/Monitoring/plugins/nmap_discovery_runner.py new file mode 100755 index 00000000..338e211f --- /dev/null +++ b/Monitoring/plugins/nmap_discovery_runner.py @@ -0,0 +1,419 @@ +#!/usr/bin/env python +#Copyright (C) 2009-2010 : +# Gabes Jean, naparuba@gmail.com +# Gerhard Lausser, Gerhard.Lausser@consol.de +# Gregory Starck, g.starck@gmail.com +# +#This file is part of Shinken. +# +#Shinken is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. +# +#Shinken is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU Affero General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with Shinken. If not, see <http://www.gnu.org/licenses/>. + +#sudo nmap 192.168.0.1 -T4 -O --traceroute -oX toto.xml + +import optparse +import sys +import os +import tempfile +import subprocess + +try: + # xml.etree.ElementTree is new in Python 2.5 + from xml.etree.ElementTree import ElementTree +except ImportError: + sys.exit("This script needs the Python ElementTree module. Please install it") + +VERSION = '0.1' + +parser = optparse.OptionParser( + "%prog [options] -t nmap scanning targets", + version="%prog " + VERSION) + +parser.add_option('-t', '--targets', dest="targets", + help="NMap scanning targets.") +parser.add_option('-v', '--verbose', dest="verbose", action='store_true', + help="Verbose output.") + +targets = [] +opts, args = parser.parse_args() +if not opts.targets: + parser.error("Requires at least one nmap target for scanning (option -t/--targets") +else: + targets.append(opts.targets) + +if not opts.verbose: + verbose = False +else: + verbose = True + +if args: + targets.extend(args) + +print "Got our target", targets + +def debug(txt): + if verbose: + print txt + +# Says if a host is up or not +def is_up(h): + status = h.find('status') + state = status.attrib['state'] + return state == 'up' + + + +class DetectedHost: + def __init__(self): + self.ip = '' + self.mac_vendor = '' + self.host_name = '' + + self.os_possibilities = [] + self.os = ('', '') + self.open_ports = [] + + self.parent = '' + + + # Keep the first name we've got + def set_host_name(self, name): + if self.host_name == '': + self.host_name = name + + + # Get a identifier for this host + def get_name(self): + if self.host_name != '': + return self.host_name + if self.ip != '': + return self.ip + return None + + # We look for the host VMWare + def is_vmware_esx(self): + # If it's not a virtual machine bail out + if self.mac_vendor != 'VMware': + return False + # If we got all theses ports, we are quite ok for + # a VMWare host + needed_ports = [22, 80, 443, 902, 903, 5989] + for p in needed_ports: + if p not in self.open_ports: + # find one missing port, not a VMWare host + return False + # Ok all ports are found, we are a ESX :) + return True + + # Says if we are a virtual machine or not + def is_vmware_vm(self): + # special case : the esx host itself + if self.is_vmware_esx(): + return False + # Else, look at the mac vendor + return self.mac_vendor == 'VMware' + + + # Fill the different os possibilities + def add_os_possibility(self, os, osgen, accuracy): + self.os_possibilities.append( (os, osgen, accuracy) ) + + + # We search if our potential parent is present in the + # other detected hosts. If so, set it as my parent + def look_for_parent(self, all_hosts): + self.parents = [] + parent = self.parent + debug("Look for my parent %s -> %s" % (self.get_name(), parent)) + # Ok, we didn't find any parent + # we bail out + if parent == '': + return + for h in all_hosts: + debug("Is it you? %s" % h.get_name()) + if h.get_name() == parent: + debug("Houray, we find our parent %s -> %s" % (self.get_name(), h.get_name())) + self.parents.append(h.get_name()) + + + + + # Look at ours oses and see which one is the better + def compute_os(self): + self.os_name = 'Unknown OS' + self.os_version = 'Unknown Version' + + # bailout if we got no os :( + if len(self.os_possibilities) == 0: + return + + max_accuracy = 0 + for (os, osgen, accuracy) in self.os_possibilities: + if accuracy > max_accuracy: + max_accuracy = accuracy + + # now get the entry with the max value + for (os, osgen, accuracy) in self.os_possibilities: + print "Can be", (os, osgen, accuracy) + if accuracy == max_accuracy: + self.os = (os, osgen) + + print "Try to match", self.os + + #Ok, unknown os... not good + if self.os == ('', ''): + return + + map = {('Windows', '2000') : 'windows', + ('Windows', '2003') : 'windows', + ('Windows', '7') : 'windows', + ('Windows', 'XP') : 'windows', + # ME? you are a stupid moron! + ('Windows', 'Me') : 'windows', + ('Windows', '2008') : 'windows', + # that's a good boy :) + ('Linux', '2.6.X') : 'linux', + ('Linux', '2.4.X') : 'linux', + # HPUX? I think you didn't choose... + ('HP-UX', '11.X') : 'hpux', + ('HP-UX', '10.X') : 'hpux', + } + + if self.os not in map: + return + + self.os_name = map[self.os] + self.os_version = self.os[1] +# self.templates.append(t) +# +# # Look for VMWare VM or hosts +# if self.h.is_vmware_vm(): +# self.templates.append('vmware-vm') +# # Now is an host? +# if self.h.is_vmware_esx(): +# self.templates.append('vmware-host') + + + # Return the string of the 'discovery' items + def get_discovery_output(self): + r = [] + r.append('%s::isup=1' % self.get_name()) + r.append(self.get_discovery_system()) + r.append(self.get_discovery_macvendor()) + op = self.get_discovery_ports() + if op != '': + r.append(op) + par = self.get_discovery_parents() + if par != '': + r.append(par) + fqdn = self.get_dicovery_fqdn() + if fqdn != '': + r.append(fqdn) + ip = self.get_discovery_ip() + if ip != '': + r.append(ip) + return r + + + # for system output + def get_discovery_system(self): + r = '%s::os=%s' % (self.get_name(), self.os_name)+'\n' + r += '%s::osversion=%s' % (self.get_name(), self.os_version) + return r + + def get_discovery_macvendor(self): + return '%s::macvendor=%s' % (self.get_name(), self.mac_vendor) + + def get_discovery_ports(self): + if self.open_ports == []: + return '' + return '%s::openports=%s' % (self.get_name(), ','.join([str(p) for p in self.open_ports])) + + def get_discovery_parents(self): + if self.parents == []: + return '' + return '%s::parents=%s' % (self.get_name(), ','.join(self.parents)) + + def get_dicovery_fqdn(self): + if self.host_name == '': + return '' + return '%s::fqdn=%s' % (self.get_name(), self.host_name) + + def get_discovery_ip(self): + if self.ip == '': + return '' + return '%s::ip=%s' % (self.get_name(), self.ip) + + +(_, tmppath) = tempfile.mkstemp() + +print "propose a tmppath", tmppath + +cmd = "sudo nmap %s -T4 -O --traceroute -oX %s" % (' '.join(targets) , tmppath) +print "Launching command,", cmd +try: + nmap_process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + close_fds=True, shell=True) +except OSError , exp: + print "Debug : Error in launching command:", cmd, exp + sys.exit(2) + +print "Try to communicate" +(stdoutdata, stderrdata) = nmap_process.communicate() + +if nmap_process.returncode != 0: + print "Error : the nmap return an error : '%s'" % stderrdata + sys.exit(2) + +print "Got it", (stdoutdata, stderrdata) + +xml_input = tmppath + +tree = ElementTree() +try: + tree.parse(xml_input) +except IOError, exp: + print "Error opening file '%s' : %s" % (xml_input, exp) + sys.exit(2) + +hosts = tree.findall('host') +debug("Number of hosts : %d" % len(hosts)) + + +all_hosts = [] + +for h in hosts: + # Bypass non up hosts + if not is_up(h): + continue + + dh = DetectedHost() + + # Now we get the ipaddr and the mac vendor + # for future VMWare matching + #print h.__dict__ + addrs = h.findall('address') + for addr in addrs: + #print "Address", addr.__dict__ + addrtype = addr.attrib['addrtype'] + if addrtype == 'ipv4': + dh.ip = addr.attrib['addr'] + if addrtype == "mac": + if 'vendor' in addr.attrib: + dh.mac_vendor = addr.attrib['vendor'] + + + # Now we've got the hostnames + host_names = h.findall('hostnames') + for h_name in host_names: + h_names = h_name.findall('hostname') + for h_n in h_names: + #print 'hname', h_n.__dict__ + #print 'Host name', h_n.attrib['name'] + dh.set_host_name(h_n.attrib['name']) + + + # Now print the traceroute + traces = h.findall('trace') + for trace in traces: + #print trace.__dict__ + hops = trace.findall('hop') + #print "Number of hops", len(hops) + distance = len(hops) + if distance >= 2: + for hop in hops: + ttl = int(hop.attrib['ttl']) + #We search for the direct father + if ttl == distance-1: + #print ttl + #print "Super hop", hop.__dict__ + # Get the host name if possible, if not + # take the IP + if 'host' in hop.attrib: + dh.parent = hop.attrib['host'] + else: + dh.parent = hop.attrib['ipaddr'] + + + # Now the OS detection + ios = h.find('os') + #print os.__dict__ + cls = ios.findall('osclass') + for c in cls: + #print "Class", c.__dict__ + family = c.attrib['osfamily'] + accuracy = c.attrib['accuracy'] + if 'osgen' in c.attrib: + osgen = c.attrib['osgen'] + else: + osgen = None + #print "Type:", family, osgen, accuracy + dh.add_os_possibility(family, osgen, accuracy) + # Ok we can compute our OS now :) + dh.compute_os() + + + # Now the ports :) + allports = h.findall('ports') + for ap in allports: + ports = ap.findall('port') + for p in ports: + #print "Port", p.__dict__ + p_id = p.attrib['portid'] + s = p.find('state') + #print s.__dict__ + state = s.attrib['state'] + if state == 'open': + dh.open_ports.append(int(p_id)) + + #print dh.__dict__ + all_hosts.append(dh) + #print "\n\n" + + + +for h in all_hosts: + name = h.get_name() + if not name: + continue + + debug("Doing name %s" % name) + #path = os.path.join(output_dir, name+'.discover') + #print "Want path", path + #f = open(path, 'wb') + #cPickle.dump(h, f) + #f.close() + debug(str(h.__dict__)) + # And generate the configuration too + h.look_for_parent(all_hosts) + #c.fill_system_conf() + #c.fill_ports_services() + #c.fill_system_services() +# c.write_host_configuration() + #print "Host config", c.get_cfg_for_host() +# c.write_services_configuration() + #print "Service config" + #print c.get_cfg_for_services() + #print c.__dict__ + print '\n'.join(h.get_discovery_output()) + #print "\n\n\n" + + +# Try to remove the temppath +try: + os.unlink(tmppath) +except Exception: + pass + |