risu 1.7.2 → 1.7.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0073dd7b2895f69ff1d3515c21c91ccc14ba437d
4
- data.tar.gz: 1eea60625dad86ec77f8d6966cd66e01f989cd3f
3
+ metadata.gz: 3976d26d2c92a443ccbc3a367a78f452e1bf959e
4
+ data.tar.gz: 0d8c53e2188555be31370de88051c3b033ab5e25
5
5
  SHA512:
6
- metadata.gz: 813332cd080c91dee71d85441a0977ff18b93febfb592286b70df0f38ea7b2b32fde77f6346bf92efc8c4e418726beaa0bd8621b80bc78874270fb4ea9af3fe9
7
- data.tar.gz: bed6c5350c538f1a0d378558c7c196f7a2d712d0bbe383dd0d4ea9ed9c9c81c3e62641506208545d3760bce0552cd0bb5c4541e5e8f1e65ffcae49ad5c25eace
6
+ metadata.gz: bdee561ba2e2d97d7c07cc211b469c51fabc303c7ceaa673fb92aaa8141d52fa53c9a6c28054002ba8a548d1d6e1e9787bb1c44ce49fc4bf5836ea6cb31fb05a
7
+ data.tar.gz: baed03ceb606c9034731555abe4857552a61e97453a5dbd15ed6b72cef40a3a33f1fd5e4c03aa61ddc23b8f604a3985e6c3f35c4cff0fed649e5d737be011cef
@@ -1,5 +1,15 @@
1
1
  # News
2
2
 
3
+ # 1.7.3 (January 8, 2015)
4
+ - Parser Optimizations by [@bluehavana]
5
+ - Renamed Attachment.type to Attachment.ttype, due to a rails naming issue
6
+ - Added SAX Parser tests for Attachments
7
+ - Rewrote the technical_findings template
8
+ - Template Helper
9
+ - Added title method
10
+ - Added definition method
11
+ - Fixed various bugs
12
+
3
13
  # 1.7.2 (January 5, 2015)
4
14
  - Updated Copyrights / etc
5
15
  - Added VMware ESXi Post Processing
@@ -26,7 +26,7 @@
26
26
 
27
27
  module Risu
28
28
  APP_NAME = "risu"
29
- VERSION = "1.7.2"
29
+ VERSION = "1.7.3"
30
30
  GRAPH_WIDTH = 750
31
31
  # red orange yellow green blue purple grey pink
32
32
  GRAPH_COLORS = %w(#d2403f #ec9241 #fcc343 #50ad51 #397bbb #8E6B8E black #cccccc brown #e52d89)
@@ -165,7 +165,7 @@ module Risu
165
165
  create_table :attachments do |t|
166
166
  t.integer :item_id
167
167
  t.string :name
168
- t.string :type
168
+ t.string :ttype
169
169
  t.string :ahash
170
170
  t.text :value
171
171
  end
@@ -144,7 +144,7 @@ module Risu
144
144
  heading1 "Poor Security Practice" if poor_count > 0
145
145
 
146
146
  #Anon ftp/smb + clear text
147
- @output.text anon_ftp_text + anon_smb_text + anonymous_access_text if anon_ftp_count > 1 || anon_smb_count > 1
147
+ @output.text anon_ftp_text + anon_smb_text + anonymous_access_text if anon_ftp_count > 0 || anon_smb_count > 0
148
148
  @output.text "\n"
149
149
  @output.text "\n"
150
150
  end
@@ -73,45 +73,52 @@ module Risu
73
73
  @output.text text, options
74
74
  end
75
75
 
76
- #
77
- def heading1 title
78
- @output.font_size(24) do
79
- @output.text title, :style => :bold
76
+ def title(text, size=18, color='#000000')
77
+ @output.font_size(size) do
78
+ @output.fill_color color.gsub('#', '')
79
+ @output.text text, :style => :bold
80
+ @output.fill_color "000000"
80
81
  end
82
+
83
+ @output.text "\n"
81
84
  end
82
85
 
83
- #
84
- def heading2 title
85
- @output.font_size(18) do
86
- @output.text title, :style => :bold
86
+ def definition term, text, options = {}
87
+ if text != nil
88
+ @output.text "\n#{term}", :style => :bold
89
+ @output.text text, options
87
90
  end
88
91
  end
89
92
 
90
93
  #
91
- def heading3 title
92
- @output.font_size(14) do
93
- @output.text title, :style => :bold
94
- end
94
+ def heading1 title_text
95
+ title title_text, 24
95
96
  end
96
97
 
97
98
  #
98
- def heading4 title
99
- @output.font_size(12) do
100
- @output.text title, :style => :bold
101
- end
99
+ def heading2 title_text
100
+ title title_text, 18
102
101
  end
103
102
 
104
103
  #
105
- def heading5 title
106
- @output.font_size(10) do
107
- @output.text title, :style => :bold
108
- end
104
+ def heading3 title_text
105
+ title title_text, 14
106
+ end
107
+
108
+ #
109
+ def heading4 title_text
110
+ title title_text, 12
111
+ end
112
+
113
+ #
114
+ def heading5 title_text
115
+ title title_text, 10
109
116
  end
110
117
 
111
118
  #
112
- def heading6 title
119
+ def heading6 title_text
113
120
  @output.font_size(8) do
114
- @output.text title, :style => :bold
121
+ @output.text title_text, :style => :bold
115
122
  end
116
123
  end
117
124
 
@@ -24,6 +24,8 @@
24
24
  # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25
25
  # OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
+ require 'set'
28
+
27
29
  ActiveRecord::Migration.verbose = false
28
30
 
29
31
  module Risu
@@ -34,64 +36,125 @@ module Risu
34
36
  class NessusSaxListener
35
37
  include LibXML::XML::SaxParser::Callbacks
36
38
 
37
- # Sets up a array of all valid XML fields
39
+ # An array of valid reference element names
40
+ VALID_REFERENCES = Set.new(%w[
41
+ cpe bid see_also xref cve iava msft
42
+ osvdb cert edb-id rhsa secunia suse dsa
43
+ owasp cwe iavb iavt cisco-sa ics-alert
44
+ cisco-bug-id cisco-sr cert-vu vmsa apple-sa
45
+ icsa cert-cc msvr usn hp glsa freebsd
46
+ ])
47
+
48
+ # An array of valid host properties
49
+ VALID_HOST_PROPERTIES = Set.new(%w[
50
+ HOST_END mac-address HOST_START operating-system host-ip host-fqdn netbios-name
51
+ local-checks-proto smb-login-used ssh-auth-meth ssh-login-used pci-dss-compliance
52
+ pci-dss-compliance: system-type bios-uuid pcidss:compliance:failed pcidss:compliance:passed
53
+ pcidss:deprecated_ssl pcidss:expired_ssl_certificate pcidss:high_risk_flaw pcidss:medium_risk_flaw
54
+ pcidss:reachable_db pcidss:www:xss pcidss:directory_browsing pcidss:known_credentials
55
+ pcidss:compromised_host:worm pcidss:obsolete_operating_system pcidss:dns_zone_transfer
56
+ pcidss:unprotected_mssql_db pcidss:obsolete_software pcidss:www:sql_injection pcidss:backup_files
57
+ traceroute-hop-0 traceroute-hop-1 traceroute-hop-2 operating-system-unsupported patch-summary-total-cves
58
+ pcidss:insecure_http_methods LastUnauthenticatedResults LastAuthenticatedResults cpe-0 cpe-1
59
+ cpe-2 cpe-3 Credentialed_Scan policy-used UnsupportedProduct:microsoft:windows_xp::sp2
60
+ UnsupportedProduct:microsoft:windows_xp UnsupportedProduct:microsoft:windows_2000 UnsupportedProduct
61
+ ])
62
+
63
+ # An array of all valid elements expected during parsing
64
+ VALID_ELEMENTS = VALID_REFERENCES \
65
+ + Set.new(%w[ReportItem plugin_version risk_factor
66
+ description cvss_base_score solution item plugin_output tag synopsis plugin_modification_date
67
+ FamilyName FamilyItem Status vuln_publication_date ReportHost HostProperties preferenceName
68
+ preferenceValues preferenceType fullName pluginId pluginName selectedValue selectedValue
69
+ name value preference plugin_publication_date cvss_vector patch_publication_date
70
+ NessusClientData_v2 Policy PluginName ServerPreferences policyComments policyName PluginItem
71
+ Report Family Preferences PluginsPreferences FamilySelection IndividualPluginSelection PluginId
72
+ pci-dss-compliance exploitability_ease cvss_temporal_vector exploit_framework_core cvss_temporal_score
73
+ exploit_available metasploit_name exploit_framework_canvas canvas_package exploit_framework_metasploit
74
+ plugin_type exploithub_sku exploit_framework_exploithub stig_severity plugin_name fname always_run
75
+ cm:compliance-info cm:compliance-actual-value cm:compliance-check-id cm:compliance-policy-value
76
+ cm:compliance-audit-file cm:compliance-check-name cm:compliance-result cm:compliance-output policyOwner
77
+ visibility script_version attachment policy_comments d2_elliot_name exploit_framework_d2_elliot
78
+ exploited_by_malware compliance
79
+ ])
80
+
81
+ # TODO: documentation. These are never used in the class
82
+ VALID_HOST_PROPERTIES_REGEX = [
83
+ "patch-summary-cve-num", "patch-summary-cves", "patch-summary-txt", "cpe-\d+", "KB\d+"
84
+ ]
85
+
86
+ # Map of host properties to symbols for use with ActiveRecord
87
+ # interfaces
88
+ #
89
+ # These are the more commonly used host properties,
90
+ # mapping them here to store in the host table
91
+ HOST_PROPERTIES_MAPPING = {
92
+ "HOST_END" => :end,
93
+ "mac-address" => :mac,
94
+ "HOST_START" => :start,
95
+ "operating-system" => :os,
96
+ "host-ip" => :ip,
97
+ "host-fqdn" => :fqdn,
98
+ "netbios-name" => :netbios
99
+ }
100
+
101
+ # Used to map element names to private methods so
102
+ # that the methods can be called when the parser
103
+ # encounters the opening of an element.
104
+ #
105
+ # {"ElementName" => :start_method_to_be_called}
106
+ #
107
+ # @example call #start_policy for a "Policy" element
108
+ # element = "Policy"
109
+ # send(DYNAMIC_START_METHOD_NAMES[element], element, attributes)
110
+ #
111
+ # @param element [String] the element name starting to be parsed
112
+ # @param attributes [Array<Hash{Sring=>String}>] the array of
113
+ # key value pairs for the element that is starting to be parsed
114
+ DYNAMIC_START_METHOD_NAMES = {
115
+ "Policy" => :start_policy,
116
+ "preference" => :start_preference,
117
+ "item" => :start_item,
118
+ "FamilyItem" => :start_family_item,
119
+ "PluginItem" => :start_plugin_item,
120
+ "Report" => :start_report,
121
+ "ReportHost" => :start_report_host,
122
+ "tag" => :start_tag,
123
+ "ReportItem" => :start_report_item,
124
+ "attachment" => :start_attachment
125
+ }
126
+
127
+ # @see DYNAMIC_START_MEHTOD_NAMES
128
+ #
129
+ # @note only one argument for the methods
130
+ #
131
+ # @example call #end_policy_name for a "policyName" element
132
+ # element = "policyName"
133
+ # send(DYNAMIC_END_METHOD_NAMES[element], element)
134
+ #
135
+ # @param element [String] the name of the element ending
136
+ DYNAMIC_END_METHOD_NAMES = {
137
+ "policyName" => :end_policy_name,
138
+ "policyComments" => :end_policy_comments,
139
+ "policy_comments" => :end_policy_comments,
140
+ "policyOwner" => :end_policy_owner,
141
+ "visibility" => :end_visibility,
142
+ "preference" => :end_preference,
143
+ "item" => :end_item,
144
+ "FamilyItem" => :end_family_item,
145
+ "PluginItem" => :end_plugin_item,
146
+ "tag" => :end_tag,
147
+ "ReportItem" => :end_report_item,
148
+ "attachment" => :end_attachment
149
+ }
150
+
151
+ private_constant :DYNAMIC_END_METHOD_NAMES, :DYNAMIC_START_METHOD_NAMES,
152
+ :HOST_PROPERTIES_MAPPING, :VALID_HOST_PROPERTIES_REGEX, :VALID_HOST_PROPERTIES,
153
+ :VALID_ELEMENTS, :VALID_REFERENCES
154
+
155
+ # vals tracks state for elements encountered during parsing
38
156
  def initialize
39
157
  @vals = Hash.new
40
-
41
- @valid_references = Array[
42
- "cpe", "bid", "see_also", "xref", "cve", "iava", "msft",
43
- "osvdb", "cert", "edb-id", "rhsa", "secunia", "suse", "dsa",
44
- "owasp", "cwe", "iavb", "iavt", "cisco-sa", "ics-alert",
45
- "cisco-bug-id", "cisco-sr", "cert-vu", "vmsa", "apple-sa",
46
- "icsa", "cert-cc", "msvr", "usn", "hp", "glsa", "freebsd"
47
- ]
48
-
49
- @valid_host_properties = Array[
50
- "HOST_END", "mac-address", "HOST_START", "operating-system", "host-ip", "host-fqdn", "netbios-name",
51
- "local-checks-proto", "smb-login-used", "ssh-auth-meth", "ssh-login-used", "pci-dss-compliance",
52
- "pci-dss-compliance:", "system-type", "bios-uuid", "pcidss:compliance:failed", "pcidss:compliance:passed",
53
- "pcidss:deprecated_ssl", "pcidss:expired_ssl_certificate", "pcidss:high_risk_flaw", "pcidss:medium_risk_flaw",
54
- "pcidss:reachable_db", "pcidss:www:xss", "pcidss:directory_browsing", "pcidss:known_credentials",
55
- "pcidss:compromised_host:worm", "pcidss:obsolete_operating_system", "pcidss:dns_zone_transfer",
56
- "pcidss:unprotected_mssql_db", "pcidss:obsolete_software", "pcidss:www:sql_injection", "pcidss:backup_files",
57
- "traceroute-hop-0", "traceroute-hop-1", "traceroute-hop-2", "operating-system-unsupported", "patch-summary-total-cves",
58
- "pcidss:insecure_http_methods", "LastUnauthenticatedResults", "LastAuthenticatedResults", "cpe-0", "cpe-1",
59
- "cpe-2", "cpe-3", "Credentialed_Scan", "policy-used", "UnsupportedProduct:microsoft:windows_xp::sp2",
60
- "UnsupportedProduct:microsoft:windows_xp", "UnsupportedProduct:microsoft:windows_2000", "UnsupportedProduct"
61
- ]
62
-
63
- @valid_host_properties_regex = Array[
64
- "patch-summary-cve-num", "patch-summary-cves", "patch-summary-txt", "cpe-\d+", "KB\d+"
65
- ]
66
-
67
- @valid_elements = Array["ReportItem", "plugin_version", "risk_factor",
68
- "description", "cvss_base_score", "solution", "item", "plugin_output", "tag", "synopsis", "plugin_modification_date",
69
- "FamilyName", "FamilyItem", "Status", "vuln_publication_date", "ReportHost", "HostProperties", "preferenceName",
70
- "preferenceValues", "preferenceType", "fullName", "pluginId", "pluginName", "selectedValue", "selectedValue",
71
- "name", "value", "preference", "plugin_publication_date", "cvss_vector", "patch_publication_date",
72
- "NessusClientData_v2", "Policy", "PluginName", "ServerPreferences", "policyComments", "policyName", "PluginItem",
73
- "Report", "Family", "Preferences", "PluginsPreferences", "FamilySelection", "IndividualPluginSelection", "PluginId",
74
- "pci-dss-compliance", "exploitability_ease", "cvss_temporal_vector", "exploit_framework_core", "cvss_temporal_score",
75
- "exploit_available", "metasploit_name", "exploit_framework_canvas", "canvas_package", "exploit_framework_metasploit",
76
- "plugin_type", "exploithub_sku", "exploit_framework_exploithub", "stig_severity", "plugin_name", "fname", "always_run",
77
- "cm:compliance-info", "cm:compliance-actual-value", "cm:compliance-check-id", "cm:compliance-policy-value",
78
- "cm:compliance-audit-file", "cm:compliance-check-name", "cm:compliance-result", "cm:compliance-output", "policyOwner",
79
- "visibility", "script_version", "attachment", "policy_comments", "d2_elliot_name", "exploit_framework_d2_elliot",
80
- "exploited_by_malware", "compliance"
81
- ]
82
-
83
- @valid_elements = @valid_elements + @valid_references
84
-
85
- # These are the more commonly used host properties, mapping them here to store in the host table
86
- @host_properties_mapping = {
87
- "HOST_END" => :end,
88
- "mac-address" => :mac,
89
- "HOST_START" => :start,
90
- "operating-system" => :os,
91
- "host-ip" => :ip,
92
- "host-fqdn" => :fqdn,
93
- "netbios-name" => :netbios
94
- }
95
158
  end
96
159
 
97
160
  # Callback for when the start of a XML element is reached
@@ -102,95 +165,14 @@ module Risu
102
165
  @tag = element
103
166
  @vals[@tag] = ""
104
167
 
105
- if !@valid_elements.include?(element)
168
+ if !VALID_ELEMENTS.include?(element)
106
169
  puts "New XML element detected: #{element}. Please report this at #{Risu::GITHUB}/issues/new or via email to #{Risu::EMAIL}"
107
170
  end
108
171
 
109
- case element
110
- when "Policy"
111
- @policy = Risu::Models::Policy.create
112
- @policy.save
113
- when "preference"
114
- @sp = @policy.server_preferences.create
115
- @sp.save
116
- when "item"
117
- @item = @policy.plugins_preferences.create
118
- @item.save
119
- when "FamilyItem"
120
- @family = @policy.family_selections.create
121
- @family.save
122
- when "PluginItem"
123
- @plugin_selection = @policy.individual_plugin_selections.create
124
- @plugin_selection.save
125
- when "Report"
126
- @report = @policy.reports.create
127
- @report.name = attributes["name"]
128
- @report.save
129
- when "ReportHost"
130
- @rh = @report.hosts.create
131
- @rh.name = attributes["name"]
132
- @rh.save
133
- when "tag"
134
- @attr = nil
135
- @hp = @rh.host_properties.create
136
-
137
- if attributes["name"] =~ /[M|m][S|s]\d{2,}-\d{2,}/
138
- @attr = if attributes["name"] =~ /[M|m][S|s]\d{2,}-\d{2,}/
139
- attributes["name"]
140
- else
141
- nil
142
- end
143
- #Ugly as fuck. Really this needs to be rewritten. Fuck.
144
- elsif attributes['name'] =~ /patch-summary-cve-num/ ||
145
- attributes['name'] =~ /patch-summary-cves/ ||
146
- attributes['name'] =~ /patch-summary-txt/ ||
147
- attributes['name'] =~ /cpe-\d+/ ||
148
- attributes['name'] =~ /KB\d+/
149
- @attr = if attributes["name"] =~ /patch-summary-cve-num/ ||
150
- attributes['name'] =~ /patch-summary-cves/ ||
151
- attributes['name'] =~ /patch-summary-txt/ ||
152
- attributes['name'] =~ /cpe-\d+/ ||
153
- attributes['name'] =~ /KB\d+/
154
- attributes["name"]
155
- else
156
- nil
157
- end
158
- else
159
- @attr = if @valid_host_properties.include?(attributes["name"])
160
- attributes["name"]
161
- else
162
- nil
163
- end
164
- end
165
-
166
- # implicit nil check?
167
- if attributes["name"] !~ /(netstat-(?:established|listen)-(?:tcp|udp)\d+-\d+)/ && attributes["name"] !~ /traceroute-hop-\d+/
168
- puts "New HostProperties attribute: #{attributes["name"]}. Please report this at #{Risu::GITHUB}/issues/new or via email to #{Risu::EMAIL}\n" if @attr.nil?
169
- end
170
- when "ReportItem"
171
- @vals = Hash.new # have to clear this out or everything has the same references
172
- @ri = @rh.items.create
173
- if attributes["pluginID"] == "0"
174
- @plugin = Risu::Models::Plugin.find_or_create_by(:id => 1)
175
- else
176
- @plugin = Risu::Models::Plugin.find_or_create_by(:id => attributes["pluginID"])
177
- end
178
-
179
- @ri.port = attributes["port"]
180
- @ri.svc_name = attributes["svc_name"]
181
- @ri.protocol = attributes["protocol"]
182
- @ri.severity = attributes["severity"]
183
-
184
- @ri.plugin_id = @plugin.id
185
- @plugin.plugin_name = attributes["pluginName"]
186
- @plugin.family_name = attributes["pluginFamily"]
187
- @plugin.save
188
- @ri.save
189
- when "attachment"
190
- @attachment = @ri.attachments.create
191
- @attachment.name = attributes['name']
192
- @attachment.type = attributes['type']
193
- @attachment.save
172
+ if DYNAMIC_START_METHOD_NAMES.key?(element)
173
+ # Dynamic dispatch to private instance "policyComments"methods in the const hash
174
+ # DYNAMIC_START_METHOD_NAMES where {"element" => :start_element}
175
+ send(DYNAMIC_START_METHOD_NAMES[element], element, attributes)
194
176
  end
195
177
  end
196
178
 
@@ -210,160 +192,221 @@ module Risu
210
192
  # @param element
211
193
  def on_end_element(element)
212
194
  @tag = nil
213
- case element
214
- when "policyName"
215
- @policy.attributes = {
216
- :name => @vals["policyName"]
217
- }
218
- @policy.save
219
-
220
- when "policyComments"
221
- @policy.attributes = {
222
- :comments => @vals["policyComments"]
223
- }
224
- @policy.save
225
-
226
- when "policy_comments"
227
- @policy.attributes = {
228
- :comments => @vals["policy_comments"]
229
- }
230
- @policy.save
231
-
232
- when "policyOwner"
233
- @policy.attributes = {
234
- :owner => @vals["policyOwner"]
235
- }
236
- @policy.save
237
-
238
- when "visibility"
239
- @policy.attributes = {
240
- :visibility => @vals["visibility"]
241
- }
242
- @policy.save
243
-
244
- when "preference"
245
- @sp.attributes = {
246
- :name => @vals["name"],
247
- :value => @vals["value"]
248
- }
249
- @sp.save
250
-
251
- #This takes a really long time, there is about 34,000 pluginIDs in this
252
- #field and it takes about 36 minutes to parse just this info =\
253
- #lets pre-populate the plugins table with the known plugin_id's
254
- #if @vals["name"] == "plugin_set"
255
- # @all_plugins = @vals["value"].split(";")
256
- #
257
- # @all_plugins.each { |p|
258
- # @plug = Plugin.find_or_create_by_id(p)
259
- # @plug.save
260
- # }
261
- #end
262
- when "item"
263
- @item.attributes = {
264
- :plugin_name => @vals["pluginName"],
265
- :plugin_id => @vals["pluginId"],
266
- :fullname => @vals["fullName"],
267
- :preference_name => @vals["preferenceName"],
268
- :preference_type => @vals["preferenceType"],
269
- :preference_values => @vals["preferenceValues"],
270
- :selected_values => @vals["selectedValue"]
271
- }
272
-
273
- @item.save
274
- when "FamilyItem"
275
- @family.attributes = {
276
- :family_name => @vals["FamilyName"],
277
- :status => @vals["Status"]
278
- }
279
-
280
- @family.save
281
- when "PluginItem"
282
- @plugin_selection.attributes = {
283
- :plugin_id => @vals["PluginId"],
284
- :plugin_name => @vals["PluginName"],
285
- :family => @vals["Family"],
286
- :status => @vals["Status"]
287
- }
288
-
289
- @plugin_selection.save
290
- when "tag"
291
- if @attr =~ /[M|m][S|s]\d{2}-\d{2,}/
292
- @patch = @rh.patches.create
293
- @patch.name = @attr
294
- @patch.value = @vals['tag']
295
- @patch.save
296
- else
297
- @rh.attributes = {@host_properties_mapping[@attr] => @vals["tag"].gsub("\n", ",") } if @host_properties_mapping.keys.include?(@attr)
298
- @rh.save
299
-
300
- @hp.name = @attr
301
- @hp.value = @vals['tag']
302
- @hp.save
303
-
304
- end if @attr != nil
305
- #We cannot handle the references in the same block as the rest of the ReportItem tag because
306
- #there tends to be more than of the different types of reference per ReportItem, this causes issue for a sax
307
- #parser. To solve this we do the references before the final plugin data, Valid references must be added
308
- #the @valid_reference array at the top to be parsed.
309
- # *@valid_reference, does a 'when' on each element of the @valid_references array, pure magic
310
- when *@valid_references
311
- @ref = @plugin.references.create
312
- @ref.reference_name = element
313
- @ref.value = @vals["#{element}"]
314
- @ref.save
315
- when "ReportItem"
316
- @ri.plugin_output = @vals["plugin_output"]
317
- @ri.plugin_name = @vals["plugin_name"]
318
- @ri.cm_compliance_info = @vals["cm:compliance-info"]
319
- @ri.cm_compliance_actual_value = @vals["cm:compliance-actual-value"]
320
- @ri.cm_compliance_check_id = @vals["cm:compliance-check-id"]
321
- @ri.cm_compliance_policy_value= @vals["cm:compliance-policy-value"]
322
- @ri.cm_compliance_audit_file = @vals["cm:compliance-audit-file"]
323
- @ri.cm_compliance_check_name = @vals["cm:compliance-check-name"]
324
- @ri.cm_compliance_result = @vals["cm:compliance-result"]
325
- @ri.cm_compliance_output = @vals["cm:compliance-output"]
326
-
327
- @ri.save
328
-
329
- @plugin.attributes = {
330
- :solution => @vals["solution"],
331
- :risk_factor => @vals["risk_factor"],
332
- :description => @vals["description"],
333
- :plugin_publication_date => @vals["plugin_publication_date"],
334
- :plugin_modification_date => @vals["plugin_modification_date"],
335
- :synopsis => @vals["synopsis"],
336
- :plugin_type => @vals["plugin_type"],
337
- :cvss_vector => @vals["cvss_vector"],
338
- :cvss_base_score => @vals["cvss_base_score"].to_f,
339
- :vuln_publication_date => @vals["vuln_publication_date"],
340
- :plugin_version => @vals["plugin_version"],
341
- :cvss_temporal_score => @vals["cvss_temporal_score"],
342
- :cvss_temporal_vector => @vals["cvss_temporal_vector"],
343
- :exploitability_ease => @vals["exploitability_ease"],
344
- :exploit_framework_core => @vals["exploit_framework_core"],
345
- :exploit_available => @vals["exploit_available"],
346
- :exploit_framework_metasploit => @vals["exploit_framework_metasploit"],
347
- :metasploit_name => @vals["metasploit_name"],
348
- :exploit_framework_canvas => @vals["exploit_framework_canvas"],
349
- :canvas_package => @vals["canvas_package"],
350
- :exploit_framework_exploithub => @vals["exploit_framework_exploithub"],
351
- :exploithub_sku => @vals["exploithub_sku"],
352
- :stig_severity => @vals["stig_severity"],
353
- :fname => @vals["fname"],
354
- :always_run => @vals["always_run"],
355
- :script_version => @vals["script_version"],
356
- :exploited_by_malware => @vals["exploited_by_malware"],
357
- :compliance => @vals["compliance"]
358
- }
359
- @plugin.save
360
- when "attachment"
361
- @attachment.attributes = {
362
- :ahash => @vals['attachment']
363
- }
364
- @attachment.save
195
+
196
+ if DYNAMIC_END_METHOD_NAMES.key?(element)
197
+ # Dynamic dispatch to private instance methods in the const hash
198
+ # DYNAMIC_END_METHOD_NAMES where {"element" => :end_element}
199
+ send(DYNAMIC_END_METHOD_NAMES[element], element)
200
+ elsif VALID_REFERENCES.include?(element)
201
+ end_valid_reference(element)
202
+ end
203
+ end
204
+
205
+ private
206
+
207
+ # Dynamic dispatch start element methods
208
+ def start_policy(_element, _attributes)
209
+ @policy = Risu::Models::Policy.create
210
+ end
211
+
212
+ def start_preference(_element, _attributes)
213
+ @sp = @policy.server_preferences.create
214
+ end
215
+
216
+ def start_item(_element, _attributes)
217
+ @item = @policy.plugins_preferences.create
218
+ end
219
+
220
+ def start_family_item(_element, _attributes)
221
+ @family = @policy.family_selections.create
222
+ end
223
+
224
+ def start_plugin_item(_element, _attributes)
225
+ @plugin_selection = @policy.individual_plugin_selections.create
226
+ end
227
+
228
+ def start_report(_element, attributes)
229
+ @report = @policy.reports.create(:name => attributes["name"])
230
+ end
231
+
232
+ def start_report_host(_element, attributes)
233
+ @rh = @report.hosts.create(:name => attributes["name"])
234
+ end
235
+
236
+ def start_tag(_, attributes)
237
+ @attr = nil
238
+ @hp = @rh.host_properties.create
239
+
240
+ if attributes["name"] =~ /[M|m][S|s]\d{2,}-\d{2,}/
241
+ @attr = attributes["name"]
242
+ #Ugly as fuck. Really this needs to be rewritten. Fuck.
243
+ elsif attributes['name'] =~ /
244
+ (?:patch-summary-cve-num)
245
+ | (?:patch-summary-cves)
246
+ | (?:patch-summary-txt)
247
+ | (?:cpe-\d+)
248
+ | (?:KB\d+)
249
+ /x
250
+ @attr = attributes["name"]
251
+ elsif VALID_HOST_PROPERTIES.include?(attributes["name"])
252
+ @attr = attributes["name"]
253
+ end
254
+
255
+ # implicit nil check?
256
+ if attributes["name"] !~ /(netstat-(?:established|listen)-(?:tcp|udp)\d+-\d+)/ \
257
+ && attributes["name"] !~ /traceroute-hop-\d+/ \
258
+ && @attr.nil?
259
+ puts "New HostProperties attribute: #{attributes["name"]}. Please report this at #{Risu::GITHUB}/issues/new or via email to #{Risu::EMAIL}\n"
365
260
  end
366
261
  end
262
+
263
+ def start_report_item(_element, attributes)
264
+ @vals = Hash.new # have to clear this out or everything has the same references
265
+
266
+ if attributes["pluginID"] == "0"
267
+ @plugin = Risu::Models::Plugin.find_or_create_by(:id => 1)
268
+ else
269
+ @plugin = Risu::Models::Plugin.find_or_create_by(:id => attributes["pluginID"]) do |plugin|
270
+ plugin.plugin_name = attributes["pluginName"]
271
+ plugin.family_name = attributes["pluginFamily"]
272
+ end
273
+ end
274
+
275
+ @ri = @rh.items.create(:port => attributes["port"],
276
+ :svc_name => attributes["svc_name"],
277
+ :protocol => attributes["protocol"],
278
+ :severity => attributes["severity"],
279
+ :plugin_id => @plugin.id)
280
+
281
+ @plugin.save
282
+ end
283
+
284
+ def start_attachment(_element, attributes)
285
+ @attachment = @ri.attachments.create(:name => attributes['name'], :ttype => attributes['type'])
286
+ end
287
+
288
+ # Dynamic dispatch end element methods
289
+ def end_policy_name(_)
290
+ @policy.update(:name => @vals["policyName"])
291
+ end
292
+
293
+ def end_policy_comments(element)
294
+ return unless element == "policyComments" || element == "policy_comments"
295
+ @policy.update(:comments => @vals[element])
296
+ end
297
+
298
+ def end_policy_owner(_)
299
+ @policy.update(:owner => @vals["policyOwner"])
300
+ end
301
+
302
+ def end_visibility(_)
303
+ @policy.update(:visibility => @vals["visibility"])
304
+ end
305
+
306
+ def end_preference(_)
307
+ @sp.update(:name => @vals["name"], :value => @vals["value"])
308
+ end
309
+
310
+ # This takes a really long time, there is about 34,000 pluginIDs in this
311
+ # field and it takes about 36 minutes to parse just this info =\
312
+ # lets pre-populate the plugins table with the known plugin_id's
313
+ #
314
+ # if @vals["name"] == "plugin_set"
315
+ # @all_plugins = @vals["value"].split(";")
316
+ #
317
+ # @all_plugins.each { |p|
318
+ # @plug = Plugin.find_or_create_by_id(p)
319
+ # @plug.save
320
+ # }
321
+ # end
322
+ def end_item(_)
323
+ @item.update(:plugin_name => @vals["pluginName"],
324
+ :plugin_id => @vals["pluginId"], :fullname => @vals["fullName"],
325
+ :preference_name => @vals["preferenceName"],
326
+ :preference_type => @vals["preferenceType"],
327
+ :preference_values => @vals["preferenceValues"],
328
+ :selected_values => @vals["selectedValue"])
329
+ end
330
+
331
+ def end_family_item(_)
332
+ @family.update( :family_name => @vals["FamilyName"],
333
+ :status => @vals["Status"])
334
+ end
335
+
336
+ def end_plugin_item(_)
337
+ @plugin_selection.update(:plugin_id => @vals["PluginId"],
338
+ :plugin_name => @vals["PluginName"],
339
+ :family => @vals["Family"], :status => @vals["Status"])
340
+ end
341
+
342
+ def end_tag(_)
343
+ return if @attr.nil?
344
+
345
+ if @attr =~ /[M|m][S|s]\d{2}-\d{2,}/
346
+ @patch = @rh.patches.create(:name => @attr, :value => @vals['tag'])
347
+ else
348
+ if HOST_PROPERTIES_MAPPING.key?(@attr)
349
+ @rh.update(HOST_PROPERTIES_MAPPING[@attr] => @vals["tag"].gsub("\n", ","))
350
+ end
351
+
352
+ @hp.update(:name => @attr, :value => @vals['tag'])
353
+ end
354
+ end
355
+
356
+ #We cannot handle the references in the same block as the rest of the ReportItem tag because
357
+ #there tends to be more than of the different types of reference per ReportItem, this causes issue for a sax
358
+ #parser. To solve this we do the references before the final plugin data, Valid references must be added
359
+ #the VALID_REFERENCE set at the top to be parsed.
360
+ def end_valid_reference(element)
361
+ @ref = @plugin.references.create(:reference_name => element,
362
+ :value => @vals["#{element}"])
363
+ end
364
+
365
+ def end_report_item(_)
366
+ @ri.update(:plugin_output => @vals["plugin_output"],
367
+ :plugin_name => @vals["plugin_name"],
368
+ :cm_compliance_info => @vals["cm:compliance-info"],
369
+ :cm_compliance_actual_value => @vals["cm:compliance-actual-value"],
370
+ :cm_compliance_check_id => @vals["cm:compliance-check-id"],
371
+ :cm_compliance_policy_value => @vals["cm:compliance-policy-value"],
372
+ :cm_compliance_audit_file => @vals["cm:compliance-audit-file"],
373
+ :cm_compliance_check_name => @vals["cm:compliance-check-name"],
374
+ :cm_compliance_result => @vals["cm:compliance-result"],
375
+ :cm_compliance_output => @vals["cm:compliance-output"])
376
+
377
+ @plugin.update(:solution => @vals["solution"],
378
+ :risk_factor => @vals["risk_factor"],
379
+ :description => @vals["description"],
380
+ :plugin_publication_date => @vals["plugin_publication_date"],
381
+ :plugin_modification_date => @vals["plugin_modification_date"],
382
+ :synopsis => @vals["synopsis"],
383
+ :plugin_type => @vals["plugin_type"],
384
+ :cvss_vector => @vals["cvss_vector"],
385
+ :cvss_base_score => @vals["cvss_base_score"].to_f,
386
+ :vuln_publication_date => @vals["vuln_publication_date"],
387
+ :plugin_version => @vals["plugin_version"],
388
+ :cvss_temporal_score => @vals["cvss_temporal_score"],
389
+ :cvss_temporal_vector => @vals["cvss_temporal_vector"],
390
+ :exploitability_ease => @vals["exploitability_ease"],
391
+ :exploit_framework_core => @vals["exploit_framework_core"],
392
+ :exploit_available => @vals["exploit_available"],
393
+ :exploit_framework_metasploit => @vals["exploit_framework_metasploit"],
394
+ :metasploit_name => @vals["metasploit_name"],
395
+ :exploit_framework_canvas => @vals["exploit_framework_canvas"],
396
+ :canvas_package => @vals["canvas_package"],
397
+ :exploit_framework_exploithub => @vals["exploit_framework_exploithub"],
398
+ :exploithub_sku => @vals["exploithub_sku"],
399
+ :stig_severity => @vals["stig_severity"],
400
+ :fname => @vals["fname"],
401
+ :always_run => @vals["always_run"],
402
+ :script_version => @vals["script_version"],
403
+ :exploited_by_malware => @vals["exploited_by_malware"],
404
+ :compliance => @vals["compliance"])
405
+ end
406
+
407
+ def end_attachment(_)
408
+ @attachment.update(:ahash => @vals['attachment'])
409
+ end
367
410
  end
368
411
  end
369
412
  end
@@ -34,12 +34,7 @@ module Risu
34
34
  class SimpleNexpose
35
35
  include LibXML::XML::SaxParser::Callbacks
36
36
 
37
- # @todo comment
38
- #
39
- def initialize
40
- @vals = Hash.new
41
-
42
- @valid_fingerprints = {
37
+ VALID_FINGERPRINTS = {
43
38
  "description" => :os,
44
39
  "vendor" => nil,
45
40
  "family" => nil,
@@ -49,6 +44,11 @@ module Risu
49
44
  "architecture" => nil
50
45
  }
51
46
 
47
+ # @todo comment
48
+ #
49
+ def initialize
50
+ @vals = Hash.new
51
+
52
52
  @report = Report.create
53
53
  end
54
54
 
@@ -93,7 +93,7 @@ module Risu
93
93
  @in_device = false
94
94
  when "description"
95
95
  if @in_device && @in_fingerprint
96
- @rh.attributes = { @valid_fingerprints[element] => @vals[element].gsub("\n", ",") } if @valid_fingerprints.keys.include?(element)
96
+ @rh.attributes = { VALID_FINGERPRINTS[element] => @vals[element].gsub("\n", ",") } if VALID_FINGERPRINTS.key?(element)
97
97
  @rh.save
98
98
  end
99
99
  when "fingerprint"
@@ -34,117 +34,75 @@ module Risu
34
34
  {
35
35
  :name => "technical_findings",
36
36
  :author => "hammackj",
37
- :version => "0.0.8",
37
+ :version => "0.0.9",
38
38
  :renderer => "PDF",
39
39
  :description => "Generates a Technical Findings Report"
40
40
  }
41
41
  end
42
42
 
43
- def render(output)
44
- text Report.classification.upcase, :align => :center
45
- text "\n"
43
+ def print_technical_findings(risks, text, color, last=false)
44
+ if risks.length > 0
45
+ title text, 18, color
46
46
 
47
- report_title Report.title
48
- report_subtitle "Critical and High Findings"
49
- report_author "This report was prepared by\n#{Report.author}"
50
-
51
- text "\n\n\n"
47
+ risks.each do |f|
48
+ hosts = Item.where(:plugin_id => f.plugin_id).group(:host_id)
49
+ plugin = Plugin.find_by_id(f.plugin_id)
52
50
 
53
- unique_risks = Array.new
54
- unique_risks << Hash[:title => "Critical Findings", :color => Risu::GRAPH_COLORS[0], :values => Item.critical_risks_unique] if Item.critical_risks_unique.to_a.size != 0
55
- unique_risks << Hash[:title => "High Findings", :color => Risu::GRAPH_COLORS[1], :values => Item.high_risks_unique] if Item.high_risks_unique.to_a.size != 0
51
+ references = Reference.where(:plugin_id => plugin.id).group(:value).order(:reference_name)
56
52
 
57
- # unique_risks << Hash[:title => "Medium Findings", :color => Risu::GRAPH_COLORS[2], :values => Item.medium_risks_unique_sorted] if Item.medium_risks_unique_sorted.to_a.size != 0
58
- # unique_risks << Hash[:title => "Low Findings", :color => Risu::GRAPH_COLORS[3], :values => Item.low_risks_unique_sorted] if Item.low_risks_unique_sorted.to_a.size != 0
53
+ output.font_size(16) do
54
+ text "#{plugin.plugin_name}\n"
55
+ end
59
56
 
60
- unique_risks.each_with_index do |h, index|
61
- if h[:values].length > 0
57
+ if hosts.length > 1
58
+ text "Hosts", :style => :bold
59
+ else
60
+ text "Host", :style => :bold
61
+ end
62
62
 
63
- output.font_size(18) do
64
- output.fill_color h[:color]
65
- text h[:title], :style => :bold
66
- output.fill_color "000000"
63
+ hostlist = Array.new
64
+ hosts.each do |host|
65
+ ho = Host.find_by_id(host.host_id)
66
+ host_string = "#{ho.name}"
67
+ host_string << " (#{ho.fqdn})" if ho.fqdn != nil
68
+ hostlist << host_string
67
69
  end
68
70
 
69
- text "\n"
71
+ text hostlist.join(', ')
70
72
 
71
- h[:values].each do |f|
72
-
73
- hosts = Item.where(:plugin_id => f.plugin_id).group(:host_id)
74
- plugin = Plugin.find_by_id(f.plugin_id)
75
-
76
- references = Reference.where(:plugin_id => plugin.id).group(:value).order(:reference_name)
77
-
78
- output.font_size(16) do
79
- text "#{plugin.plugin_name}\n"
80
- end
81
-
82
- if hosts.length > 1
83
- text "Hosts", :style => :bold
84
- else
85
- text "Host", :style => :bold
86
- end
87
-
88
- hostlist = Array.new
89
- hosts.each do |host|
90
- ho = Host.find_by_id(host.host_id)
91
- #if h.id != blacklist_host_id.first.id
92
- host_string = "#{ho.name}"
93
- host_string << " (#{ho.fqdn})" if ho.fqdn != nil
94
- hostlist << host_string
95
- #end
96
- end
97
-
98
- text hostlist.join(', ')
99
-
100
- if f.plugin_output != nil
101
- text "\nPlugin output", :style => :bold
102
- text f.plugin_output
103
- end
104
-
105
- if plugin.description != nil
106
- text "\nDescription", :style => :bold
107
- text plugin.description.gsub(/[ ]{2,}/, " "), :inline_format => true
108
- end
109
-
110
- if plugin.synopsis != nil
111
- text "\nSynopsis", :style => :bold
112
- text plugin.synopsis
113
- end
114
-
115
- if plugin.cvss_base_score != nil
116
- text "\nCVSS Base Score", :style => :bold
117
- text plugin.cvss_base_score
118
- end
119
-
120
- if plugin.exploit_available != nil
121
- text "\nExploit Available", :style => :bold
122
-
123
- if plugin.exploit_available == "true"
124
- text "Yes"
125
- else
126
- text "No"
127
- end
128
- end
129
-
130
- if plugin.solution != nil
131
- text "\nSolution", :style => :bold
132
- text plugin.solution
133
- end
134
-
135
- if references.size != 0
136
- text "\nReferences", :style => :bold
137
- text plugin.references.reference_string, :inline_format => true
138
- plugin_url = "http://www.tenablesecurity.com/plugins/index.php?view=single&id=#{plugin.id}"
139
- text "<b>nessus_plugin</b>: #{plugin_url}", :inline_format => true, :link => plugin_url
140
- end
141
-
142
- text "\n"
143
- end
73
+ definition "Plugin output", f.plugin_output
74
+ definition "Description", plugin.description.gsub(/[ ]{2,}/, " ") if plugin.description != nil
75
+ definition "Synopsis", plugin.synopsis
76
+ definition "CVSS Base Score", plugin.cvss_base_score
77
+ definition "Exploit Available", (plugin.exploit_available == "true") ? "Yes" : "No"
78
+ definition "Solution", plugin.solution
79
+ definition "References", plugin.references.reference_string, :inline_format => true
80
+
81
+ plugin_url = "http://www.tenablesecurity.com/plugins/index.php?view=single&id=#{plugin.id}"
82
+ definition "Nessus Plugin", plugin_url, :inline_format => true, :link => plugin_url
83
+
84
+ text "\n"
144
85
  end
145
86
 
146
- output.start_new_page if unique_risks[index+1] != nil
87
+ @output.start_new_page if last == false
147
88
  end
89
+ end
90
+
91
+ def render(output)
92
+ text Report.classification.upcase, :align => :center
93
+ text "\n"
94
+
95
+ report_title Report.title
96
+ report_subtitle "Technical Findings"
97
+ report_author "This report was prepared by\n#{Report.author}"
98
+ text "\n\n\n"
99
+
100
+ # If you uncomment the med/low change the true in high to false for a new page after it
101
+
102
+ print_technical_findings(Item.critical_risks_unique, "Critical Findings", Risu::GRAPH_COLORS[0]) if Item.critical_risks_unique.to_a.size != 0
103
+ print_technical_findings(Item.high_risks_unique, "High Findings", Risu::GRAPH_COLORS[1], true) if Item.high_risks_unique.to_a.size != 0
104
+ #print_technical_findings(Item.medium_risks_unique, "Medium Findings", Risu::GRAPH_COLORS[2]) if Item.medium_risks_unique.to_a.size != 0
105
+ #print_technical_findings(Item.low_risks_unique, "Low Findings", Risu::GRAPH_COLORS[3], true) if Item.low_risks_unique.to_a.size != 0
148
106
 
149
107
  output.number_pages "<page> of <total>", :at => [output.bounds.right - 75, 0], :width => 150, :page_filter => :all
150
108
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: risu
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: 1.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Hammack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-07 00:00:00.000000000 Z
11
+ date: 2015-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov