Created
August 12, 2010 18:26
-
-
Save swdunlop/521426 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 ) | |
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