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