prenus 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,394 @@
1
+ require 'lib/gemcache/ruby-nessus/ruby-nessus/Version1/host'
2
+ require 'lib/gemcache/ruby-nessus/ruby-nessus/Version1/event'
3
+
4
+ module Nessus
5
+
6
+ # .Nessus Version 2 Schema
7
+ module Version1
8
+
9
+ # File to parse
10
+ attr_reader :file
11
+
12
+ class XML
13
+
14
+ include Enumerable
15
+
16
+ #
17
+ # Creates a new .Nessus (XML) object to be parser
18
+ #
19
+ # @param [String] file The Nessus xml results file to parse.
20
+ #
21
+ # @yield [prog] If a block is given, it will be passed the newly
22
+ # created XML object.
23
+ #
24
+ # @yieldparam [XML] prog The newly created XML object.
25
+ #
26
+ # @example
27
+ # Nessus::XML.new(nessus_scan_file) do |scan|
28
+ # scan.report_name
29
+ # end
30
+ #
31
+ def initialize(xml)
32
+ @xml = xml
33
+ raise "Error: Not A Version 1.0 .Nessus file." unless @xml.at('NessusClientData')
34
+ end
35
+
36
+ def version
37
+ 1
38
+ end
39
+
40
+ #
41
+ # Return the nessus report title.
42
+ #
43
+ # @return [String]
44
+ # The Nessus Report Title
45
+ #
46
+ # @example
47
+ # scan.report_name #=> "My Super Cool Nessus Report"
48
+ #
49
+ def title
50
+ @report_name ||= @xml.xpath("//NessusClientData//Report//ReportName").inner_text.split(' - ').last
51
+ end
52
+
53
+ #
54
+ # Return the nessus report time.
55
+ #
56
+ # @return [String]
57
+ # The Nessus Report Time
58
+ #
59
+ # @example
60
+ # scan.report_time #=> "09/11/08 02:21:22 AM"
61
+ #
62
+ def time
63
+ datetime = @xml.xpath("//NessusClientData//Report//ReportName").inner_text.split(' - ').first
64
+ @report_time ||= DateTime.strptime(datetime, fmt='%y/%m/%d %I:%M:%S %p')
65
+ end
66
+
67
+ #
68
+ # Return the scan start time.
69
+ #
70
+ # @return [DateTime]
71
+ # The Nessus Scan Start Time
72
+ #
73
+ # @example
74
+ # scan.start_time #=> 'Fri Nov 11 23:36:54 1985'
75
+ #
76
+ def start_time
77
+ @start_time = DateTime.strptime(@xml.xpath("//NessusClientData//Report//StartTime").inner_text, fmt='%a %b %d %H:%M:%S %Y')
78
+ end
79
+
80
+ #
81
+ # Return the scan stop time.
82
+ #
83
+ # @return [DateTime]
84
+ # The Nessus Scan Stop Time
85
+ #
86
+ # @example
87
+ # scan.stop_time #=> 'Mon Nov 11 23:36:54 1985'
88
+ #
89
+ def stop_time
90
+ @stop_time = DateTime.strptime(@xml.xpath("//NessusClientData//Report//StopTime").inner_text, fmt='%a %b %d %H:%M:%S %Y')
91
+ end
92
+
93
+ #
94
+ # Return the scan run time.
95
+ #
96
+ # @return [String]
97
+ # The Nessus Scan Run Time
98
+ #
99
+ # @example
100
+ # scan.runtime #=> '2 hours 5 minutes and 16 seconds'
101
+ #
102
+ def runtime
103
+ h = ("#{Time.parse(stop_time.to_s).strftime('%H').to_i - Time.parse(start_time.to_s).strftime('%H').to_i}").gsub('-', '')
104
+ m = ("#{Time.parse(stop_time.to_s).strftime('%M').to_i - Time.parse(start_time.to_s).strftime('%M').to_i}").gsub('-', '')
105
+ s = ("#{Time.parse(stop_time.to_s).strftime('%S').to_i - Time.parse(start_time.to_s).strftime('%S').to_i}").gsub('-', '')
106
+ return "#{h} hours #{m} minutes and #{s} seconds"
107
+ end
108
+
109
+ #
110
+ # Return the nessus scan policy name. When creating a nessus policy this is usually the title field.
111
+ #
112
+ # @return [String]
113
+ # The Nessus Scan Policy Name
114
+ #
115
+ def policy_title
116
+ @policy_name ||= @xml.xpath("//NessusClientData//Report//policyName").inner_text
117
+ end
118
+
119
+ #
120
+ # Return the nessus scan policy comments. This is the description field when creating a new policy with the Nessus GUI client.
121
+ #
122
+ # @return [String]
123
+ # The Nessus Scan Policy Comments
124
+ #
125
+ def policy_notes
126
+ @policy_comments ||= @xml.xpath("//NessusClientData//Report//policyComments").inner_text
127
+ end
128
+
129
+ #
130
+ # Returns and array of the plugin ids userd for the passed .nessus scan.
131
+ #
132
+ # @return [Array]
133
+ # The Nessus Scan Plugin Ids
134
+ #
135
+ # @example
136
+ # scan.plugin_ids #=> [1234,2343,9742,5452,5343,2423,1233]
137
+ #
138
+ def plugin_ids
139
+ unless @plugin_ids
140
+ @plugin_ids = []
141
+
142
+ @xml.xpath("//PluginSelection").last.text.split(';').each do |id|
143
+ @plugin_ids << id
144
+ end
145
+ end
146
+
147
+ @plugin_ids
148
+ end
149
+
150
+ #
151
+ # Returns and array of the plugin names userd for the passed .nessus scan.
152
+ #
153
+ # @return [Array]
154
+ # The Nessus Scan Plugin Names
155
+ #
156
+ # @example
157
+ # scan.plugins #=> ["PHP < 5.2.1 Multiple Vulnerabilities", "PHP < 4.4.1 / 5.0.6 Multiple Vulnerabilities"]
158
+ #
159
+ def plugins
160
+ unless @plugins
161
+ # get elements with attribute:
162
+ @plugins = []
163
+
164
+ @xml.xpath("//pluginName").each do |x|
165
+ @plugins << x.inner_text unless x.inner_text.empty?
166
+ end
167
+
168
+ @plugins.uniq!
169
+ @plugins.sort!
170
+ end
171
+
172
+ return @plugins
173
+ end
174
+
175
+ #
176
+ # Creates a new Host object to be parser
177
+ #
178
+ # @yield [prog] If a block is given, it will be passed the newly
179
+ # created Host object.
180
+ #
181
+ # @yieldparam [XML] prog The newly created Host object.
182
+ #
183
+ # @example
184
+ # scan.hosts do |host|
185
+ # puts host.hostname
186
+ # end
187
+ #
188
+ def each_host(&block)
189
+ hosts = []
190
+ @xml.xpath("//ReportHost").each do |host|
191
+ hosts << host.at('HostName').inner_text if host.at('HostName').inner_text
192
+ block.call(Host.new(host)) if block
193
+ end
194
+ hosts
195
+ end
196
+
197
+ #
198
+ # Parses the hosts of the scan.
199
+ #
200
+ # @return [Array<String>]
201
+ # The Hosts of the scan.
202
+ #
203
+ def hosts
204
+ Enumerator.new(self,:each_host).to_a
205
+ end
206
+
207
+ #
208
+ # Return the nessus scan host count.
209
+ #
210
+ # @return [Integer]
211
+ # The Nessus Scan Host Count
212
+ #
213
+ # @example
214
+ # scan.host_count #=> 23
215
+ #
216
+ def host_count
217
+ hosts.size
218
+ end
219
+
220
+ #
221
+ # Retunrs an array of all unique ports.
222
+ #
223
+ # @return [Array]
224
+ #
225
+ # @example
226
+ # scan.unique_ports #=> 234
227
+ #
228
+ def unique_ports
229
+ unless @unique_ports
230
+ @unique_ports = []
231
+ @xml.xpath("//ReportItem//port").each do |port|
232
+ @unique_ports << port.inner_text
233
+ end
234
+ @unique_ports.uniq!
235
+ @unique_ports.sort!
236
+ end
237
+ end
238
+
239
+ #
240
+ # Return the informational severity count.
241
+ #
242
+ # @return [Integer]
243
+ # The Informational Severity Count
244
+ #
245
+ # @example
246
+ # scan.informational_severity_count #=> 1203
247
+ #
248
+ def open_ports_count
249
+ count_severity[:open_ports].to_i
250
+ end
251
+
252
+ #
253
+ # Return the High severity count.
254
+ #
255
+ # @return [Integer]
256
+ # The High Severity Count
257
+ #
258
+ # @example
259
+ # scan.high_severity_count #=> 10
260
+ #
261
+ def high_severity_count
262
+ count_severity[:high].to_i
263
+ end
264
+
265
+ #
266
+ # Return the Medium severity count.
267
+ #
268
+ # @return [Integer]
269
+ # The Medium Severity Count
270
+ #
271
+ # @example
272
+ # scan.medium_severity_count #=> 234
273
+ #
274
+ def medium_severity_count
275
+ count_severity[:medium].to_i
276
+ end
277
+
278
+ #
279
+ # Return the Low severity count.
280
+ #
281
+ # @return [Integer]
282
+ # The Low Severity Count
283
+ #
284
+ # @example
285
+ # scan.low_severity_count #=> 114
286
+ #
287
+ def low_severity_count
288
+ count_severity[:low].to_i
289
+ end
290
+
291
+ #
292
+ # Return the Total severity count. [high, medium, low, informational]
293
+ #
294
+ # @return [Integer]
295
+ # The Total Severity Count
296
+ #
297
+ # @example
298
+ # scan.total_event_count #=> 1561
299
+ #
300
+ def total_event_count
301
+ count_severity[:all].to_i
302
+ end
303
+
304
+ #
305
+ # Return the Total severity count.
306
+ #
307
+ # @param [String] severity the severity in which to calculate percentage for.
308
+ #
309
+ # @param [Boolean] round round the result to the nearest whole number.
310
+ #
311
+ # @raise [ExceptionClass] One of the following severity options must be passed. [high, medium, low, informational, all]
312
+ #
313
+ # @return [Integer]
314
+ # The Percentage Of Events For A Passed Severity
315
+ #
316
+ # @example
317
+ # scan.event_percentage_for("low", true) #=> 11%
318
+ #
319
+ def event_percentage_for(type, round_percentage=false)
320
+ @sc ||= count_severity
321
+ if %W(high medium low all).include?(type)
322
+ calc = ((@sc[:"#{type}"].to_f / @sc[:all].to_f) * 100)
323
+ if round_percentage
324
+ return "#{calc.round}"
325
+ else
326
+ return "#{calc}"
327
+ end
328
+ else
329
+ raise "Error: #{type} is not an acceptable severity. Possible options include: all, high, medium, low and informational."
330
+ end
331
+ end
332
+
333
+ #
334
+ # Creates a new Host object to be parser from a passed search param.
335
+ #
336
+ # @param [String] hostname the hostname to build a Host object for.
337
+ #
338
+ # @yield [prog] If a block is given, it will be passed the newly
339
+ # created Host object.
340
+ #
341
+ # @yieldparam [XML] prog The newly created Host object.
342
+ #
343
+ # @example
344
+ # scan.find_by_hostname('127.0.0.1') do |host|
345
+ # puts host.hostname
346
+ # end
347
+ #
348
+ def find_by_hostname(hostname, &block)
349
+ raise "Error: hostname can't be blank." if hostname.blank?
350
+ @xml.xpath('//ReportHost[HostName]').each do |host|
351
+ next unless host.inner_text.match(hostname)
352
+ block.call(Host.new(host)) if block
353
+ end
354
+ end
355
+
356
+ private
357
+
358
+ #
359
+ # Calculates an event hash of totals for severity counts.
360
+ #
361
+ # @return [hash]
362
+ # The Event Totals For Severity
363
+ #
364
+ def count_severity
365
+ unless @count
366
+ @count = {}
367
+ @open_ports = 0
368
+ @low = 0
369
+ @medium = 0
370
+ @high = 0
371
+
372
+ @xml.xpath("//ReportHost").each do |s|
373
+ @open_ports += s.at('num_ports').inner_text.to_i
374
+ @low += s.at('num_lo').inner_text.to_i
375
+ @medium += s.at('num_med').inner_text.to_i
376
+ @high += s.at('num_hi').inner_text.to_i
377
+ end
378
+
379
+ @count = { :open_ports => @open_ports,
380
+ :low => @low,
381
+ :medium => @medium,
382
+ :high => @high,
383
+ :all => (@low + @medium + @high) }
384
+ end
385
+
386
+ return @count
387
+ end
388
+
389
+ end
390
+
391
+
392
+ end
393
+
394
+ end
@@ -0,0 +1,341 @@
1
+ require 'lib/gemcache/ruby-nessus/ruby-nessus/Version2/port'
2
+
3
+ module Nessus
4
+ module Version2
5
+
6
+ class Event
7
+
8
+ def initialize(event)
9
+ @event = event
10
+ end
11
+
12
+ #
13
+ # Return the event port.
14
+ #
15
+ # @return [Object]
16
+ # Return the event port object or port string.
17
+ #
18
+ # @example
19
+ # event.port #=> "https (443/tcp)"
20
+ # event.port.number #=> 443
21
+ # event.port.service #=> "https"
22
+ # event.port.protocol #=> "tcp"
23
+ #
24
+ def port
25
+ @port ||= Port.new(@event.at('@port'), @event.at('@svc_name'), @event.at('@protocol'))
26
+ end
27
+
28
+ #
29
+ # Return the event severity.
30
+ #
31
+ # @return [String]
32
+ # Return the event severity.
33
+ #
34
+ # @example
35
+ # event.severity #=> 3
36
+ # event.severity.in_words #=> "High Severity"
37
+ #
38
+ # @see String#in_words
39
+ #
40
+ def severity
41
+ @severity ||= @event.at('@severity').inner_text.to_i
42
+ end
43
+
44
+ #
45
+ # Return true if event is of informational severity.
46
+ #
47
+ # @return [Boolean]
48
+ # Return true if the event is informational.
49
+ #
50
+ def informational?
51
+ severity == 0
52
+ end
53
+
54
+ #
55
+ # Return ture if the event is of low severity.
56
+ #
57
+ # @return [Boolean]
58
+ # Return true if the event is low severity.
59
+ #
60
+ def low?
61
+ severity == 1
62
+ end
63
+
64
+ #
65
+ # Return ture if the event is of medium severity.
66
+ #
67
+ # @return [Boolean]
68
+ # Return true if the event is medium severity.
69
+ #
70
+ def medium?
71
+ severity == 2
72
+ end
73
+
74
+ #
75
+ # Return ture if the event is of high severity.
76
+ #
77
+ # @return [Boolean]
78
+ # Return true if the event is high severity.
79
+ #
80
+ def high?
81
+ severity == 3
82
+ end
83
+
84
+ #
85
+ # Return true if the event is of critical severity.
86
+ #
87
+ # @return [Boolean]
88
+ # Return true if the event is high severity.
89
+ #
90
+ def critical?
91
+ severity == 4
92
+ end
93
+
94
+ #
95
+ # Return the event object nessus plugin id
96
+ #
97
+ # @return [String]
98
+ # Return the event object nessus plugin id
99
+ #
100
+ # @example
101
+ # event.plugin_id #=> 3245
102
+ #
103
+ def id
104
+ @plugin_id ||= @event.at('@pluginID').inner_text.to_i
105
+ end
106
+ alias plugin_id id
107
+
108
+ #
109
+ # Return the event object plugin family name.
110
+ #
111
+ # @return [String]
112
+ # Return the event object plugin family name.
113
+ #
114
+ # @example
115
+ # event.family #=> "Service detection"
116
+ #
117
+ def family
118
+ @plugin_family ||= @event.at('@pluginFamily').inner_text
119
+ end
120
+ alias plugin_family family
121
+
122
+ #
123
+ # Return the event name (plugin_name)
124
+ #
125
+ # @return [String, false]
126
+ # Return the event name (plugin_name)
127
+ #
128
+ # @example
129
+ # event.plugin_name #=> "PHP < 5.2.4 Multiple Vulnerabilities"
130
+ # event.name #=> "PHP < 5.2.4 Multiple Vulnerabilities"
131
+ #
132
+ def plugin_name
133
+ s = @event.at('@pluginName').inner_text
134
+
135
+ @plugin_name ||= if s.empty?
136
+ false
137
+ else
138
+ @event.at('@pluginName').inner_text
139
+ end
140
+
141
+ return @plugin_name
142
+ end
143
+ alias name plugin_name
144
+
145
+ #
146
+ # Return the event synopsis.
147
+ #
148
+ # @return [String, false]
149
+ # Return the event synopsis.
150
+ #
151
+ def synopsis
152
+ @synopsis ||= if @event.at('synopsis')
153
+ @event.at('synopsis').inner_text
154
+ else
155
+ false
156
+ end
157
+ end
158
+
159
+ #
160
+ # Return the event description.
161
+ #
162
+ # @return [String, false]
163
+ # Return the event description.
164
+ #
165
+ def description
166
+ @description ||= if @event.at('description')
167
+ @event.at('description').inner_text
168
+ else
169
+ false
170
+ end
171
+ end
172
+
173
+ #
174
+ # Return the event solution.
175
+ #
176
+ # @return [String, false]
177
+ # Return the event solution.
178
+ #
179
+ def solution
180
+ @solution ||= if @event.at('solution')
181
+ @event.at('solution').inner_text
182
+ else
183
+ false
184
+ end
185
+ end
186
+
187
+ #
188
+ # Return the event risk.
189
+ #
190
+ # @return [String, false]
191
+ # Return the event risk.
192
+ #
193
+ def risk
194
+ @risk_factor ||= if @event.at('risk_factor')
195
+ @event.at('risk_factor').inner_text
196
+ else
197
+ false
198
+ end
199
+ end
200
+
201
+ #
202
+ # Return the event plugin output.
203
+ #
204
+ # @return [String, false]
205
+ # Return the event plugin output.
206
+ #
207
+ def output
208
+ @plugin_output ||= if @event.at('plugin_output')
209
+ @event.at('plugin_output').inner_text
210
+ else
211
+ false
212
+ end
213
+ end
214
+ alias data output
215
+ alias plugin_output output
216
+
217
+ #
218
+ # Return the event plugin version.
219
+ #
220
+ # @return [String, false]
221
+ # Return the event plugin version.
222
+ #
223
+ def version
224
+ @plugin_version ||= if @event.at('plugin_version')
225
+ @event.at('plugin_version').inner_text
226
+ else
227
+ false
228
+ end
229
+ end
230
+ alias plugin_version version
231
+
232
+ #
233
+ # Return the event reference links.
234
+ #
235
+ # @return [String, false]
236
+ # Return the event reference links.
237
+ #
238
+ def see_also
239
+ unless @see_also
240
+ @see_also = []
241
+ @event.xpath("see_also").each do |see_also|
242
+ @see_also << see_also.inner_text
243
+ end
244
+ end
245
+ @see_also
246
+ end
247
+ alias links see_also
248
+ alias more see_also
249
+ alias references see_also
250
+
251
+ #
252
+ # Return the event patch publication date.
253
+ #
254
+ # @return [String, false]
255
+ # Return the event patch publication date.
256
+ #
257
+ def patch_publication_date
258
+ @patch_publication_date ||= if @event.at('patch_publication_date')
259
+ DateTime.strptime(@event.at('patch_publication_date').inner_text, fmt='%Y/%m/%d')
260
+ else
261
+ false
262
+ end
263
+ end
264
+
265
+ #
266
+ # Return the event cvss base score.
267
+ #
268
+ # @return [String, false]
269
+ # Return the event cvss base score.
270
+ #
271
+ def cvss_base_score
272
+ @cvss_base_score ||= if @event.at('cvss_base_score')
273
+ @event.at('cvss_base_score').inner_text.to_f
274
+ else
275
+ false
276
+ end
277
+ end
278
+
279
+ #
280
+ # Return the event cve.
281
+ #
282
+ # @return [String, false]
283
+ # Return the event cvss base score.
284
+ #
285
+ def cve
286
+ @cve ||= if @event.at('cve')
287
+ @event.at('cve').inner_text
288
+ else
289
+ false
290
+ end
291
+ end
292
+
293
+ #
294
+ # Return the event bid.
295
+ #
296
+ # @return [String, false]
297
+ # Return the event bid.
298
+ #
299
+ def bid
300
+ @bid ||= if @event.at('bid')
301
+ @event.at('bid').inner_text.to_i
302
+ else
303
+ false
304
+ end
305
+ end
306
+
307
+ #
308
+ # Return other event related references.
309
+ #
310
+ # @return [String, false]
311
+ # Return the event related references.
312
+ #
313
+ def xref
314
+ unless @xref
315
+ @xref = []
316
+ @event.xpath("xref").each do |xref|
317
+ @xref << xref.inner_text
318
+ end
319
+ end
320
+ @xref
321
+ end
322
+
323
+ #
324
+ # Return other event cvss vector.
325
+ #
326
+ # @return [String, false]
327
+ # Return the event cvss vector.
328
+ #
329
+ def cvss_vector
330
+ @cvss_vector ||= if @event.at('cvss_vector')
331
+ @event.at('cvss_vector').inner_text
332
+ else
333
+ false
334
+ end
335
+ end
336
+
337
+ end
338
+
339
+ end
340
+
341
+ end