Class: Nessus::ReportItem

Inherits:
Object
  • Object
show all
Defined in:
lib/nessus/report_item.rb

Overview

This class represents each of the /NessusClientData_v2/Report/ReportHost/ReportItem elements in the Nessus XML document.

It provides a convenient way to access the information scattered all over the XML in attributes and nested tags.

Instead of providing separate methods for each supported property we rely on Ruby’s #method_missing to do most of the work.

Instance Method Summary collapse

Constructor Details

#initialize(xml_node) ⇒ ReportItem

Accepts an XML node from Nokogiri::XML.



13
14
15
# File 'lib/nessus/report_item.rb', line 13

def initialize(xml_node)
  @xml = xml_node
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

This method is invoked by Ruby when a method that is not defined in this instance is called.

In our case we inspect the @method@ parameter and try to find the attribute, simple descendent or collection that it maps to in the XML tree.



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
# File 'lib/nessus/report_item.rb', line 55

def method_missing(method, *args)
  
  # We could remove this check and return nil for any non-recognized tag.
  # The problem would be that it would make tricky to debug problems with
  # typos. For instance: <>.potr would return nil instead of raising an
  # exception
  unless supported_tags.include?(method)
    super
    return
  end

  # first we try the attributes: port, svc_name, protocol, severity,
  #   plugin_id, plugin_name, plugin_family
  translations_table = {
    # @port           = xml.attributes["port"]
    # @svc_name       = xml.attributes["svc_name"]
    # @protocol       = xml.attributes["protocol"]
    # @severity       = xml.attributes["severity"]
    :cvss3_impact_score => 'cvssV3_impactScore',
    :plugin_id => 'pluginID',
    :plugin_name => 'pluginName',
    :plugin_family  => 'pluginFamily'
  }
  method_name = translations_table.fetch(method, method.to_s)
  return @xml.attributes[method_name].value if @xml.attributes.key?(method_name)

  # then we try the children tags: solution, risk_factor, description,
  #   plugin_publication_date, metasploit_name, cvss_vector,
  #   cvss_temporal_vector, synopsis, exploit_available,
  #   patch_publication_date, plugin_modification_date, cvss_temporal_score,
  #   cvss_base_score, plugin_output, plugin_version, exploitability_ease,
  #   vuln_publication_date, exploit_framework_canvas,
  #   exploit_framework_metasploit, exploit_framework_core
  tag = @xml.xpath("./#{method_name}").first
  if tag
    text = tag.text
    return tags_with_html_content.include?(method) ? cleanup_html(text) : text
  end

  # then the custom XML tags (cm: namespace)
  if method_name.starts_with?('cm_')
    method_name = method_name.sub(/cm_/, 'cm:compliance-').gsub(/_/, '-')
    cm_value = @xml.at_xpath("./#{method_name}", { 'cm' => 'http://www.nessus.org/cm' })
    if cm_value
      return cm_value.text
    else
      return nil
    end
  end

  # older versions of Nessus use <vpr_score> while newer versions of Nessus 
  #   use <vulnerability_priority_rating>. This allows either tag to be 
  #   pulled in to the vpr_score mapping
  if method_name == 'vpr_score'
    return @xml.at_xpath('./vulnerability_priority_rating | ./vpr_score')&.text
  end

  # finally the enumerations: bid_entries, cve_entries, xref_entries
  translations_table = {
    :bid_entries => 'bid',
    :cve_entries => 'cve',
    :cwe_entries => 'cwe',
    :see_also_entries => 'see_also',
    :xref_entries  => 'xref'
  }
  method_name = translations_table.fetch(method, nil)
  if method_name
    @xml.xpath("./#{method_name}").collect(&:text)
  else
    # nothing found, the tag is valid but not present in this ReportItem
    return nil
  end
end

Instance Method Details

#respond_to?(method, include_private = false) ⇒ Boolean

This allows external callers (and specs) to check for implemented properties

Returns:

  • (Boolean)


44
45
46
47
# File 'lib/nessus/report_item.rb', line 44

def respond_to?(method, include_private=false)
  return true if supported_tags.include?(method.to_sym)
  super
end

#supported_tagsObject

List of supported tags. They can be attributes, simple descendans or collections (e.g. <bid/>, <cve/>, <xref/>)



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/nessus/report_item.rb', line 19

def supported_tags
  [
    # attributes
    :plugin_family, :plugin_id, :plugin_name, :port, :protocol, :svc_name, :severity, 
    # simple tags
    :age_of_vuln, :cvss3_base_score, :cvss3_temporal_score, :cvss3_temporal_vector, 
    :cvss3_vector, :cvss_base_score, :cvss3_impact_score, :cvss_temporal_score, 
    :cvss_temporal_vector, :cvss_vector, :description, :exploit_available, 
    :exploit_code_maturity, :exploit_framework_canvas, :exploit_framework_core, 
    :exploitability_ease, :exploit_framework_metasploit,:metasploit_name, 
    :patch_publication_date, :plugin_modification_date, :plugin_output, 
    :plugin_publication_date, :plugin_type, :plugin_version, :product_coverage, 
    :risk_factor, :solution, :synopsis, :threat_intensity_last_28, :threat_recency, 
    :threat_sources_last_28, :vpr_score, :vuln_publication_date,
    # multiple tags
    :bid_entries, :cve_entries, :cwe_entries, :see_also_entries, :xref_entries,
    # compliance tags
    :cm_actual_value, :cm_audit_file, :cm_check_id, :cm_check_name, :cm_info,
    :cm_output, :cm_policy_value, :cm_reference, :cm_result, :cm_see_also,
    :cm_solution
  ]
end