class Prenus::Input::Nessusin
Public Class Methods
import_nessus_files(options)
click to toggle source
This class method is used to convert a single (or collection) of .nessus (v2) files into 2 different hashes. events and hosts
@return
hosts - a hash of hashes {<hostid> => {:ip => <ip>, :hostname => <hostname>, :os => <os>, :info => <number of informational findings>, :low => <number of low findings>, :med => <number of medium findings>, :high => <number of high findings>, :crit => <number of critical findings>, :total => <total number of findings>, :total_excl_info => <total number of findings excluding informational findings>}} events - a hash of hashes {<nessus_id> => {:family => <vuln family>, :severity => <severity>, :plugin_name => <plugin name>, :synopsis => <synopsis>, :description => <description>, :solution => <solution>, :see_also => <array of solutions>, :cvss_base_score => <CVSS base score>, :cve => <CVE ID>, :cvss_vector => <CVSS vector>, :ports => {<port string>, :hosts => {<hostid>, :result => <result>}}}
@input
options - the hash object with the configuration objections within it. These options include the output folder etc, and are used within many of the methods below
@example
hosts, events = Prenus::Input::Nessusin.import_nessus_files(options)
# File lib/input/nessusin.rb, line 27 def self.import_nessus_files(options) hosts = {} #initialise the output hosts hash events = {} #initialise the output events hash hostid = 0 #initialise the unique hostid #take the options[:input] parameter as a search parameter for input files, we don't check if these are .nessus files or anything #Dir.glob(options[:input]) do |nessus_file| options[:input].each do |nessus_file| Nessus::Parse.new(nessus_file) do |scan| #use the awesome ruby-nessus gem # in the scan file, iterate over each host scan.each_host do |host| ip = host.ip || "" #grap the IP next if ip == "" #I've found sometimes if it doesn't have an IP it means its not scanned for whatever reasons .. like a printer # I next here because I've found it easier to just ignore those which weren't scanned # Lets check if we want to skip an IP for .. whatever reason unless options[:skip].nil? next if options[:skip].include?(ip.to_s) end hostname = host.hostname || "" #grab the hostname os = host.os || "" #grab the os os = os.gsub(/\n/,"/") # sometimes the OS is split over multiple lines - mange them together .. mange mange # Lets check if there's an override array in the config unless options[:override].nil? # Check for this IP address, as this is the primary key we use for overriding ovr = options[:override].detect{|x|x['ip'] == ip.to_s} unless ovr.nil? os = ovr['os'] unless ovr['os'].nil? # Override the OS hostname = ovr['hostname'] unless ovr['hostname'].nil? # Override the hostname end end info = host.informational_severity_count || 0 #grab the number of informational findings low = host.low_severity_count || 0 #grab the number of low findings med = host.medium_severity_count || 0 #grab the number of medium findings high = host.high_severity_count || 0 #grab the number of high findings crit = host.critical_severity_count || 0 #grab the number of critical findings targethostid = hostid #For the moment # Check to see if we already have the host (based on IP, Hostname and OS) if hosts.select {|key,f| f[:os].to_s == os and f[:ip].to_s == ip and f[:hostname].to_s == hostname}.count == 0 # Okay, we don't have this host yet # add the host into the hosts hash hosts[hostid] = {:ip => ip, :hostname => hostname, :os => os, :info => info, :low => low, :med => med, :high => high, :crit => crit, :total => info+low+med+high+crit, :total_excl_info => low+med+high+crit} hostid += 1 # We only increase because we've added a new host else # We do have this host, lets grab the host id hosts.select {|key,f| f[:os].to_s == os and f[:ip].to_s == ip and f[:hostname] == hostname}.each {|k,v| targethostid = k} # Lets now check who has the greatest number of findings, and then we'll use that one going forward if hosts[targethostid][:total].to_i < (info + low + med + high) #therefore the older, previously detected host had more - update the counters hosts[targethostid][:info] = info hosts[targethostid][:low] = low hosts[targethostid][:med] = med hosts[targethostid][:high] = high hosts[targethostid][:crit] = crit hosts[targethostid][:total] = info + low + med + high + crit hosts[targethostid][:total_excl_info] = low + med + high + crit end end # Now lets iterate through each of the findings in this particular host host.each_event do |event| # If the events hash already has this event, lets just add this targethostid to it's hosts array within the ports hash if events.has_key?(event.id) #Lets check the ports hash if events[event.id][:ports].has_key?(event.port.to_s) # We'll only add the hostid if the host's not already in the array events[event.id][:ports][event.port.to_s][:hosts][targethostid] = event.output unless events[event.id][:ports][event.port.to_s][:hosts].include?(targethostid) #Lets add this new port to this hash else events[event.id][:ports][event.port.to_s] = {:hosts => { targethostid => event.output}} end # okay, this event doesn't exist, lets add it to the events hash else events[event.id] = { #:hosts => [hostid], #start the hosts array :family => event.family || "", #vuln family :severity => event.severity || "", #severity :plugin_name => event.plugin_name || "", #plugin name :synopsis => event.synopsis || "", #synopsis :description => event.description || "", #description :solution => event.solution || "", #solution :see_also => event.see_also || "", #see also array :cvss_base_score => event.cvss_base_score || "", #CVSS base score :cve => event.cve || "", #CVE :cvss_vector => event.cvss_vector || "", #CVSS vector #:port => event.port.to_s || "" #port :ports => {} } events[event.id][:ports][event.port.to_s] = {:hosts => {targethostid => event.output}} end end end end end #sort the events by severity crit, high, med, low, info events = events.sort_by{ |k,v| v[:severity]}.reverse #return the hosts and the events hashes return hosts, events end