Class: Prenus::Input::Nessusin

Inherits:
Object
  • Object
show all
Defined in:
lib/input/nessusin.rb

Class Method Summary collapse

Class Method Details

.import_nessus_files(options) ⇒ Object

This class method is used to convert a single (or collection) of .nessus (v2) files into 2 different hashes. events and hosts

Examples:

hosts, events = Prenus::Input::Nessusin.import_nessus_files(options)

Returns:

  • 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>}}}
    


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# 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