risu 1.4.4 → 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/NEWS.markdown +14 -1
  2. data/README.markdown +23 -41
  3. data/TODO.markdown +48 -39
  4. data/lib/risu.rb +4 -9
  5. data/lib/risu/base.rb +15 -0
  6. data/lib/risu/base/prawn_templater.rb +37 -0
  7. data/lib/risu/{schema.rb → base/schema.rb} +34 -15
  8. data/lib/risu/base/template_base.rb +23 -0
  9. data/lib/risu/base/template_manager.rb +106 -0
  10. data/lib/risu/base/templater.rb +37 -0
  11. data/lib/risu/cli/application.rb +28 -8
  12. data/lib/risu/models.rb +1 -2
  13. data/lib/risu/models/host.rb +147 -23
  14. data/lib/risu/models/item.rb +131 -43
  15. data/lib/risu/models/plugin.rb +1 -1
  16. data/lib/risu/models/report.rb +11 -1
  17. data/lib/risu/models/serverpreference.rb +0 -2
  18. data/lib/risu/models/servicedescription.rb +10 -0
  19. data/lib/risu/parsers.rb +2 -3
  20. data/lib/risu/parsers/nessus/nessus_document.rb +69 -0
  21. data/lib/risu/parsers/nessus/nessus_sax_listener.rb +278 -0
  22. data/lib/risu/templates/assets.rb +45 -18
  23. data/lib/risu/templates/cover_sheet.rb +70 -42
  24. data/lib/risu/templates/exec_summary.rb +64 -45
  25. data/lib/risu/templates/executive_summary.rb +185 -161
  26. data/lib/risu/templates/finding_statistics.rb +44 -17
  27. data/lib/risu/templates/findings_host.rb +70 -46
  28. data/lib/risu/templates/findings_summary.rb +78 -54
  29. data/lib/risu/templates/findings_summary_with_pluginid.rb +80 -54
  30. data/lib/risu/templates/graphs.rb +46 -19
  31. data/lib/risu/templates/host_summary.rb +62 -39
  32. data/lib/risu/templates/ms_patch_summary.rb +59 -35
  33. data/lib/risu/templates/ms_update_summary.rb +59 -35
  34. data/lib/risu/templates/pci_compliance.rb +88 -64
  35. data/lib/risu/templates/technical_findings.rb +132 -106
  36. data/lib/risu/templates/template.rb +24 -0
  37. metadata +12 -6
  38. data/lib/risu/listener.rb +0 -274
  39. data/lib/risu/nessusdocument.rb +0 -66
  40. data/lib/risu/prawn_templater.rb +0 -38
@@ -2,14 +2,14 @@
2
2
 
3
3
  module Risu
4
4
  module Models
5
-
5
+
6
6
  # Item Model
7
7
  #
8
8
  # @author Jacob Hammack <jacob.hammack@hammackj.com>
9
9
  class Item < ActiveRecord::Base
10
10
  belongs_to :host
11
11
  belongs_to :plugin
12
-
12
+
13
13
  class << self
14
14
 
15
15
  # Queries for all risks in the database
@@ -18,98 +18,98 @@ module Risu
18
18
  def risks
19
19
  where(:severity => [0,1,2,3])
20
20
  end
21
-
21
+
22
22
  # Queries for all the high risks in the database
23
- #
23
+ #
24
24
  # @return [ActiveRecord::Relation] with the query results
25
25
  def high_risks
26
26
  where(:severity => 3)
27
27
  end
28
-
28
+
29
29
  # Queries for all the medium risks in the database
30
30
  #
31
- # @return [ActiveRecord::Relation] with the query results
31
+ # @return [ActiveRecord::Relation] with the query results
32
32
  def medium_risks
33
33
  where(:severity => 2)
34
34
  end
35
-
35
+
36
36
  # Queries for all the low risks in the database
37
37
  #
38
38
  # @return [ActiveRecord::Relation] with the query results
39
39
  def low_risks
40
40
  where(:severity => 1)
41
41
  end
42
-
42
+
43
43
  # Queries for all the info risks in the database
44
44
  #
45
45
  # @return [ActiveRecord::Relation] with the query results
46
46
  def info_risks
47
47
  where(:severity => 0)
48
48
  end
49
-
49
+
50
50
  # Queries for all the unique high risks in the database
51
51
  #
52
52
  # @return [ActiveRecord::Relation] with the query results
53
53
  def high_risks_unique
54
54
  where(:severity => 3).joins(:plugin).order("plugins.cvss_base_score").group(:plugin_id)
55
55
  end
56
-
56
+
57
57
  # Queries for all the unique high findings and sorts them by count
58
- #
58
+ #
59
59
  # @return [ActiveRecord::Relation] with the query results
60
60
  def high_risks_unique_sorted
61
61
  select("items.*").select("count(*) as count_all").where(:severity => 3).group(:plugin_id).order("count_all DESC")
62
62
  end
63
-
63
+
64
64
  # Queries for all the unique medium risks in the database
65
65
  #
66
66
  # @return [ActiveRecord::Relation] with the query results
67
67
  def medium_risks_unique
68
68
  where(:severity => 2).joins(:plugin).order(:cvss_base_score).group(:plugin_id)
69
69
  end
70
-
70
+
71
71
  # Queries for all the unique medium findings and sorts them by count
72
- #
72
+ #
73
73
  # @return [ActiveRecord::Relation] with the query results
74
74
  def medium_risks_unique_sorted
75
75
  select("items.*").select("count(*) as count_all").where(:severity => 2).group(:plugin_id).order("count_all DESC")
76
76
  end
77
-
77
+
78
78
  # Queries for all the unique low risks in the database
79
79
  #
80
80
  # @return [ActiveRecord::Relation] with the query results
81
81
  def low_risks_unique
82
82
  where(:severity => 1).joins(:plugin).order(:cvss_base_score).group(:plugin_id)
83
83
  end
84
-
84
+
85
85
  # Queries for all the unique low findings and sorts them by count
86
- #
86
+ #
87
87
  # @return [ActiveRecord::Relation] with the query results
88
88
  def low_risks_unique_sorted
89
89
  select("items.*").select("count(*) as count_all").where(:severity => 1).group(:plugin_id).order("count_all DESC")
90
90
  end
91
-
91
+
92
92
  # Queries for all the unique info risks in the database
93
93
  #
94
94
  # @return [ActiveRecord::Relation] with the query results
95
95
  def info_risks_unique
96
96
  where(:severity => 0).joins(:plugin).order(:cvss_base_score).group(:plugin_id)
97
97
  end
98
-
98
+
99
99
  # Queries for all the unique info findings and sorts them by count
100
- #
100
+ #
101
101
  # @return [ActiveRecord::Relation] with the query results
102
102
  def info_risks_unique_sorted
103
103
  select("items.*").select("count(*) as count_all").where(:severity => 0).group(:plugin_id).order("count_all DESC")
104
104
  end
105
-
105
+
106
106
  # Queries for all the risks grouped by service type, used for the Vulnerbilities by Service graph
107
107
  #
108
108
  # @return [ActiveRecord::Relation] with the query results
109
109
  def risks_by_service(limit=10)
110
110
  select("items.*").select("count(*) as count_all").where("svc_name != 'unknown' and svc_name != 'general'").group(:svc_name).order("count_all DESC").limit(limit)
111
111
  end
112
-
112
+
113
113
  # Queries for all the high risks by plugin
114
114
  #
115
115
  # @todo update this
@@ -118,64 +118,152 @@ module Risu
118
118
  def risks_by_plugin(limit=10)
119
119
  select("items.*").select("count(*) as count_all").joins(:plugin).where("plugin_id != 1").where(:severity => 3).group(:plugin_id).order("count_all DESC").limit(limit)
120
120
  end
121
-
121
+
122
122
  # Queries for all the risks by host
123
123
  #
124
124
  # @return [ActiveRecord::Relation] with the query results
125
125
  def risks_by_host(limit=10)
126
126
  select("items.*").select("count(*) as count_all").joins(:host).where("plugin_id != 1").where(:severity => [3, 2]).group(:host_id).order("count_all DESC").limit(limit)
127
127
  end
128
-
128
+
129
129
  # Queries for all the hosts with the Microsoft patch summary plugin (38153)
130
130
  #
131
131
  # @return [ActiveRecord::Relation] with the query results
132
132
  def ms_patches
133
133
  where(:plugin_id => 38153).joins(:host)
134
134
  end
135
-
135
+
136
136
  # Queries for all host with the Microsoft Update Summary plugin(12028)
137
137
  #
138
138
  # @return [ActiveRecord::Relation] with the query results
139
139
  def ms_update
140
140
  where(:plugin_id => 12028).joins(:host)
141
141
  end
142
-
142
+
143
143
  # Generates a Graph of all the risks by service
144
- #
144
+ #
145
145
  # @return [StringIO] Object containing the generated PNG image
146
146
  def risks_by_service_graph(limit=10)
147
147
  g = Gruff::Pie.new(GRAPH_WIDTH)
148
- g.title = sprintf "Top %d Findings By Service", Item.risks_by_service(limit).all.count
148
+ g.title = sprintf "Top %d Services By Vulnerability", Item.risks_by_service(limit).all.count
149
149
  g.sort = false
150
150
  g.theme = {
151
- :colors => %w(red green blue orange yellow purple black grey brown pink),
151
+ :colors => %w(red orange yellow blue green purple black grey brown pink),
152
152
  :background_colors => %w(white white)
153
153
  }
154
154
 
155
- Item.risks_by_service(limit).all.each { |service|
155
+ Item.risks_by_service(limit).all.each { |service|
156
156
  g.data(service.svc_name, Item.find(:all, :conditions => {:svc_name => service.svc_name}).count)
157
157
  }
158
158
 
159
159
  StringIO.new(g.to_blob)
160
160
  end
161
161
 
162
+ def risks_by_service_graph_text
163
+ "This graph is a representation of the findings found by service. This graph can help " +
164
+ "understand what services are running on the network and if they are vulnerable, where " +
165
+ "the risks are and how they should be protected."
166
+
167
+ end
168
+
169
+
162
170
  # Generates a Graph of all the risks by severity
163
171
  #
164
172
  # @return [StringIO] Object containing the generated PNG image
165
173
  def risks_by_severity_graph
166
- g = Gruff::Bar.new(GRAPH_WIDTH)
167
- g.title = "Findings By Severity"
168
- g.sort = false
169
- g.theme = {
170
- :background_colors => %w(white white)
171
- }
172
-
173
- g.data("High", Item.high_risks.count, "red") unless Item.high_risks.count == 0
174
- g.data("Medium", Item.medium_risks.count, "orange") unless Item.medium_risks.count == 0
175
- g.data("Low", Item.low_risks.count, "yellow") unless Item.low_risks.count == 0
176
- g.data("Info", Item.info_risks.count, "blue") unless Item.info_risks.count == 0
177
-
178
- StringIO.new(g.to_blob)
174
+ g = Gruff::Bar.new(GRAPH_WIDTH)
175
+ g.title = "Risks By Severity"
176
+ g.sort = false
177
+ g.theme = {
178
+ :colors => %w(red orange yellow blue green purple black grey brown pink),
179
+ :background_colors => %w(white white)
180
+ }
181
+
182
+ high = Item.high_risks.count
183
+ medium = Item.medium_risks.count
184
+ low = Item.low_risks.count
185
+ info = Item.info_risks.count
186
+
187
+ if high == nil then high = 0 end
188
+ if medium == nil then medium = 0 end
189
+ if low == nil then low = 0 end
190
+ if info == nil then info = 0 end
191
+
192
+ g.data("High", high, "red")
193
+ g.data("Medium", medium, "orange")
194
+ g.data("Low", low, "yellow")
195
+ g.data("Open Ports", info, "blue")
196
+
197
+ StringIO.new(g.to_blob)
198
+ end
199
+
200
+ # @todo change Report.title to a real variable
201
+ #
202
+ def risks_by_severity_graph_text
203
+ high = Item.high_risks.count
204
+ medium = Item.medium_risks.count
205
+
206
+ if high == nil then high = 0 end
207
+ if medium == nil then medium = 0 end
208
+
209
+ percentage = high
210
+
211
+ adjective = case percentage
212
+ when 0..5
213
+ "excellent"
214
+ when 6..10
215
+ "great"
216
+ when 11..20
217
+ "very good"
218
+ when 21..30
219
+ "good"
220
+ when 31..40
221
+ "fair"
222
+ else
223
+ "poor"
224
+ end
225
+
226
+ hosts_with_high = Hash.new
227
+
228
+ Item.high_risks.all.each do |item|
229
+ ip = Host.find_by_id(item.host_id).name
230
+ if hosts_with_high[ip] == nil
231
+ hosts_with_high[ip] = 1
232
+ end
233
+
234
+ hosts_with_high[ip] = hosts_with_high[ip] + 1
235
+ end
236
+
237
+ host_percent = (hosts_with_high.count.to_f / Host.all.count.to_f) * 100
238
+
239
+ percent_text = case host_percent
240
+ when 0..5
241
+ "This implies that only a handful of computers are missing patches, and the current patch management is working well."
242
+ when 6..20
243
+ "This implies that there is a minor patch management issue. If there is a patch management system, it should be checked for problems. " +
244
+ "Each host should also be inspected to be certain it can receive patches."
245
+ else
246
+ "This implies that there is a significant patch management problem on the network. Any patch management solutions should " +
247
+ "be inspected for issues and they should be correct as soon as possible. Each host should also be inspected to be certain it can receive patches."
248
+ end
249
+
250
+ graph_text = "This bar graph is a representation of the findings by severity; the " +
251
+ "graph shows that, overall, #{Report.title} has a #{adjective} handle on the patch " +
252
+ "management of the network.\n\n"
253
+
254
+ graph_text << "The majority of the high findings were found on #{host_percent.round}% of the total assessed computers. #{percent_text}\n\n"
255
+
256
+ graph_text << "The systems with high vulnerabilities represent the largest threat to the network, " +
257
+ "so patching this group is paramount to the overall network security. It only takes one high vulnerability " +
258
+ "to create a security incident.\n\n"
259
+
260
+ graph_text << "It should be noted that low findings and open ports represent the discovery "
261
+ graph_text << "of network services and open ports. Typically, these are not an indication of "
262
+ graph_text << "a serious problem and pose little to no threat. However, the correlation of "
263
+ graph_text << "data between the different severity levels could be used to determine degree "
264
+ graph_text << "of vulnerability for a given system.\n"
265
+
266
+ return graph_text
179
267
  end
180
268
  end
181
269
  end
@@ -64,7 +64,7 @@ module Risu
64
64
  g.title = sprintf "Top %d High Findings By Plugin", Item.risks_by_plugin(limit).all.count
65
65
  g.sort = false
66
66
  g.theme = {
67
- :colors => %w(red green blue orange yellow purple black grey brown pink),
67
+ :colors => %w(red orange yellow blue green purple black grey brown pink),
68
68
  :background_colors => %w(white white)
69
69
  }
70
70
 
@@ -18,7 +18,17 @@ module Risu
18
18
  #@scan_date = Host.where("start is not null").first[:start].to_s
19
19
  #
20
20
  def scan_date
21
- Host.where("start is not null").first[:start].to_s
21
+ Host.where("start is not null").first[:start]
22
+ end
23
+
24
+ #
25
+ # @todo comment this
26
+ #
27
+ def scanner_nessus_ratings_text
28
+ text = "The vulnerability scanner used by #{Report.company} rates the findings as follows: High, Medium, Low and Open Ports. High findings represents a security hole, initially this is the highest rating a risk can get. These generally represent vulnerabilities that can lead to full system compromise due to missing security patches. High findings should be the first to be remediated as they generally leave the network wide open. Medium findings are considered a security warning; these are not as severe as high but should be evaluated on a risk-by-risk basis. These are typically configuration errors that can lead to information disclosures such as usernames, passwords, and configuration settings. Low findings are identified as security notes; these provide information the scanner discovered during the scanning process. The information includes items such as hostname, domain name, and MAC address. Open Port findings represent the open ports on each system that the scanner found during the scan process. These should be evaluated against firewall settings to test the firewall configurations.\n\n"
29
+ text << "After the scanner is complete, the scanner evaluates each finding and bases it on the Common Vulnerability Scoring System (CVSS) score assigned to each finding. Any findings with a CVSS base score of 10 are upgraded to a Critical finding. These represent vulnerabilities that are trivial to gain administrator access to the system, with little to no effort. For more information on the CVSS scoring system please visit: http://nvd.nist.gov/cvss.cfm.\n\n"
30
+
31
+ return text
22
32
  end
23
33
  end
24
34
  end
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Risu
4
2
  module Models
5
3
 
@@ -0,0 +1,10 @@
1
+ module Risu
2
+ module Models
3
+
4
+ #
5
+ #
6
+ # @author Jacob Hammack
7
+ class ServiceDescription < ActiveRecord::Base
8
+ end
9
+ end
10
+ end
@@ -1,8 +1,7 @@
1
- # encoding: utf-8
2
-
3
1
  module Risu
4
2
  module Parsers
5
3
  end
6
4
  end
7
5
 
8
- #require 'risu/parsers/'
6
+ require 'risu/parsers/nessus/nessus_document'
7
+ require 'risu/parsers/nessus/nessus_sax_listener'
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ module Risu
4
+ module Parsers
5
+ module Nessus
6
+ # A Object to represet the Nessus xml file in memory
7
+ #
8
+ # @author Jacob Hammack <jacob.hammack@hammackj.com>
9
+ class NessusDocument
10
+
11
+ # Creates a instance of the NessusDocument class
12
+ #
13
+ def initialize document
14
+ @document = document
15
+ end
16
+
17
+ # Checks the validness of a NessusDocument
18
+ #
19
+ # @return [Boolean] True if valid, False if invalid
20
+ def valid?
21
+ if File.exist?(@document)
22
+ @parser = LibXML::XML::Parser.file @document
23
+ doc = @parser.parse
24
+
25
+ if doc.root.name == nil
26
+ return false
27
+ end
28
+
29
+ if doc.root.name == "NessusClientData_v2"
30
+ return true
31
+ elsif doc.root.name == "NessusClientData"
32
+ return false
33
+ else
34
+ return false
35
+ end
36
+ else
37
+ return false
38
+ end
39
+ end
40
+
41
+ # Invokes the SAX parser on the XML document
42
+ #
43
+ def parse
44
+ @parser = LibXML::XML::SaxParser.file @document
45
+ @parser.callbacks = NessusSaxListener.new
46
+ @parser.parse
47
+ end
48
+
49
+ # Fixes the ip field if nil and replaces it with the name if its an ip
50
+ #
51
+ def fix_ips
52
+ @hosts = Host.all
53
+
54
+ @hosts.each do |host|
55
+ if host.ip == nil
56
+ begin
57
+ ip = IPAddr.new host.name
58
+ host.ip = ip.to_string
59
+ host.save
60
+ rescue ArgumentError => ae
61
+ next
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,278 @@
1
+ # encoding: utf-8
2
+
3
+ require 'risu'
4
+
5
+ module Risu
6
+ module Parsers
7
+ module Nessus
8
+ # NessusSaxListener
9
+ #
10
+ #
11
+ # @author Jacob Hammack <jacob.hammack@hammackj.com>
12
+ class NessusSaxListener
13
+ include LibXML::XML::SaxParser::Callbacks
14
+
15
+ # Sets up a array of all valid xml fields
16
+ #
17
+ #
18
+ def initialize
19
+ @vals = Hash.new
20
+
21
+ @valid_elements = Array["see_also", "cve", "ReportItem", "xref", "bid", "plugin_version", "risk_factor",
22
+ "description", "cvss_base_score", "solution", "item", "plugin_output", "tag", "synopsis", "plugin_modification_date",
23
+ "FamilyName", "FamilyItem", "Status", "vuln_publication_date", "ReportHost", "HostProperties", "preferenceName",
24
+ "preferenceValues", "preferenceType", "fullName", "pluginId", "pluginName", "selectedValue", "selectedValue",
25
+ "name", "value", "preference", "plugin_publication_date", "cvss_vector", "patch_publication_date",
26
+ "NessusClientData_v2", "Policy", "PluginName", "ServerPreferences", "policyComments", "policyName", "PluginItem",
27
+ "Report", "Family", "Preferences", "PluginsPreferences", "FamilySelection", "IndividualPluginSelection", "PluginId",
28
+ "pci-dss-compliance", "exploitability_ease", "cvss_temporal_vector", "exploit_framework_core", "cvss_temporal_score",
29
+ "exploit_available", "metasploit_name", "exploit_framework_canvas", "canvas_package", "exploit_framework_metasploit",
30
+ "plugin_type", "cpe"]
31
+
32
+ # This makes adding new host properties really easy.
33
+ @valid_host_properties = {
34
+ "HOST_END" => :end ,
35
+ "mac-address" => :mac ,
36
+ "HOST_START" => :start ,
37
+ "operating-system" => :os,
38
+ "host-ip" => :ip ,
39
+ "host-fqdn" => :fqdn ,
40
+ "netbios-name" => :netbios ,
41
+ "local-checks-proto" => :local_checks_proto ,
42
+ "smb-login-used" => :smb_login_used ,
43
+ "ssh-auth-meth" => :ssh_auth_meth ,
44
+ "ssh-login-used" => :ssh_login_used ,
45
+ "pci-dss-compliance" => :pci_dss_compliance ,
46
+ "pci-dss-compliance:" => :pci_dss_compliance_ ,
47
+ "pcidss:compliance:failed" => :pcidss_compliance_failed,
48
+ "pcidss:compliance:passed" => :pcidss_compliance_passed,
49
+ "pcidss:deprecated_ssl" => :pcidss_deprecated_ssl,
50
+ "pcidss:expired_ssl_certificate" => :pcidss_expired_ssl_certificate,
51
+ "pcidss:high_risk_flaw" => :pcidss_high_risk_flaw,
52
+ "pcidss:medium_risk_flaw" => :pcidss_medium_risk_flaw,
53
+ "pcidss:reachable_db" => :pcidss_reachable_db,
54
+ "pcidss:www:xss" => :pcidss_www_xss,
55
+ "system-type" => :system_type
56
+ }
57
+
58
+ @valid_ms_patches = {
59
+ "MS11-030" => :ms11_030,
60
+ "MS11-026" => :ms11_026,
61
+ "MS11-034" => :ms11_034,
62
+ "MS11-021" => :ms11_021,
63
+ "MS11-029" => :ms11_029,
64
+ "MS11-023" => :ms11_023,
65
+ "MS11-022" => :ms11_022,
66
+ "MS09-027" => :ms09_027,
67
+ "MS11-033" => :ms11_033,
68
+ "MS11-019" => :ms11_019,
69
+ "MS11-024" => :ms11_024,
70
+ "MS11-031" => :ms11_031,
71
+ "MS11-020" => :ms11_020,
72
+ "MS11-018" => :ms11_018,
73
+ "MS11-028" => :ms11_028,
74
+ "MS11-032" => :ms11_032
75
+ }
76
+ end
77
+
78
+ # Callback for when the start of a xml element is reached
79
+ #
80
+ # @param element
81
+ # @param attributes
82
+ def on_start_element(element, attributes)
83
+ @tag = element
84
+ @vals[@tag] = ""
85
+
86
+ if !@valid_elements.include?(element)
87
+ puts "New XML element detected: #{element}. Please report this to #{Risu::EMAIL}"
88
+ end
89
+
90
+ case element
91
+ when "Policy"
92
+ @policy = Risu::Models::Policy.create
93
+ @policy.save
94
+ when "preference"
95
+ @sp = @policy.server_preferences.create
96
+ @sp.save
97
+ when "item"
98
+ @item = @policy.plugins_preferences.create
99
+ @item.save
100
+ when "FamilyItem"
101
+ @family = @policy.family_selections.create
102
+ @family.save
103
+ when "PluginItem"
104
+ @plugin_selection = @policy.individual_plugin_selections.create
105
+ @plugin_selection.save
106
+ when "Report"
107
+ @report = @policy.reports.create
108
+ @report.name = attributes["name"]
109
+ @report.save
110
+ when "ReportHost"
111
+ @rh = @report.hosts.create
112
+ @rh.name = attributes["name"]
113
+ @rh.save
114
+ when "tag"
115
+ unless attributes["name"] =~ /(MS\d\d-\d\d\d)/
116
+ @attr = if @valid_host_properties.keys.include?(attributes["name"])
117
+ attributes["name"]
118
+ else
119
+ nil
120
+ end
121
+ puts "New HostProperties attribute: #{attributes["name"]}. Please report this to jacob.hammack@hammackj.com\n" if @attr.nil?
122
+ end
123
+ when "ReportItem"
124
+ @vals = Hash.new # have to clear this out or everything has the same references
125
+ @ri = @rh.items.create
126
+ if attributes["pluginID"] == "0"
127
+ @plugin = Risu::Models::Plugin.find_or_create_by_id(1)
128
+ else
129
+ @plugin = Risu::Models::Plugin.find_or_create_by_id(attributes["pluginID"])
130
+ end
131
+
132
+ @ri.port = attributes["port"]
133
+ @ri.svc_name = attributes["svc_name"]
134
+ @ri.protocol = attributes["protocol"]
135
+ @ri.severity = attributes["severity"]
136
+
137
+ @ri.plugin_id = @plugin.id
138
+ @plugin.plugin_name = attributes["pluginName"]
139
+ @plugin.family_name = attributes["pluginFamily"]
140
+ @plugin.save
141
+ @ri.save
142
+ end
143
+ end
144
+
145
+ # Called when the inner text of a element is reached
146
+ #
147
+ # @param text
148
+ def on_characters(text)
149
+ if @vals[@tag] == nil then
150
+ @vals[@tag] = text
151
+ else
152
+ @vals[@tag] << text
153
+ end
154
+ end
155
+
156
+ # Called when the end of the xml element is reached
157
+ #
158
+ # @param element
159
+ def on_end_element(element)
160
+ @tag = nil
161
+ case element
162
+ when "policyName"
163
+ @policy.attributes = {
164
+ :name => @vals["policyName"]
165
+ }
166
+
167
+ @policy.save
168
+ when "policyComments"
169
+ @policy.attributes = {
170
+ :comments => @vals["policyComments"]
171
+ }
172
+
173
+ @policy.save
174
+ when "preference"
175
+ @sp.attributes = {
176
+ :name => @vals["name"],
177
+ :value => @vals["value"]
178
+ }
179
+ @sp.save
180
+
181
+ #This takes a really long time, there is about 34,000 pluginIDs in this
182
+ #field and it takes about 36 minutes to parse just this info =\
183
+ #lets prepopulate the plugins table with the known pluginid's
184
+ #if @vals["name"] == "plugin_set"
185
+ # @all_plugins = @vals["value"].split(";")
186
+ #
187
+ # @all_plugins.each { |p|
188
+ # @plug = Plugin.find_or_create_by_id(p)
189
+ # @plug.save
190
+ # }
191
+ #end
192
+ when "item"
193
+ @item.attributes = {
194
+ :plugin_name => @vals["pluginName"],
195
+ :plugin_id => @vals["pluginId"],
196
+ :fullname => @vals["fullName"],
197
+ :preference_name => @vals["preferenceName"],
198
+ :preference_type => @vals["preferenceType"],
199
+ :preference_values => @vals["preferenceValues"],
200
+ :selected_values => @vals["selectedValue"]
201
+ }
202
+
203
+ @item.save
204
+ when "FamilyItem"
205
+ @family.attributes = {
206
+ :family_name => @vals["FamilyName"],
207
+ :status => @vals["Status"]
208
+ }
209
+
210
+ @family.save
211
+ when "PluginItem"
212
+ @plugin_selection.attributes = {
213
+ :plugin_id => @vals["PluginId"],
214
+ :plugin_name => @vals["PluginName"],
215
+ :family => @vals["Family"],
216
+ :status => @vals["Status"]
217
+ }
218
+
219
+ @plugin_selection.save
220
+ when "tag"
221
+ @rh.attributes = {@valid_host_properties[@attr] => @vals["tag"].gsub("\n", ",") } if @valid_host_properties.keys.include?(@attr)
222
+ @rh.save
223
+ #We cannot handle the references in the same block as the rest of the ReportItem tag because
224
+ #there tends to be more than of the different types of reference per ReportItem, this causes issue for a sax
225
+ #parser. To solve this we do the references before the final plugin data
226
+ when "cve"
227
+ @cve = @plugin.references.create
228
+ @cve.reference_name = "cve"
229
+ @cve.value = @vals["cve"]
230
+ @cve.save
231
+ when "bid"
232
+ @bid = @plugin.references.create
233
+ @bid.reference_name = "bid"
234
+ @bid.value = @vals["bid"]
235
+ @bid.save
236
+ when "see_also"
237
+ @see_also = @plugin.references.create
238
+ @see_also.reference_name = "see_also"
239
+ @see_also.value = @vals["see_also"]
240
+ @see_also.save
241
+ when "xref"
242
+ @xref = @plugin.references.create
243
+ @xref.reference_name = "xref"
244
+ @xref.value = @vals["xref"]
245
+ @xref.save
246
+ when "ReportItem"
247
+ @ri.plugin_output = @vals["plugin_output"]
248
+ @ri.save
249
+
250
+ @plugin.attributes = {
251
+ :solution => @vals["solution"],
252
+ :risk_factor => @vals["risk_factor"],
253
+ :description => @vals["description"],
254
+ :plugin_publication_date => @vals["plugin_publication_date"],
255
+ :synopsis => @vals["synopsis"],
256
+ :plugin_type => @vals["plugin_type"],
257
+ :cvss_vector => @vals["cvss_vector"],
258
+ :cvss_base_score => @vals["cvss_base_score"],
259
+ :vuln_publication_date => @vals["vuln_publication_date"],
260
+ :plugin_version => @vals["plugin_version"],
261
+ :cvss_temporal_score => @vals["cvss_temporal_score"],
262
+ :cvss_temporal_vector => @vals["cvss_temporal_vector"],
263
+ :exploitability_ease => @vals["exploitability_ease"],
264
+ :exploit_framework_core => @vals["exploit_framework_core"],
265
+ :exploit_available => @vals["exploit_available"],
266
+ :exploit_framework_metasploit => @vals["exploit_framework_metasploit"],
267
+ :metasploit_name => @vals["metasploit_name"],
268
+ :exploit_framework_canvas => @vals["exploit_framework_canvas"],
269
+ :canvas_package => @vals["canvas_package"],
270
+ :cpe => @vals["cpe"]
271
+ }
272
+ @plugin.save
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end