Nessus Grep
February 7, 2010 Leave a comment
The code is pretty self explanatory. It searches through a .nessus file and spits out matching hosts.
#!/usr/bin/python
def usage():
print """
This program takes a regular expression for a problem and returns the
affected hosts. It iterates through all reports saved in a .nessus file
making no attempt at uniqueness, (eg if you scanned a host more than once)
searching through titles, data, port, and IDs for matches.
It prints one host per line, relying on tools like wc, tr, sort, uniq
USAGE:
arg[0] [--dns] myfile.nessus regex
For a regex reference, see http://docs.python.org/library/re.html
The --dns flag will print out the dns name in addition to what was given for
the scan
EXAMPLES:
#search for hosts that ran the nikto plugin
python nessus_grep.py scan.nessus nikto
#case insensitive search for nikto
python nessus_grep.py scan.nessus "(?i)nikto"
#it's usually probably ok to just check for id, but be careful
#as an added precaution I give it the beginning end of lines
python nessus_grep.py scan.nessus "^10386$"
#find all hosts with either the SSL Cipher "bug" or running SSL Version 2
python nessus_grep.py scan.nessus "(SSL Weak Cipher Suites Supported|SSL
Version 2 (v2) Protocol Detection)"
"""
import sys
import re
from lxml import etree
def regexsearch(regex, *strings):
for i in strings:
try:
if re.search(regex, i):
return True
except TypeError:
pass
"""
Although there is some repeating logic in dotnessusparse
and dotxmlparse, they are two different formats and are
kept separate in case of changes to only one
"""
def dotnessusparse(nessus_xml, hostprint=False):
for report in nessus_xml.getroot():
if "Report" in repr(report.tag):
for host in report:
if "ReportHost" in host.tag:
hostname = (host.find("HostName").text)
dnsname = host.find("dns_name").text.rstrip(".\n")
if ("(unknown)" in dnsname):
dnsname = ""
reptitem = (host.findall("ReportItem"))
for issue in reptitem:
data = issue.find("data").text
pluginname = issue.find("pluginName").text
pluginid = issue.find("pluginID").text
port = issue.find("port").text
if regexsearch(regex, data, pluginname, pluginid, port):
if hostprint:
hostname = hostname + " (" + dnsname + ")"
print hostname
break
def dotxmlparse(nessus_xml, hostprint=False):
for report in nessus_xml.getroot():
if "Report" in repr(report.tag):
for host in report:
if "ReportHost" in host.tag:
hostname = host.get("name")
dnsname = ""
hostprops = host.find("HostProperties").findall("tag")
for prop in hostprops:
if prop.get("name") == "host-fqdn":
dnsname = prop.text
reptitem = (host.findall("ReportItem"))
for issue in reptitem:
data = sol = syn = plugout = None
if issue.find("description") is not None:
data = issue.find("description").text
if issue.find("solution") is not None:
sol = issue.find("solution").text
if issue.find("synopsis") is not None:
syn = issue.find("synopsis").text
if issue.find("plugin_output") is not None:
plugout = issue.find("plugin_output").text
pluginname = issue.get("pluginName")
pluginId = issue.get("pluginID")
if regexsearch(regex, sol, syn, plugout, pluginname, pluginId):
if hostprint:
hostname = hostname + " (" + dnsname + ")"
print hostname
break
if __name__ == "__main__":
re.IGNORECASE
if len(sys.argv) < 3:
usage()
sys.exit(0)
filelist = sys.argv[1:-1]
try:
filelist.remove("--dns")
hostprint = True
except ValueError:
hostprint = False
regex = sys.argv[-1]
for nessusfile in filelist:
nessus_xml = etree.parse(nessusfile)
if nessusfile.endswith(".nessus"):
dotnessusparse(nessus_xml, hostprint)
if nessusfile.endswith(".xml"):
dotxmlparse(nessus_xml, hostprint)