ruby-nessus 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,333 @@
1
+ require 'ruby-nessus/Version2/port'
2
+
3
+ module Nessus
4
+ module Version2
5
+
6
+ class Event
7
+ # Event
8
+ attr_reader :event
9
+
10
+ def initialize(event)
11
+ @event = event
12
+ end
13
+
14
+ #
15
+ # Return the event port.
16
+ #
17
+ # @return [Object]
18
+ # Return the event port object or port string.
19
+ #
20
+ # @example
21
+ # event.port #=> "https (443/tcp)"
22
+ # event.port.number #=> 443
23
+ # event.port.service #=> "https"
24
+ # event.port.protocol #=> "tcp"
25
+ #
26
+ def port
27
+ @port ||= Port.new(@event.at('@port'), @event.at('@svc_name'), @event.at('@protocol'))
28
+ end
29
+
30
+ #
31
+ # Return the event severity.
32
+ #
33
+ # @return [String]
34
+ # Return the event severity.
35
+ #
36
+ # @example
37
+ # event.severity #=> 3
38
+ # event.severity.in_words #=> "High Severity"
39
+ #
40
+ # @see String#in_words
41
+ #
42
+ def severity
43
+ @severity ||= @event.at('@severity').inner_text.to_i
44
+ end
45
+
46
+ #
47
+ # Return true if event is of informational severity.
48
+ #
49
+ # @return [Boolean]
50
+ # Return true if the event is informational.
51
+ #
52
+ def informational?
53
+ severity == 0
54
+ end
55
+
56
+ #
57
+ # Return ture if the event is of low severity.
58
+ #
59
+ # @return [Boolean]
60
+ # Return true if the event is low severity.
61
+ #
62
+ def low?
63
+ severity == 1
64
+ end
65
+
66
+ #
67
+ # Return ture if the event is of medium severity.
68
+ #
69
+ # @return [Boolean]
70
+ # Return true if the event is medium severity.
71
+ #
72
+ def medium?
73
+ severity == 2
74
+ end
75
+
76
+ #
77
+ # Return ture if the event is of high severity.
78
+ #
79
+ # @return [Boolean]
80
+ # Return true if the event is high severity.
81
+ #
82
+ def high?
83
+ severity == 3
84
+ end
85
+
86
+ #
87
+ # Return the event object nessus plugin id
88
+ #
89
+ # @return [String]
90
+ # Return the event object nessus plugin id
91
+ #
92
+ # @example
93
+ # event.plugin_id #=> 3245
94
+ #
95
+ def id
96
+ @plugin_id ||= @event.at('@pluginID').inner_text.to_i
97
+ end
98
+ alias plugin_id id
99
+
100
+ #
101
+ # Return the event object plugin family name.
102
+ #
103
+ # @return [String]
104
+ # Return the event object plugin family name.
105
+ #
106
+ # @example
107
+ # event.family #=> "Service detection"
108
+ #
109
+ def family
110
+ @plugin_family ||= @event.at('@pluginFamily').inner_text
111
+ end
112
+ alias plugin_family family
113
+
114
+ #
115
+ # Return the event name (plugin_name)
116
+ #
117
+ # @return [String, false]
118
+ # Return the event name (plugin_name)
119
+ #
120
+ # @example
121
+ # event.plugin_name #=> "PHP < 5.2.4 Multiple Vulnerabilities"
122
+ # event.name #=> "PHP < 5.2.4 Multiple Vulnerabilities"
123
+ #
124
+ def plugin_name
125
+ s = @event.at('@pluginName').inner_text
126
+
127
+ @plugin_name ||= if s.empty?
128
+ false
129
+ else
130
+ @event.at('@pluginName').inner_text
131
+ end
132
+
133
+ return @plugin_name
134
+ end
135
+ alias name plugin_name
136
+
137
+ #
138
+ # Return the event synopsis.
139
+ #
140
+ # @return [String, false]
141
+ # Return the event synopsis.
142
+ #
143
+ def synopsis
144
+ @synopsis ||= if @event.at('synopsis')
145
+ @event.at('synopsis').inner_text
146
+ else
147
+ false
148
+ end
149
+ end
150
+
151
+ #
152
+ # Return the event description.
153
+ #
154
+ # @return [String, false]
155
+ # Return the event description.
156
+ #
157
+ def description
158
+ @description ||= if @event.at('description')
159
+ @event.at('description').inner_text
160
+ else
161
+ false
162
+ end
163
+ end
164
+
165
+ #
166
+ # Return the event solution.
167
+ #
168
+ # @return [String, false]
169
+ # Return the event solution.
170
+ #
171
+ def solution
172
+ @solution ||= if @event.at('solution')
173
+ @event.at('solution').inner_text
174
+ else
175
+ false
176
+ end
177
+ end
178
+
179
+ #
180
+ # Return the event risk.
181
+ #
182
+ # @return [String, false]
183
+ # Return the event risk.
184
+ #
185
+ def risk
186
+ @risk_factor ||= if @event.at('risk_factor')
187
+ @event.at('risk_factor').inner_text
188
+ else
189
+ false
190
+ end
191
+ end
192
+
193
+ #
194
+ # Return the event plugin output.
195
+ #
196
+ # @return [String, false]
197
+ # Return the event plugin output.
198
+ #
199
+ def output
200
+ @plugin_output ||= if @event.at('plugin_output')
201
+ @event.at('plugin_output').inner_text
202
+ else
203
+ false
204
+ end
205
+ end
206
+ alias data output
207
+ alias plugin_output output
208
+
209
+ #
210
+ # Return the event plugin version.
211
+ #
212
+ # @return [String, false]
213
+ # Return the event plugin version.
214
+ #
215
+ def version
216
+ @plugin_version ||= if @event.at('plugin_version')
217
+ @event.at('plugin_version').inner_text
218
+ else
219
+ false
220
+ end
221
+ end
222
+ alias plugin_version version
223
+
224
+ #
225
+ # Return the event reference links.
226
+ #
227
+ # @return [String, false]
228
+ # Return the event reference links.
229
+ #
230
+ def see_also
231
+ unless @see_also
232
+ @see_also = []
233
+ @event.xpath("see_also").each do |see_also|
234
+ @see_also << see_also.inner_text
235
+ end
236
+ end
237
+ @see_also
238
+ end
239
+ alias links see_also
240
+ alias more see_also
241
+ alias references see_also
242
+
243
+ #
244
+ # Return the event patch publication date.
245
+ #
246
+ # @return [String, false]
247
+ # Return the event patch publication date.
248
+ #
249
+ def patch_publication_date
250
+ @patch_publication_date ||= if @event.at('patch_publication_date')
251
+ DateTime.strptime(@event.at('patch_publication_date').inner_text, fmt='%Y/%m/%d')
252
+ else
253
+ false
254
+ end
255
+ end
256
+
257
+ #
258
+ # Return the event cvss base score.
259
+ #
260
+ # @return [String, false]
261
+ # Return the event cvss base score.
262
+ #
263
+ def cvss_base_score
264
+ @cvss_base_score ||= if @event.at('cvss_base_score')
265
+ @event.at('cvss_base_score').inner_text.to_f
266
+ else
267
+ false
268
+ end
269
+ end
270
+
271
+ #
272
+ # Return the event cve.
273
+ #
274
+ # @return [String, false]
275
+ # Return the event cvss base score.
276
+ #
277
+ def cve
278
+ @cve ||= if @event.at('cve')
279
+ @event.at('cve').inner_text
280
+ else
281
+ false
282
+ end
283
+ end
284
+
285
+ #
286
+ # Return the event bid.
287
+ #
288
+ # @return [String, false]
289
+ # Return the event bid.
290
+ #
291
+ def bid
292
+ @bid ||= if @event.at('bid')
293
+ @event.at('bid').inner_text.to_i
294
+ else
295
+ false
296
+ end
297
+ end
298
+
299
+ #
300
+ # Return other event related references.
301
+ #
302
+ # @return [String, false]
303
+ # Return the event related references.
304
+ #
305
+ def xref
306
+ unless @xref
307
+ @xref = []
308
+ @event.xpath("xref").each do |xref|
309
+ @xref << xref.inner_text
310
+ end
311
+ end
312
+ @xref
313
+ end
314
+
315
+ #
316
+ # Return other event cvss vector.
317
+ #
318
+ # @return [String, false]
319
+ # Return the event cvss vector.
320
+ #
321
+ def cvss_vector
322
+ @cvss_vector ||= if @event.at('cvss_vector')
323
+ @event.at('cvss_vector').inner_text
324
+ else
325
+ false
326
+ end
327
+ end
328
+
329
+ end
330
+
331
+ end
332
+
333
+ end
@@ -0,0 +1,528 @@
1
+ module Nessus
2
+ module Version2
3
+
4
+ class Host
5
+ include Enumerable
6
+
7
+ # Host
8
+ attr_reader :host
9
+
10
+ #
11
+ # Creates A New Host Object
12
+ #
13
+ # @param [Object] Host Object
14
+ #
15
+ # @example
16
+ # Host.new(object)
17
+ #
18
+ def initialize(host)
19
+ @host = host
20
+ end
21
+
22
+ #
23
+ # Return the Host Object hostname.
24
+ #
25
+ # @return [String]
26
+ # The Host Object Hostname
27
+ #
28
+ # @example
29
+ # host.hostname #=> "example.com"
30
+ #
31
+ def hostname
32
+ @hostname ||= @host.at('tag[name=host-fqdn]').inner_text
33
+ end
34
+ alias name hostname
35
+ alias fqdn hostname
36
+ alias dns_name hostname
37
+
38
+ #
39
+ # Return the Host Object IP.
40
+ #
41
+ # @return [String]
42
+ # The Host Object IP
43
+ #
44
+ # @example
45
+ # host.ip #=> "127.0.0.1"
46
+ #
47
+ def ip
48
+ @ip ||= @host.at('tag[name=host-ip]').inner_text
49
+ end
50
+
51
+ #
52
+ # Return the host scan start time.
53
+ #
54
+ # @return [DateTime]
55
+ # The Host Scan Start Time
56
+ #
57
+ # @example
58
+ # scan.scan_start_time #=> 'Fri Nov 11 23:36:54 1985'
59
+ #
60
+ def start_time
61
+ if @host.at('tag[name=HOST_START]').inner_text.blank?
62
+ return false
63
+ else
64
+ @host_scan_start_time = DateTime.strptime(@host.at('tag[name=HOST_START]').inner_text, fmt='%a %b %d %H:%M:%S %Y')
65
+ end
66
+ end
67
+
68
+ #
69
+ # Return the host scan stop time.
70
+ #
71
+ # @return [DateTime]
72
+ # The Host Scan Stop Time
73
+ #
74
+ # @example
75
+ # scan.scan_start_time #=> 'Fri Nov 11 23:36:54 1985'
76
+ #
77
+ def stop_time
78
+ if @host.at('tag[name=HOST_END]').inner_text.blank?
79
+ return false
80
+ else
81
+ @host_scan_stop_time = DateTime.strptime(@host.at('tag[name=HOST_END]').inner_text, fmt='%a %b %d %H:%M:%S %Y')
82
+ end
83
+ end
84
+
85
+ #
86
+ # Return the host run time.
87
+ #
88
+ # @return [String]
89
+ # The Host Scan Run Time
90
+ #
91
+ # @example
92
+ # scan.scan_run_time #=> '2 hours 5 minutes and 16 seconds'
93
+ #
94
+ def runtime
95
+ h = ("#{Time.parse(stop_time.to_s).strftime('%H').to_i - Time.parse(start_time.to_s).strftime('%H').to_i}").gsub('-', '')
96
+ m = ("#{Time.parse(stop_time.to_s).strftime('%M').to_i - Time.parse(start_time.to_s).strftime('%M').to_i}").gsub('-', '')
97
+ s = ("#{Time.parse(stop_time.to_s).strftime('%S').to_i - Time.parse(start_time.to_s).strftime('%S').to_i}").gsub('-', '')
98
+ return "#{h} hours #{m} minutes and #{s} seconds"
99
+ end
100
+
101
+ #
102
+ # Return the Host Netbios Name.
103
+ #
104
+ # @return [String]
105
+ # The Host Netbios Name
106
+ #
107
+ # @example
108
+ # host.netbios_name #=> "SOMENAME4243"
109
+ #
110
+ def netbios_name
111
+ @netbios_name ||= @host.at('tag[name=netbios-name]').inner_text
112
+ end
113
+
114
+ #
115
+ # Return the Host Mac Address.
116
+ #
117
+ # @return [String]
118
+ # Return the Host Mac Address
119
+ #
120
+ # @example
121
+ # host.mac_addr #=> "00:11:22:33:44:55"
122
+ #
123
+ def mac_addr
124
+ @mac_addr ||= @host.at('tag[name=mac-addr]').inner_text
125
+ end
126
+ alias mac_address mac_addr
127
+
128
+ #
129
+ # Return the Host OS Name.
130
+ #
131
+ # @return [String]
132
+ # Return the Host OS Name
133
+ #
134
+ # @example
135
+ # host.dns_name #=> "Microsoft Windows 2000, Microsoft Windows Server 2003"
136
+ #
137
+ def os_name
138
+ @os_name ||= @host.at('tag[name=operating-system]').inner_text
139
+ end
140
+ alias os os_name
141
+ alias operating_system os_name
142
+
143
+ #
144
+ # Return the open ports for a given host object.
145
+ #
146
+ # @return [Integer]
147
+ # Return the open ports for a given host object.
148
+ #
149
+ # @example
150
+ # host.open_ports #=> 213
151
+ #
152
+ def open_ports
153
+ @scanned_ports ||= host_stats[:open_ports].to_i
154
+ end
155
+
156
+ #
157
+ # Returns All Informational Event Objects For A Given Host.
158
+ #
159
+ # @yield [prog] If a block is given, it will be passed the newly
160
+ # created Event object.
161
+ #
162
+ # @yieldparam [EVENT] prog The newly created Event object.
163
+ #
164
+ # @return [Integer]
165
+ # Return The Informational Event Count For A Given Host.
166
+ #
167
+ # @example
168
+ # host.informational_severity_events do |info|
169
+ # puts info.port
170
+ # puts info.data if info.data
171
+ # end
172
+ #
173
+ def informational_severity_events(&block)
174
+ unless @informational_events
175
+ @informational_events = []
176
+
177
+ @host.xpath("ReportItem").each do |event|
178
+ next if event['severity'].to_i != 0
179
+ @informational_events << Event.new(event)
180
+ end
181
+
182
+ end
183
+
184
+ @informational_events.each(&block)
185
+ end
186
+
187
+ #
188
+ # Returns All Low Event Objects For A Given Host.
189
+ #
190
+ # @yield [prog] If a block is given, it will be passed the newly
191
+ # created Event object.
192
+ #
193
+ # @yieldparam [EVENT] prog The newly created Event object.
194
+ #
195
+ # @return [Integer]
196
+ # Return The Low Event Count For A Given Host.
197
+ #
198
+ # @example
199
+ # host.low_severity_events do |low|
200
+ # puts low.name if low.name
201
+ # end
202
+ #
203
+ def low_severity_events(&block)
204
+
205
+ unless @low_severity_events
206
+ @low_severity_events = []
207
+
208
+ @host.xpath("ReportItem").each do |event|
209
+ next if event['severity'].to_i != 1
210
+ @low_severity_events << Event.new(event)
211
+ end
212
+
213
+ end
214
+
215
+ @low_severity_events.each(&block)
216
+ end
217
+
218
+ #
219
+ # Returns All Medium Event Objects For A Given Host.
220
+ #
221
+ # @yield [prog] If a block is given, it will be passed the newly
222
+ # created Event object.
223
+ # @yieldparam [EVENT] prog The newly created Event object.
224
+ #
225
+ # @return [Integer]
226
+ # Return The Medium Event Count For A Given Host.
227
+ #
228
+ # @example
229
+ # host.medium_severity_events do |medium|
230
+ # puts medium.name if medium.name
231
+ # end
232
+ #
233
+ def medium_severity_events(&block)
234
+
235
+ unless @medium_severity_events
236
+ @medium_severity_events = []
237
+
238
+ @host.xpath("ReportItem").each do |event|
239
+ next if event['severity'].to_i != 2
240
+ @medium_severity_events << Event.new(event)
241
+ end
242
+
243
+ end
244
+
245
+ @medium_severity_events.each(&block)
246
+ end
247
+
248
+ def medium_severity
249
+ Enumerator.new(self,:medium_severity_events).to_a
250
+ end
251
+
252
+ #
253
+ # Returns All High Event Objects For A Given Host.
254
+ #
255
+ # @yield [prog] If a block is given, it will be passed the newly
256
+ # created Event object.
257
+ #
258
+ # @yieldparam [EVENT] prog The newly created Event object.
259
+ #
260
+ # @return [Integer]
261
+ # Return The High Event Count For A Given Host.
262
+ #
263
+ # @example
264
+ # host.high_severity_events do |high|
265
+ # puts high.name if high.name
266
+ # end
267
+ #
268
+ def high_severity_events(&block)
269
+
270
+ unless @high_severity_events
271
+ @high_severity_events = []
272
+
273
+ @host.xpath("ReportItem").each do |event|
274
+ next if event['severity'].to_i != 3
275
+ @high_severity_events << Event.new(event)
276
+ end
277
+
278
+ end
279
+
280
+ @high_severity_events.each(&block)
281
+ end
282
+
283
+ #
284
+ # Return the total event count for a given host.
285
+ #
286
+ # @return [Integer]
287
+ # Return the total event count for a given host.
288
+ #
289
+ # @example
290
+ # host.event_count #=> 3456
291
+ #
292
+ def event_count
293
+ ((low_severity_events.to_i) + (medium_severity_events.to_i) + (high_severity_events.to_i)).to_i
294
+ end
295
+
296
+ #
297
+ # Creates a new Event object to be parser
298
+ #
299
+ # @yield [prog] If a block is given, it will be passed the newly
300
+ # created Event object.
301
+ # @yieldparam [EVENT] prog The newly created Event object.
302
+ #
303
+ # @example
304
+ # host.each_event do |event|
305
+ # puts event.name if event.name
306
+ # puts event.port
307
+ # end
308
+ #
309
+ def each_event(&block)
310
+ @host.xpath("ReportItem").each do |event|
311
+ block.call(Event.new(event)) if block
312
+ end
313
+ end
314
+
315
+ #
316
+ # Parses the events of the host.
317
+ #
318
+ # @return [Array<String>]
319
+ # The events of the host.
320
+ #
321
+ def events
322
+ Enumerator.new(self,:each_event).to_a
323
+ end
324
+
325
+ #
326
+ # Return the Open Ports count.
327
+ #
328
+ # @return [Array]
329
+ # The Open Ports Count
330
+ #
331
+ # @example
332
+ # scan.ports #=> ['22', '80', '443']
333
+ #
334
+ def ports
335
+ unless @ports
336
+ @ports = []
337
+ @host.xpath("ReportItem").each do |port|
338
+ @ports << port['port']
339
+ end
340
+ @ports.uniq!
341
+ @ports.sort!
342
+ end
343
+ @ports
344
+ end
345
+
346
+ #
347
+ # Return the TCP Event Count.
348
+ #
349
+ # @return [Integer]
350
+ # The TCP Event Count
351
+ #
352
+ # @example
353
+ # scan.tcp_count #=> 3
354
+ #
355
+ def tcp_count
356
+ host_stats[:tcp].to_i
357
+ end
358
+
359
+ #
360
+ # Return the UDP Event Count.
361
+ #
362
+ # @return [Integer]
363
+ # The UDP Event Count
364
+ #
365
+ # @example
366
+ # scan.udp_count #=> 3
367
+ #
368
+ def udp_count
369
+ host_stats[:udp].to_i
370
+ end
371
+
372
+ #
373
+ # Return the ICMP Event Count.
374
+ #
375
+ # @return [Integer]
376
+ # The ICMP Event Count
377
+ #
378
+ # @example
379
+ # scan.icmp_count #=> 3
380
+ #
381
+ def icmp_count
382
+ host_stats[:icmp].to_i
383
+ end
384
+
385
+ #
386
+ # Return the informational severity count.
387
+ #
388
+ # @return [Integer]
389
+ # The Informational Severity Count
390
+ #
391
+ # @example
392
+ # scan.informational_severity_count #=> 1203
393
+ #
394
+ def informational_severity_count
395
+ host_stats[:informational].to_i
396
+ end
397
+
398
+ #
399
+ # Return the High severity count.
400
+ #
401
+ # @return [Integer]
402
+ # The High Severity Count
403
+ #
404
+ # @example
405
+ # scan.high_severity_count #=> 10
406
+ #
407
+ def high_severity_count
408
+ host_stats[:high].to_i
409
+ end
410
+
411
+ #
412
+ # Return the Medium severity count.
413
+ #
414
+ # @return [Integer]
415
+ # The Medium Severity Count
416
+ #
417
+ # @example
418
+ # scan.medium_severity_count #=> 234
419
+ #
420
+ def medium_severity_count
421
+ host_stats[:medium].to_i
422
+ end
423
+
424
+ #
425
+ # Return the Low severity count.
426
+ #
427
+ # @return [Integer]
428
+ # The Low Severity Count
429
+ #
430
+ # @example
431
+ # scan.low_severity_count #=> 114
432
+ #
433
+ def low_severity_count
434
+ host_stats[:low].to_i
435
+ end
436
+
437
+ #
438
+ # Return the Total severity count. [high, medium, low, informational]
439
+ #
440
+ # @return [Integer]
441
+ # The Total Severity Count
442
+ #
443
+ # @example
444
+ # scan.total_event_count #=> 1561
445
+ #
446
+ def total_event_count(count_informational = false)
447
+ if count_informational
448
+ host_stats[:all].to_i + informational_severity_count
449
+ else
450
+ host_stats[:all].to_i
451
+ end
452
+ end
453
+
454
+ #
455
+ # Return the Total severity count.
456
+ #
457
+ # @param [String] severity the severity in which to calculate percentage for.
458
+ #
459
+ # @param [true, false] round round the result to the nearest whole number.
460
+ #
461
+ # @raise [ExceptionClass] One of the following severity options must be passed. [high, medium, low, informational, all]
462
+ #
463
+ # @return [Integer]
464
+ # The Percentage Of Events For A Passed Severity
465
+ #
466
+ # @example
467
+ # scan.event_percentage_for("low", true) #=> 11%
468
+ #
469
+ def event_percentage_for(type, round_percentage=false)
470
+ @sc ||= host_stats
471
+ if %W(high medium low tcp udp icmp all).include?(type)
472
+ calc = ((@sc[:"#{type}"].to_f / (@sc[:all].to_f)) * 100)
473
+ if round_percentage
474
+ return "#{calc.round}"
475
+ else
476
+ return "#{calc}"
477
+ end
478
+ else
479
+ raise "Error: #{type} is not an acceptable severity. Possible options include: all, tdp, udp, icmp, high, medium and low."
480
+ end
481
+ end
482
+
483
+ private
484
+
485
+ def host_stats
486
+
487
+ unless @host_stats
488
+ @host_stats = {}
489
+ @open_ports, @tcp, @udp, @icmp, @informational, @low, @medium, @high = 0,0,0,0,0,0,0,0
490
+
491
+ @host.xpath("ReportItem").each do |s|
492
+ case s['severity'].to_i
493
+ when 0
494
+ @informational += 1
495
+ when 1
496
+ @low += 1
497
+ when 2
498
+ @medium += 1
499
+ when 3
500
+ @high += 1
501
+ end
502
+
503
+ unless s['severity'].to_i == 0
504
+ @tcp += 1 if s['protocol'] == 'tcp'
505
+ @udp += 1 if s['protocol'] == 'udp'
506
+ @icmp += 1 if s['protocol'] == 'icmp'
507
+ end
508
+
509
+ @open_ports += 1 if s['port'].to_i != 0
510
+ end
511
+
512
+ @host_stats = {:open_ports => @open_ports,
513
+ :tcp => @tcp,
514
+ :udp => @udp,
515
+ :icmp => @icmp,
516
+ :informational => @informational,
517
+ :low => @low,
518
+ :medium => @medium,
519
+ :high => @high,
520
+ :all => (@low + @medium + @high)}
521
+
522
+ end
523
+ @host_stats
524
+ end
525
+
526
+ end
527
+ end
528
+ end