Expand Up 
  
 @@ -120,7 +120,12 @@ def do_scan(host, nmap_path, ports=None, arguments=None): 
  
 
 
  perform the nmap scan  
 
 
 
  """  
 
 
 
  if arguments is None:  
 
 
 
  arguments = "-sV"  
 
 
 
 
  lib.output.misc_info("using default scan arguments")  
 
 
 
 
  arguments = [  
 
 
 
 
  "-sF", "-Pn", "-sV",  
 
 
 
 
  "-O", "-F", "--reason",  
 
 
 
 
  "-vvv"  
 
 
 
 
  ]  
 
 
 
  launch_arguments = [  
 
 
 
  nmap_path, '-oX', '-', host,  
 
 
 
  '-p ' + ports if ports is not None else "",  
 
 
 
 
 
  
  
 Expand Down 
 
 
  
  
 Expand Up 
  
 @@ -150,106 +155,235 @@ def do_scan(host, nmap_path, ports=None, arguments=None): 
  
 
 
  return output_data, "".join(nmap_warn_tracestack), "".join(nmap_error_tracestack)  
 
 
 
  
 
 
 
  
 
 
 
 
 # copy pasta :DD  
 
 
 
 
 # https://github.com/komand/python-nmap/blob/master/nmap/nmap.py#L273  
 
 
 
 def parse_xml_output(output, warnings, error):  
 
 
 
  """  
 
 
 
  parse the XML data out of the file into a dict  
 
 
 
 
  Analyses NMAP xml scan ouput  
 
 
 
 
  May raise PortScannerError exception if nmap output was not xml  
 
 
 
 
  Test existance of the following key to know if something went wrong : ['nmap']['scaninfo']['error']  
 
 
 
 
  If not present, everything was ok.  
 
 
 
 
  :param nmap_xml_output: xml string to analyse  
 
 
 
 
  :returns: scan_result as dictionnary  
 
 
 
  """  
 
 
 
  results = {}  
 
 
 
 
  # nmap xml output looks like :  
 
 
 
 
  # <host starttime="1267974521" endtime="1267974522">  
 
 
 
 
  # <status state="up" reason="user-set"/>  
 
 
 
 
  # <address addr="192.168.1.1" addrtype="ipv4" />  
 
 
 
 
  # <hostnames><hostname name="neufbox" type="PTR" /></hostnames>  
 
 
 
 
  # <ports>  
 
 
 
 
  # <port protocol="tcp" portid="22">  
 
 
 
 
  # <state state="filtered" reason="no-response" reason_ttl="0"/>  
 
 
 
 
  # <service name="ssh" method="table" conf="3" />  
 
 
 
 
  # </port>  
 
 
 
 
  # <port protocol="tcp" portid="25">  
 
 
 
 
  # <state state="filtered" reason="no-response" reason_ttl="0"/>  
 
 
 
 
  # <service name="smtp" method="table" conf="3" />  
 
 
 
 
  # </port>  
 
 
 
 
  # </ports>  
 
 
 
 
  # <hostscript>  
 
 
 
 
  # <script id="nbstat" output="NetBIOS name: GROSTRUC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown>
" />  
 
 
 
 
  # <script id="smb-os-discovery" output=" 
 OS: Unix (Samba 3.6.3)
 Name: WORKGROUP\Unknown
 System time: 2013年06月23日 15:37:40 UTC+2
" />  
 
 
 
 
  # <script id="smbv2-enabled" output="Server doesn't support SMBv2 protocol" />  
 
 
 
 
  # </hostscript>  
 
 
 
 
  # <times srtt="-1" rttvar="-1" to="1000000" />  
 
 
 
 
  # </host>  
 
 
 
 
  # <port protocol="tcp" portid="25">  
 
 
 
 
  # <state state="open" reason="syn-ack" reason_ttl="0"/>  
 
 
 
 
  # <service name="smtp" product="Exim smtpd" version="4.76" hostname="grostruc" method="probed" conf="10">  
 
 
 
 
  # <cpe>cpe:/a:exim:exim:4.76</cpe>  
 
 
 
 
  # </service>  
 
 
 
 
  # <script id="smtp-commands" output="grostruc Hello localhost [127.0.0.1], SIZE 52428800, PIPELINING, HELP, 
 Commands supported: AUTH HELO EHLO MAIL RCPT DATA NOOP QUIT RSET HELP "/>  
 
 
 
 
  # </port>  
 
 
 
 
  scan_result = {}  
 
 
 
  try:  
 
 
 
  root  = ElementTree.fromstring(output)  
 
 
 
 
  dom  = ElementTree.fromstring(output)  
 
 
 
  except Exception:  
 
 
 
  if len(error) !=  0:  
 
 
 
 
  if len(error) >  0:  
 
 
 
  raise lib.errors.NmapScannerError(error)  
 
 
 
  else:  
 
 
 
  raise lib.errors.NmapScannerError(output)  
 
 
 
  results['nmap_scan'] = {  
 
 
 
  'full_command_line': root.get('args'),  
 
 
 
  'scan_information': {},  
 
 
 
  'scan_stats': {  
 
 
 
  'time_string': root.find('runstats/finished').get('timestr'),  
 
 
 
  'elapsed': root.find('runstats/finished').get('elapsed'),  
 
 
 
  'hosts_up': root.find('runstats/hosts').get('up'),  
 
 
 
  'down_hosts': root.find('runstats/hosts').get('down'),  
 
 
 
  'total_hosts_scanned': root.find('runstats/hosts').get('total')  
 
 
 
 
  # nmap command line  
 
 
 
 
  scan_result['nmap'] = {  
 
 
 
 
  'command_line': dom.get('args'),  
 
 
 
 
  'scaninfo': {},  
 
 
 
 
  'scanstats': {  
 
 
 
 
  'timestr': dom.find("runstats/finished").get('timestr'),  
 
 
 
 
  'elapsed': dom.find("runstats/finished").get('elapsed'),  
 
 
 
 
  'uphosts': dom.find("runstats/hosts").get('up'),  
 
 
 
 
  'downhosts': dom.find("runstats/hosts").get('down'),  
 
 
 
 
  'totalhosts': dom.find("runstats/hosts").get('total')}  
 
 
 
  }  
 
 
 
  }  
 
 
 
  if len(error) != 0:  
 
 
 
  results['nmap_scan']['scan_information']['errors'] = error  
 
 
 
  if len(warnings) != 0:  
 
 
 
  results['nmap_scan']['scan_information']['warnings'] = warnings  
 
 
 
  for info in root.findall('scaninfo'):  
 
 
 
  results['nmap_scan']['scan_information'][info.get('protocol')] = {  
 
 
 
  'method': info.get('type'),  
 
 
 
  'services': info.get('services')  
 
 
 
  }  
 
 
 
  for attempted_host in root.findall('host'):  
 
 
 
 
  # if there was an error  
 
 
 
 
  if len(error) > 0:  
 
 
 
 
  scan_result['nmap']['scaninfo']['error'] = error  
 
 
 
 
  # if there was a warning  
 
 
 
 
  if len(warnings) > 0:  
 
 
 
 
  scan_result['nmap']['scaninfo']['warning'] = warnings  
 
 
 
 
  # info about scan  
 
 
 
 
  for dsci in dom.findall('scaninfo'):  
 
 
 
 
  scan_result['nmap']['scaninfo'][dsci.get('protocol')] = {  
 
 
 
 
  'method': dsci.get('type'),  
 
 
 
 
  'services': dsci.get('services')  
 
 
 
 
  }  
 
 
 
 
  scan_result['scan'] = {}  
 
 
 
 
  for dhost in dom.findall('host'):  
 
 
 
 
  # host ip, mac and other addresses  
 
 
 
  host = None  
 
 
 
  addresses  = {}  
 
 
 
  vendors  = {}  
 
 
 
  for address in attempted_host .findall(" address" ):  
 
 
 
  address_type  = address.get('addrtype')  
 
 
 
  addresses[address_type ] = address.get('addr')  
 
 
 
  if address_type  == " ipv4" :  
 
 
 
  host = addresses[address_type ]  
 
 
 
  elif address_type  == " mac"  and address.get('vendor') is not None:  
 
 
 
  vendors[addresses[address_type ]] = address.get('vendor')  
 
 
 
 
  address_block  = {}  
 
 
 
 
  vendor_block  = {}  
 
 
 
 
  for address in dhost .findall(' address' ):  
 
 
 
 
  addtype  = address.get('addrtype')  
 
 
 
 
  address_block[addtype ] = address.get('addr')  
 
 
 
 
  if addtype  == ' ipv4' :  
 
 
 
 
  host = address_block[addtype ]  
 
 
 
 
  elif addtype  == ' mac'  and address.get('vendor') is not None:  
 
 
 
 
  vendor_block[address_block[addtype ]] = address.get('vendor')  
 
 
 
  if host is None:  
 
 
 
  host = attempted_host .find('address').get('addr')  
 
 
 
 
  host = dhost .find('address').get('addr')  
 
 
 
  hostnames = []  
 
 
 
  if len(attempted_host .findall('hostnames/hostname')) !=  0:  
 
 
 
  for current_hostnames  in attempted_host .findall('hostnames/hostname'):  
 
 
 
 
  if len(dhost .findall('hostnames/hostname')) >  0:  
 
 
 
 
  for dhostname  in dhost .findall('hostnames/hostname'):  
 
 
 
  hostnames.append({  
 
 
 
  'hostname ': current_hostnames .get('name'),  
 
 
 
  'host_type ': current_hostnames .get('type')  
 
 
 
 
  'name ': dhostname .get('name'),  
 
 
 
 
  'type ': dhostname .get('type'),   
 
 
 
  })  
 
 
 
  else:  
 
 
 
  hostnames.append({  
 
 
 
  'hostname ': None ,  
 
 
 
  'host_type ': None   
 
 
 
 
  'name ': '' ,  
 
 
 
 
  'type ': '',   
 
 
 
  })  
 
 
 
  
 
 
 
  results['nmap_scan'][host] = {}  
 
 
 
  results['nmap_scan'][host]['hostnames'] = hostnames  
 
 
 
  results['nmap_scan'][host]['addresses'] = addresses  
 
 
 
  results['nmap_scan'][host]['vendors'] = vendors  
 
 
 
  
 
 
 
  for status in attempted_host.findall('status'):  
 
 
 
  results['nmap_scan'][host]['status'] = {  
 
 
 
  'state': status.get('state'),  
 
 
 
  'reason': status.get('reason')  
 
 
 
  }  
 
 
 
  for uptime in attempted_host.findall('uptime'):  
 
 
 
  results['nmap_scan'][host]['uptime'] = {  
 
 
 
  'seconds': uptime.get('seconds'),  
 
 
 
  'lastboot': uptime.get('lastboot')  
 
 
 
  }  
 
 
 
  for discovered_port in attempted_host.findall('ports/port'):  
 
 
 
  protocol = discovered_port.get('protocol')  
 
 
 
  port_number = discovered_port.get('portid')  
 
 
 
  port_state = discovered_port.find('state').get('state')  
 
 
 
  port_reason = discovered_port.find('state').get('reason')  
 
 
 
  
 
 
 
  # this is actually a thing!!  
 
 
 
  name = discovered_config = discovered_version = extra_information = discovered_product = stuff = ""  
 
 
 
  for discovered_name in discovered_port.findall('service'):  
 
 
 
  name = discovered_name.get('name')  
 
 
 
  if discovered_name.get('product'):  
 
 
 
  discovered_product = discovered_name.get('product')  
 
 
 
  if discovered_name.get('version'):  
 
 
 
  discovered_version = discovered_name.get('version')  
 
 
 
  if discovered_name.get('extrainfo'):  
 
 
 
  extra_information = discovered_name.get('extrainfo')  
 
 
 
  if discovered_name.get('conf'):  
 
 
 
  discovered_config = discovered_name.get('conf')  
 
 
 
  
 
 
 
  for other_stuff in discovered_name.findall('cpe'):  
 
 
 
  stuff = other_stuff.text  
 
 
 
  if protocol not in results['nmap_scan'][host].keys():  
 
 
 
  results['nmap_scan'][host][protocol] = list()  
 
 
 
  results['nmap_scan'][host][protocol].append({  
 
 
 
  'port': port_number, 'state': port_state, 'reason': port_reason,  
 
 
 
  'name': name, 'product': discovered_product, 'version': discovered_version,  
 
 
 
  'extrainfo': extra_information, 'conf': discovered_config, 'cpe': stuff  
 
 
 
 
  scan_result['scan'][host] = {'hostnames': hostnames}  
 
 
 
 
  scan_result['scan'][host]['addresses'] = address_block  
 
 
 
 
  scan_result['scan'][host]['vendor'] = vendor_block  
 
 
 
 
  for dstatus in dhost.findall('status'):  
 
 
 
 
  # status : up...  
 
 
 
 
  scan_result['scan'][host]['status'] = {'state': dstatus.get('state'),  
 
 
 
 
  'reason': dstatus.get('reason')}  
 
 
 
 
  for dstatus in dhost.findall('uptime'):  
 
 
 
 
  # uptime : seconds, lastboot  
 
 
 
 
  scan_result['scan'][host]['uptime'] = {'seconds': dstatus.get('seconds'),  
 
 
 
 
  'lastboot': dstatus.get('lastboot')}  
 
 
 
 
  for dport in dhost.findall('ports/port'):  
 
 
 
 
  # protocol  
 
 
 
 
  proto = dport.get('protocol')  
 
 
 
 
  # port number converted as integer  
 
 
 
 
  port = int(dport.get('portid'))  
 
 
 
 
  # state of the port  
 
 
 
 
  state = dport.find('state').get('state')  
 
 
 
 
  # reason  
 
 
 
 
  reason = dport.find('state').get('reason')  
 
 
 
 
  # name, product, version, extra info and conf if any  
 
 
 
 
  name = product = version = extrainfo = conf = cpe = ''  
 
 
 
 
  for dname in dport.findall('service'):  
 
 
 
 
  name = dname.get('name')  
 
 
 
 
  if dname.get('product'):  
 
 
 
 
  product = dname.get('product')  
 
 
 
 
  if dname.get('version'):  
 
 
 
 
  version = dname.get('version')  
 
 
 
 
  if dname.get('extrainfo'):  
 
 
 
 
  extrainfo = dname.get('extrainfo')  
 
 
 
 
  if dname.get('conf'):  
 
 
 
 
  conf = dname.get('conf')  
 
 
 
 
  for dcpe in dname.findall('cpe'):  
 
 
 
 
  cpe = dcpe.text  
 
 
 
 
  # store everything  
 
 
 
 
  if proto not in list(scan_result['scan'][host].keys()):  
 
 
 
 
  scan_result['scan'][host][proto] = list()  
 
 
 
 
  # Komand - change proto from dict to list to ease output spec  
 
 
 
 
  scan_result['scan'][host][proto].append({  
 
 
 
 
  'port': port,  
 
 
 
 
  'state': state,  
 
 
 
 
  'reason': reason,  
 
 
 
 
  'name': name,  
 
 
 
 
  'product': product,  
 
 
 
 
  'version': version,  
 
 
 
 
  'extrainfo': extrainfo,  
 
 
 
 
  'conf': conf,  
 
 
 
 
  'cpe': cpe  
 
 
 
 
  })  
 
 
 
 
  script_id = ''  
 
 
 
 
  script_out = ''  
 
 
 
 
  # get script output if any  
 
 
 
 
  for dscript in dport.findall('script'):  
 
 
 
 
  script_id = dscript.get('id')  
 
 
 
 
  script_out = dscript.get('output')  
 
 
 
 
  if 'script' not in list(scan_result['scan'][host][proto][port].keys()):  
 
 
 
 
  scan_result['scan'][host][proto][port]['script'] = {}  
 
 
 
 
  scan_result['scan'][host][proto][port]['script'][script_id] = script_out  
 
 
 
 
  # <hostscript>  
 
 
 
 
  # <script id="nbstat" output="NetBIOS name: GROSTRUC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown>
" />  
 
 
 
 
  # <script id="smb-os-discovery" output=" 
 OS: Unix (Samba 3.6.3)
 Name: WORKGROUP\Unknown
 System time: 2013年06月23日 15:37:40 UTC+2
" />  
 
 
 
 
  # <script id="smbv2-enabled" output="Server doesn't support SMBv2 protocol" />  
 
 
 
 
  # </hostscript>  
 
 
 
 
  for dhostscript in dhost.findall('hostscript'):  
 
 
 
 
  for dname in dhostscript.findall('script'):  
 
 
 
 
  hsid = dname.get('id')  
 
 
 
 
  hsoutput = dname.get('output')  
 
 
 
 
  if 'hostscript' not in list(scan_result['scan'][host].keys()):  
 
 
 
 
  scan_result['scan'][host]['hostscript'] = []  
 
 
 
 
  scan_result['scan'][host]['hostscript'].append(  
 
 
 
 
  {  
 
 
 
 
  'id': hsid,  
 
 
 
 
  'output': hsoutput  
 
 
 
 
  }  
 
 
 
 
  )  
 
 
 
 
  # <osmatch name="Juniper SA4000 SSL VPN gateway (IVE OS 7.0)" accuracy="98" line="36241">  
 
 
 
 
  # <osclass type="firewall" vendor="Juniper" osfamily="IVE OS" osgen="7.X"  
 
 
 
 
  # accuracy="98"><cpe>cpe:/h:juniper:sa4000</cpe><cpe>cpe:/o:juniper:ive_os:7</cpe></osclass>  
 
 
 
 
  # </osmatch>  
 
 
 
 
  # <osmatch name="Cymphonix EX550 firewall" accuracy="98" line="17929">  
 
 
 
 
  # <osclass type="firewall" vendor="Cymphonix" osfamily="embedded"  
 
 
 
 
  # accuracy="98"><cpe>cpe:/h:cymphonix:ex550</cpe></osclass>  
 
 
 
 
  # </osmatch>  
 
 
 
 
  for dos in dhost.findall('os'):  
 
 
 
 
  osmatch = []  
 
 
 
 
  portused = []  
 
 
 
 
  for dportused in dos.findall('portused'):  
 
 
 
 
  # <portused state="open" proto="tcp" portid="443"/>  
 
 
 
 
  state = dportused.get('state')  
 
 
 
 
  proto = dportused.get('proto')  
 
 
 
 
  portid = dportused.get('portid')  
 
 
 
 
  portused.append({  
 
 
 
 
  'state': state,  
 
 
 
 
  'proto': proto,  
 
 
 
 
  'portid': portid,  
 
 
 
  })  
 
 
 
  
 
 
 
  return results  
 
 
 
 
  scan_result['scan'][host]['portused'] = portused  
 
 
 
 
  for dosmatch in dos.findall('osmatch'):  
 
 
 
 
  # <osmatch name="Linux 3.7 - 3.15" accuracy="100" line="52790">  
 
 
 
 
  name = dosmatch.get('name')  
 
 
 
 
  accuracy = dosmatch.get('accuracy')  
 
 
 
 
  line = dosmatch.get('line')  
 
 
 
 
  osclass = []  
 
 
 
 
  for dosclass in dosmatch.findall('osclass'):  
 
 
 
 
  # <osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="98"/>  
 
 
 
 
  ostype = dosclass.get('type')  
 
 
 
 
  vendor = dosclass.get('vendor')  
 
 
 
 
  osfamily = dosclass.get('osfamily')  
 
 
 
 
  osgen = dosclass.get('osgen')  
 
 
 
 
  accuracy = dosclass.get('accuracy')  
 
 
 
 
  cpe = []  
 
 
 
 
  for dcpe in dosclass.findall('cpe'):  
 
 
 
 
  cpe.append(dcpe.text)  
 
 
 
 
  osclass.append({  
 
 
 
 
  'type': ostype,  
 
 
 
 
  'vendor': vendor,  
 
 
 
 
  'osfamily': osfamily,  
 
 
 
 
  'osgen': osgen,  
 
 
 
 
  'accuracy': accuracy,  
 
 
 
 
  'cpe': cpe,  
 
 
 
 
  })  
 
 
 
 
  osmatch.append({  
 
 
 
 
  'name': name,  
 
 
 
 
  'accuracy': accuracy,  
 
 
 
 
  'line': line,  
 
 
 
 
  'osclass': osclass  
 
 
 
 
  })  
 
 
 
 
  else:  
 
 
 
 
  scan_result['scan'][host]['osmatch'] = osmatch  
 
 
 
 
  for dport in dhost.findall('osfingerprint'):  
 
 
 
 
  # <osfingerprint fingerprint="OS:SCAN(V=5.50%D=11/[...]S)
"/>  
 
 
 
 
  fingerprint = dport.get('fingerprint')  
 
 
 
 
  scan_result['scan'][host]['fingerprint'] = fingerprint  
 
 
 
 
  return scan_result