public
Created

  • Download Gist
nscross.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#!/usr/bin/env python
 
'''
Generates a cross-reference of findings in a Nessus dump, organizing them by finding and enumerating hosts. This is useful for penetration testers and other security professionals who
often need to group a number of similar hosts for remediation.
'''
 
import sys, lxml.etree as et
 
findings_by_pid = {}
findings = []
 
class Finding:
def __init__( self, pid, severity, cve, name, synopsis ):
self.pid = pid
self.severity = severity
self.cve = cve
self.name = name
self.synopsis = synopsis
self.instances = []
findings_by_pid[ pid ] = self
findings.append( self )
 
class Instance:
def __init__( self, ip, fqdn, portno ):
self.ip = ip
self.fqdn = fqdn
self.portno = portno
 
def find_text( node, tag, alt=None ):
node = node.find( tag )
if node is not None:
return node.text or None
return None
 
def process_report_item( ip, fqdn, data ):
portno = data.get( 'port' )
pid = int( data.get( 'pluginID' ) )
finding = findings_by_pid.get( pid )
 
if finding is None:
name = data.get( 'pluginName' )
synopsis = find_text( data, 'synopsis' )
cve = find_text( data, 'cve' )
severity = int( data.get( 'severity' ) )
finding = Finding( pid, severity, cve, name, synopsis )
 
instance = Instance( ip, fqdn, portno )
finding.instances.append( instance )
 
def process_report_host( data ):
try:
fqdn = data.find( '*/tag[@name="host-fqdn"]' ).text
except:
fqdn = None
try:
ip = data.find( '*/tag[@name="host-ip"]' ).text
except:
ip = data.get( 'name' ) or None
 
report_items = data.findall( 'ReportItem' )
for report_item in report_items:
data = process_report_item( ip, fqdn, report_item )
def print_finding( finding ):
if finding.cve:
print "-- %s [%s]" % (finding.name, finding.cve)
else:
print "-- %s" % finding.name
 
for instance in finding.instances:
if instance.fqdn and instance.ip:
print " %s (%s), port %s" % ( instance.fqdn, instance.ip, instance.portno )
elif instance.fqdn:
print " %s, port %s" % ( instance.fqdn, instance.portno )
elif instance.ip:
print " %s, port %s" % ( instance.ip, instance.portno )
print
 
def nscross( src_path, min_sev = 3 ):
tree = et.parse( src_path )
report_hosts = tree.findall( '//ReportHost' )
 
for report_host in report_hosts:
data = process_report_host( report_host )
 
for finding in findings:
if finding.severity >= min_sev:
print_finding( finding )
 
if __name__ == "__main__":
if 1 < len( sys.argv ) < 3:
nscross( *sys.argv[1:] )
else:
print >>sys.stderr, 'USAGE: nscross <src.nessus> <minimum-severity>?'
print >>sys.stderr, 'EX 1: nscross sample.nessus'
print >>sys.stderr, 'EX 2: nscross sample.nessus 1'

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.