Skip to content

Instantly share code, notes, and snippets.

@swdunlop
Created August 12, 2010 18:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swdunlop/521426 to your computer and use it in GitHub Desktop.
Save swdunlop/521426 to your computer and use it in GitHub Desktop.
#!/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'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment