Nessus Grep

The code is pretty self explanatory. It searches through a .nessus file and spits out matching hosts.


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

arg[0] [--dns]  myfile.nessus regex

For a regex reference, see

The --dns flag will print out the dns name in addition to what was given for 
the scan


#search for hosts that ran the nikto plugin
python scan.nessus nikto

#case insensitive search for nikto
python 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 scan.nessus "^10386$" 

#find all hosts with either the SSL Cipher "bug" or running SSL Version 2
python 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:
      if, i):
        return True
    except TypeError:

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

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

if __name__ == "__main__":
  if len(sys.argv) < 3:
  filelist = sys.argv[1:-1]
    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) 

Matching Regular Expressions that don’t end with…

Regular expressions do not mix well with syntax that requires memory, such as XML. I was trying to add a <br /> tag to every line that did not have a </p> tag. so for example I can print the strings I want with grep -v ‘^.*</P>’

Anyway, this turns out to be a bear, because (?!expression) just isn’t working for me with sed, although I think google says it should.

So what do I do? I make two!

s/(w.*</p>)/1<br />/g

adds a <br /> to every line with a word.

s/(.*</p>)<br />/1/g

take off the <br /> for lines that have a </p>

The good thing about this is it should work with all standard regular expressions, unlike that look ahead stuff which may only work with certain utilities.

You could run this with sed, vim, perl, python, whatever, and it will work.