risu 1.7.2 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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