nexpose 0.0.98 → 0.1.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.
- data/README.markdown +17 -7
- data/Rakefile +17 -22
- data/lib/README.md +5 -0
- data/lib/nexpose.rb +104 -130
- data/lib/nexpose/api_request.rb +133 -144
- data/lib/nexpose/common.rb +138 -0
- data/lib/nexpose/connection.rb +117 -106
- data/lib/nexpose/creds.rb +292 -279
- data/lib/nexpose/error.rb +21 -21
- data/lib/nexpose/manage.rb +83 -0
- data/lib/nexpose/misc.rb +85 -122
- data/lib/nexpose/report.rb +783 -603
- data/lib/nexpose/role.rb +27 -0
- data/lib/nexpose/scan.rb +264 -285
- data/lib/nexpose/scan_engine.rb +344 -350
- data/lib/nexpose/silo.rb +348 -347
- data/lib/nexpose/site.rb +826 -898
- data/lib/nexpose/ticket.rb +108 -108
- data/lib/nexpose/user.rb +223 -221
- data/lib/nexpose/util.rb +36 -36
- data/lib/nexpose/vuln.rb +510 -520
- metadata +37 -23
- data/README +0 -0
- data/nexpose.gemspec +0 -20
data/lib/nexpose/util.rb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
|
-
module Nexpose
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
1
|
+
module Nexpose
|
2
|
+
module Sanitize
|
3
|
+
def replace_entities(str)
|
4
|
+
ret = str.dup
|
5
|
+
ret.gsub!(/&/, "&")
|
6
|
+
ret.gsub!(/'/, "'")
|
7
|
+
ret.gsub!(/"/, """)
|
8
|
+
ret.gsub!(/</, "<")
|
9
|
+
ret.gsub!(/>/, ">")
|
10
|
+
ret
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module XMLUtils
|
15
|
+
def parse_xml(xml)
|
16
|
+
::REXML::Document.new(xml.to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_xml(name, opts={}, data='', append_session_id=true)
|
20
|
+
xml = REXML::Element.new(name)
|
21
|
+
if (@session_id and append_session_id)
|
22
|
+
xml.attributes['session-id'] = @session_id
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.keys.each do |k|
|
26
|
+
if opts[k] != nil
|
27
|
+
xml.attributes[k] = "#{opts[k]}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
xml.text = data
|
32
|
+
|
33
|
+
xml
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/nexpose/vuln.rb
CHANGED
@@ -1,520 +1,510 @@
|
|
1
|
-
module Nexpose
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
xml << %Q{ typeMask="#{replace_entities(typeMask)}"}
|
512
|
-
xml << %Q{ maxAlerts="#{replace_entities(maxAlerts)}"}
|
513
|
-
xml << %Q{ severityThreshold="#{replace_entities(severityThreshold)}"}
|
514
|
-
xml << "/>"
|
515
|
-
|
516
|
-
xml
|
517
|
-
end
|
518
|
-
|
519
|
-
end
|
520
|
-
end
|
1
|
+
module Nexpose
|
2
|
+
module NexposeAPI
|
3
|
+
include XMLUtils
|
4
|
+
|
5
|
+
###################
|
6
|
+
# VULN EXCEPTIONS #
|
7
|
+
###################
|
8
|
+
|
9
|
+
#-----------------------------------------------------------------------
|
10
|
+
# Returns an array of vulnerability exceptions and their associated
|
11
|
+
# attributes.
|
12
|
+
#
|
13
|
+
# @param status - (optional) The status of the vulnerability exception:
|
14
|
+
# "Under Review", "Approved", "Rejected"
|
15
|
+
#-----------------------------------------------------------------------
|
16
|
+
def vuln_listing(status = nil)
|
17
|
+
option = {}
|
18
|
+
|
19
|
+
if status && !status.empty?
|
20
|
+
if status =~ /Under Review|Approved|Rejected/
|
21
|
+
option['status'] = status
|
22
|
+
else
|
23
|
+
raise ArgumentError.new 'The vulnerability status passed in is invalid!'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
xml = make_xml('VulnerabilityExceptionListingRequest', option)
|
28
|
+
r = execute xml, '1.2'
|
29
|
+
|
30
|
+
if r.success
|
31
|
+
res = []
|
32
|
+
r.res.elements.each("//VulnerabilityException") do |ve|
|
33
|
+
submitter_comment = ve.elements['submitter-comment']
|
34
|
+
reviewer_comment = ve.elements['reviewer-comment']
|
35
|
+
res << {
|
36
|
+
:vuln_id => ve.attributes['vuln-id'],
|
37
|
+
:exception_id => ve.attributes['exception-id'],
|
38
|
+
:submitter => ve.attributes['submitter'],
|
39
|
+
:reviewer => ve.attributes['reviewer'],
|
40
|
+
:status => ve.attributes['status'],
|
41
|
+
:reason => ve.attributes['reason'],
|
42
|
+
:scope => ve.attributes['scope'],
|
43
|
+
:device_id => ve.attributes['device-id'],
|
44
|
+
:port_no => ve.attributes['port-no'],
|
45
|
+
:expiration_date => ve.attributes['expiration-date'],
|
46
|
+
:vuln_key => ve.attributes['vuln-key'],
|
47
|
+
:submitter_comment => submitter_comment.nil? ? '' : submitter_comment.text,
|
48
|
+
:reviewer_comment => reviewer_comment.nil? ? '' : reviewer_comment.text
|
49
|
+
}
|
50
|
+
end
|
51
|
+
res
|
52
|
+
else
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#-------------------------------------------------------------------------------------------------------------------
|
58
|
+
# Creates a vulnerability exception.
|
59
|
+
#
|
60
|
+
# @param input - data used to create the vulnerability exception:
|
61
|
+
# :vuln_id - The Nexpose vulnerability ID.
|
62
|
+
# :reason - The reason for the exception
|
63
|
+
# values - "False Positive", "Compensating Control", "Acceptable Use", "Acceptable Risk", "Other"
|
64
|
+
# :scope - The scope type (NOTE: The case is important)
|
65
|
+
# values - "All Instances", "All Instances on a Specific Asset", "Specific Instance of a specific Asset"
|
66
|
+
# :comment - A user comment
|
67
|
+
# :device-id - Used for specific instances related to "All Instances on a Specific Asset" AND "Specific Instance of Specific Asset"
|
68
|
+
# :port - All assets on this port related to "Specific Instance of a specific Asset"
|
69
|
+
# :vuln-key - The vulnerability key related to the "Specific Instance of a specific Asset"
|
70
|
+
#
|
71
|
+
# @returns exception-id - The Id associated with this create request
|
72
|
+
#-------------------------------------------------------------------------------------------------------------------
|
73
|
+
def vuln_exception_create(input)
|
74
|
+
options = {}
|
75
|
+
|
76
|
+
if input.nil?
|
77
|
+
raise ArgumentError.new 'The input element cannot be null'
|
78
|
+
end
|
79
|
+
|
80
|
+
vuln_id = input[:vuln_id]
|
81
|
+
unless vuln_id
|
82
|
+
raise ArgumentError.new 'The vulnerability ID is required'
|
83
|
+
end
|
84
|
+
options['vuln-id'] = vuln_id
|
85
|
+
|
86
|
+
reason = input[:reason]
|
87
|
+
if reason.nil? || reason.empty?
|
88
|
+
raise ArgumentError.new 'The reason is required'
|
89
|
+
end
|
90
|
+
|
91
|
+
unless reason =~ /False Positive|Compensating Control|Acceptable Use|Acceptable Risk|Other/
|
92
|
+
raise ArgumentError.new 'The reason type is invalid'
|
93
|
+
end
|
94
|
+
options['reason'] = reason
|
95
|
+
|
96
|
+
scope = input[:scope]
|
97
|
+
if scope.nil? || scope.empty?
|
98
|
+
raise ArgumentError.new 'The scope is required'
|
99
|
+
end
|
100
|
+
|
101
|
+
# For scope case matters.
|
102
|
+
unless scope =~ /All Instances|All Instances on a Specific Asset|Specific Instance of Specific Asset/
|
103
|
+
raise ArgumentError.new 'The scope type is invalid'
|
104
|
+
end
|
105
|
+
|
106
|
+
if scope =~ /All Instances on a Specific Asset|Specific Instance of Specific Asset/
|
107
|
+
device_id = input[:device_id]
|
108
|
+
vuln_key = input[:vuln_key]
|
109
|
+
port = input[:port]
|
110
|
+
if device_id
|
111
|
+
options['device-id'] = device_id
|
112
|
+
end
|
113
|
+
|
114
|
+
if scope =~ /All Instances on a Specific Asset/ && (vuln_key || port)
|
115
|
+
raise ArgumentError.new "Vulnerability key or port cannot be used with the scope specified"
|
116
|
+
end
|
117
|
+
|
118
|
+
if vuln_key
|
119
|
+
options['vuln-key'] = vuln_key
|
120
|
+
end
|
121
|
+
|
122
|
+
if port
|
123
|
+
options['port-no'] = port
|
124
|
+
end
|
125
|
+
end
|
126
|
+
options['scope'] = scope
|
127
|
+
|
128
|
+
xml = make_xml('VulnerabilityExceptionCreateRequest', options)
|
129
|
+
|
130
|
+
comment = input[:comment]
|
131
|
+
if comment && !comment.empty?
|
132
|
+
comment_xml = make_xml('comment', {}, comment, false)
|
133
|
+
xml.add_element comment_xml
|
134
|
+
else
|
135
|
+
raise ArgumentError.new 'The comment cannot be empty'
|
136
|
+
end
|
137
|
+
|
138
|
+
r = execute xml, '1.2'
|
139
|
+
if r.success
|
140
|
+
r.res.elements.each("//VulnerabilityExceptionCreateResponse") do |vecr|
|
141
|
+
return vecr.attributes['exception-id']
|
142
|
+
end
|
143
|
+
else
|
144
|
+
false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
#-------------------------------------------------------------------------------------------------------------------
|
149
|
+
# Resubmit a vulnerability exception.
|
150
|
+
#
|
151
|
+
# @param input - data used to create the vulnerability exception:
|
152
|
+
# :vuln_id - The Nexpose vulnerability ID. (required)
|
153
|
+
# :reason - The reason for the exception (optional)
|
154
|
+
# values - "False Positive", "Compensating Control", "Acceptable Use", "Acceptable Risk", "Other"
|
155
|
+
# :comment - A user comment (required)
|
156
|
+
#-------------------------------------------------------------------------------------------------------------------
|
157
|
+
def vuln_exception_resubmit(input)
|
158
|
+
options = {}
|
159
|
+
|
160
|
+
if input.nil?
|
161
|
+
raise ArgumentError.new 'The input element cannot be null'
|
162
|
+
end
|
163
|
+
|
164
|
+
exception_id = input[:exception_id]
|
165
|
+
unless exception_id
|
166
|
+
raise ArgumentError.new 'The exception ID is required'
|
167
|
+
end
|
168
|
+
options['exception-id'] = exception_id
|
169
|
+
|
170
|
+
reason = input[:reason]
|
171
|
+
if !reason.nil? && !reason.empty?
|
172
|
+
unless reason =~ /False Positive|Compensating Control|Acceptable Use|Acceptable Risk|Other/
|
173
|
+
raise ArgumentError.new 'The reason type is invalid'
|
174
|
+
end
|
175
|
+
options['reason'] = reason
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
|
180
|
+
|
181
|
+
comment = input[:comment]
|
182
|
+
if comment && !comment.empty?
|
183
|
+
comment_xml = make_xml('comment', {}, comment, false)
|
184
|
+
xml.add_element comment_xml
|
185
|
+
end
|
186
|
+
|
187
|
+
r = execute xml, '1.2'
|
188
|
+
r.success
|
189
|
+
end
|
190
|
+
|
191
|
+
#-------------------------------------------------------------------------------------------------------------------
|
192
|
+
# Allows a previously submitted exception that has not been approved to be withdrawn.
|
193
|
+
#
|
194
|
+
# @param exception_id - The exception id returned after the vuln exception was submitted for creation.
|
195
|
+
#-------------------------------------------------------------------------------------------------------------------
|
196
|
+
def vuln_exception_recall(exception_id)
|
197
|
+
xml = make_xml('VulnerabilityExceptionRecallRequest', {'exception-id' => exception_id})
|
198
|
+
r = execute xml, '1.2'
|
199
|
+
r.success
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
#-------------------------------------------------------------------------------------------------------------------
|
204
|
+
# Allows a submitted vulnerability exception to be approved.
|
205
|
+
#
|
206
|
+
# @param input:
|
207
|
+
# :exception_id - The exception id returned after the vuln exception was submitted for creation.
|
208
|
+
# :comment - An optional comment
|
209
|
+
#-------------------------------------------------------------------------------------------------------------------
|
210
|
+
def vuln_exception_approve(input)
|
211
|
+
exception_id = input[:exception_id]
|
212
|
+
unless exception_id
|
213
|
+
raise ArgumentError.new 'Exception Id is required'
|
214
|
+
end
|
215
|
+
|
216
|
+
xml = make_xml('VulnerabilityExceptionApproveRequest', {'exception-id' => exception_id})
|
217
|
+
comment = input[:comment]
|
218
|
+
if comment && !comment.empty?
|
219
|
+
comment_xml = make_xml('comment', {}, comment, false)
|
220
|
+
xml.add_element comment_xml
|
221
|
+
end
|
222
|
+
|
223
|
+
r = execute xml, '1.2'
|
224
|
+
r.success
|
225
|
+
end
|
226
|
+
|
227
|
+
#-------------------------------------------------------------------------------------------------------------------
|
228
|
+
# Rejects a submitted vulnerability exception to be approved.
|
229
|
+
#
|
230
|
+
# @param input:
|
231
|
+
# :exception_id - The exception id returned after the vuln exception was submitted for creation.
|
232
|
+
# :comment - An optional comment
|
233
|
+
#-------------------------------------------------------------------------------------------------------------------
|
234
|
+
def vuln_exception_reject(input)
|
235
|
+
exception_id = input[:exception_id]
|
236
|
+
unless exception_id
|
237
|
+
raise ArgumentError.new 'Exception Id is required'
|
238
|
+
end
|
239
|
+
|
240
|
+
xml = make_xml('VulnerabilityExceptionRejectRequest', {'exception-id' => exception_id})
|
241
|
+
comment = input[:comment]
|
242
|
+
if comment && !comment.empty?
|
243
|
+
comment_xml = make_xml('comment', {}, comment, false)
|
244
|
+
xml.add_element comment_xml
|
245
|
+
end
|
246
|
+
|
247
|
+
r = execute xml, '1.2'
|
248
|
+
r.success
|
249
|
+
end
|
250
|
+
|
251
|
+
#-------------------------------------------------------------------------------------------------------------------
|
252
|
+
# Updates a vulnerability exception comment.
|
253
|
+
#
|
254
|
+
# @param input:
|
255
|
+
# :exception_id - The exception id returned after the vuln exception was submitted for creation.
|
256
|
+
# :submitter_comment - The submitter comment
|
257
|
+
# :reviewer_comment - The reviewer comment
|
258
|
+
#-------------------------------------------------------------------------------------------------------------------
|
259
|
+
def vuln_exception_update_comment(input)
|
260
|
+
exception_id = input[:exception_id]
|
261
|
+
unless exception_id
|
262
|
+
raise ArgumentError.new 'Exception Id is required'
|
263
|
+
end
|
264
|
+
|
265
|
+
xml = make_xml('VulnerabilityExceptionUpdateCommentRequest', {'exception-id' => exception_id})
|
266
|
+
submitter_comment = input[:submitter_comment]
|
267
|
+
if submitter_comment && !submitter_comment.empty?
|
268
|
+
comment_xml = make_xml('submitter-comment', {}, submitter_comment, false)
|
269
|
+
xml.add_element comment_xml
|
270
|
+
end
|
271
|
+
|
272
|
+
reviewer_comment = input[:reviewer_comment]
|
273
|
+
if reviewer_comment && !reviewer_comment.empty?
|
274
|
+
comment_xml = make_xml('reviewer-comment', {}, reviewer_comment, false)
|
275
|
+
xml.add_element comment_xml
|
276
|
+
end
|
277
|
+
|
278
|
+
r = execute xml, '1.2'
|
279
|
+
r.success
|
280
|
+
end
|
281
|
+
|
282
|
+
#-------------------------------------------------------------------------------------------------------------------
|
283
|
+
# Update the expiration date for a vulnerability exception.
|
284
|
+
#
|
285
|
+
# @param input
|
286
|
+
# :exception_id - The exception id returned after the vulnerability exception was submitted for creation.
|
287
|
+
# :expiration_date - The new expiration date format: YYYY-MM-DD
|
288
|
+
#-------------------------------------------------------------------------------------------------------------------
|
289
|
+
def vuln_exception_update_expiration_date(input)
|
290
|
+
exception_id = input[:exception_id]
|
291
|
+
unless exception_id
|
292
|
+
raise ArgumentError.new 'Exception Id is required'
|
293
|
+
end
|
294
|
+
|
295
|
+
expiration_date = input[:expiration_date]
|
296
|
+
if expiration_date && !expiration_date.empty? && expiration_date =~ /\A\desc{4}-(\desc{2})-(\desc{2})\z/
|
297
|
+
if $1.to_i > 12
|
298
|
+
raise ArgumentError.new 'The expiration date month value is invalid'
|
299
|
+
end
|
300
|
+
|
301
|
+
if $2.to_i > 31
|
302
|
+
raise ArgumentError.new 'The expiration date day value is invalid'
|
303
|
+
end
|
304
|
+
else
|
305
|
+
raise ArgumentError.new 'Expiration date is invalid'
|
306
|
+
end
|
307
|
+
|
308
|
+
options = {}
|
309
|
+
options['exception-id'] = exception_id
|
310
|
+
options['expiration-date'] = expiration_date
|
311
|
+
xml = make_xml('VulnerabilityExceptionUpdateExpirationDateRequest', options)
|
312
|
+
r = execute xml, '1.2'
|
313
|
+
r.success
|
314
|
+
end
|
315
|
+
|
316
|
+
#-------------------------------------------------------------------------------------------------------------------
|
317
|
+
# Deletes a submitted vulnerability exception to be approved.
|
318
|
+
#
|
319
|
+
# @param exception_id - The exception id returned after the vuln exception was submitted for creation.
|
320
|
+
#-------------------------------------------------------------------------------------------------------------------
|
321
|
+
def vuln_exception_delete(exception_id)
|
322
|
+
unless exception_id
|
323
|
+
raise ArgumentError.new 'Exception Id is required'
|
324
|
+
end
|
325
|
+
|
326
|
+
xml = make_xml('VulnerabilityExceptionDeleteRequest', {'exception-id' => exception_id})
|
327
|
+
r = execute xml, '1.2'
|
328
|
+
r.success
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
# === Description
|
333
|
+
# Object that represents a listing of all of the vulnerabilities in the vulnerability database
|
334
|
+
#
|
335
|
+
class VulnerabilityListing
|
336
|
+
# true if an error condition exists; false otherwise
|
337
|
+
attr_reader :error
|
338
|
+
# Error message string
|
339
|
+
attr_reader :error_msg
|
340
|
+
# The NSC Connection associated with this object
|
341
|
+
attr_reader :connection
|
342
|
+
# Array containing (VulnerabilitySummary*)
|
343
|
+
attr_reader :vulnerability_summaries
|
344
|
+
# The number of vulnerability definitions
|
345
|
+
attr_reader :vulnerability_count
|
346
|
+
|
347
|
+
# Constructor
|
348
|
+
# VulnerabilityListing(connection)
|
349
|
+
def initialize(connection)
|
350
|
+
@error = false
|
351
|
+
@vulnerability_summaries = []
|
352
|
+
@connection = connection
|
353
|
+
|
354
|
+
r = @connection.execute('<VulnerabilityListingRequest session-id="' + @connection.session_id + '"/>')
|
355
|
+
|
356
|
+
if r.success
|
357
|
+
r.res.elements.each('VulnerabilityListingResponse/VulnerabilitySummary') do |v|
|
358
|
+
@vulnerability_summaries.push(VulnerabilitySummary.new(v.attributes['id'], v.attributes["title"], v.attributes["severity"]))
|
359
|
+
end
|
360
|
+
else
|
361
|
+
@error = true
|
362
|
+
@error_msg = 'VulnerabilitySummary Parse Error'
|
363
|
+
end
|
364
|
+
@vulnerability_count = @vulnerability_summaries.length
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# === Description
|
369
|
+
# Object that represents the summary of an entry in the vulnerability database
|
370
|
+
#
|
371
|
+
class VulnerabilitySummary
|
372
|
+
|
373
|
+
# The unique ID string for this vulnerability
|
374
|
+
attr_reader :id
|
375
|
+
# The title of this vulnerability
|
376
|
+
attr_reader :title
|
377
|
+
# The severity of this vulnerability (1 – 10)
|
378
|
+
attr_reader :severity
|
379
|
+
|
380
|
+
# Constructor
|
381
|
+
# VulnerabilitySummary(id, title, severity)
|
382
|
+
def initialize(id, title, severity)
|
383
|
+
@id = id
|
384
|
+
@title = title
|
385
|
+
@severity = severity
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
390
|
+
|
391
|
+
# === Description
|
392
|
+
# Object that represents the details for an entry in the vulnerability database
|
393
|
+
#
|
394
|
+
class VulnerabilityDetail
|
395
|
+
# true if an error condition exists; false otherwise
|
396
|
+
attr_reader :error
|
397
|
+
# Error message string
|
398
|
+
attr_reader :error_msg
|
399
|
+
# The NSC Connection associated with this object
|
400
|
+
attr_reader :connection
|
401
|
+
# The unique ID string for this vulnerability
|
402
|
+
attr_reader :id
|
403
|
+
# The title of this vulnerability
|
404
|
+
attr_reader :title
|
405
|
+
# The severity of this vulnerability (1 – 10)
|
406
|
+
attr_reader :severity
|
407
|
+
# The pciSeverity of this vulnerability
|
408
|
+
attr_reader :pciSeverity
|
409
|
+
# The CVSS score of this vulnerability
|
410
|
+
attr_reader :cvssScore
|
411
|
+
# The CVSS vector of this vulnerability
|
412
|
+
attr_reader :cvssVector
|
413
|
+
# The date this vulnerability was published
|
414
|
+
attr_reader :published
|
415
|
+
# The date this vulnerability was added to Nexpose
|
416
|
+
attr_reader :added
|
417
|
+
# The last date this vulnerability was modified
|
418
|
+
attr_reader :modified
|
419
|
+
# The HTML Description of this vulnerability
|
420
|
+
attr_reader :description
|
421
|
+
# External References for this vulnerability
|
422
|
+
# Array containing (Reference)
|
423
|
+
attr_reader :references
|
424
|
+
# The HTML Solution for this vulnerability
|
425
|
+
attr_reader :solution
|
426
|
+
|
427
|
+
# Constructor
|
428
|
+
# VulnerabilityListing(connection,id)
|
429
|
+
def initialize(connection, id)
|
430
|
+
|
431
|
+
@error = false
|
432
|
+
@connection = connection
|
433
|
+
@id = id
|
434
|
+
@references = []
|
435
|
+
|
436
|
+
r = @connection.execute('<VulnerabilityDetailsRequest session-id="' + @connection.session_id + '" vuln-id="' + @id + '"/>')
|
437
|
+
|
438
|
+
if r.success
|
439
|
+
r.res.elements.each('VulnerabilityDetailsResponse/Vulnerability') do |v|
|
440
|
+
@id = v.attributes['id']
|
441
|
+
@title = v.attributes["title"]
|
442
|
+
@severity = v.attributes["severity"]
|
443
|
+
@pciSeverity = v.attributes['pciSeverity']
|
444
|
+
@cvssScore = v.attributes['cvssScore']
|
445
|
+
@cvssVector = v.attributes['cvssVector']
|
446
|
+
@published = v.attributes['published']
|
447
|
+
@added = v.attributes['added']
|
448
|
+
@modified = v.attributes['modified']
|
449
|
+
|
450
|
+
v.elements.each('description') do |desc|
|
451
|
+
@description = desc.to_s.gsub(/\<\/?description\>/i, '')
|
452
|
+
end
|
453
|
+
|
454
|
+
v.elements.each('solution') do |sol|
|
455
|
+
@solution = sol.to_s.gsub(/\<\/?solution\>/i, '')
|
456
|
+
end
|
457
|
+
|
458
|
+
v.elements.each('references/reference') do |ref|
|
459
|
+
@references.push(Reference.new(ref.attributes['source'], ref.text))
|
460
|
+
end
|
461
|
+
end
|
462
|
+
else
|
463
|
+
@error = true
|
464
|
+
@error_msg = 'VulnerabilitySummary Parse Error'
|
465
|
+
end
|
466
|
+
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
# === Description
|
471
|
+
#
|
472
|
+
class Reference
|
473
|
+
|
474
|
+
attr_reader :source
|
475
|
+
attr_reader :reference
|
476
|
+
|
477
|
+
def initialize(source, reference)
|
478
|
+
@source = source
|
479
|
+
@reference = reference
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# TODO: review
|
484
|
+
# === Description
|
485
|
+
#
|
486
|
+
class VulnFilter
|
487
|
+
|
488
|
+
attr_reader :typeMask
|
489
|
+
attr_reader :maxAlerts
|
490
|
+
attr_reader :severityThreshold
|
491
|
+
|
492
|
+
def initialize(type_mask, severity_threshold, max_alerts = -1)
|
493
|
+
@typeMask = type_mask
|
494
|
+
@maxAlerts = max_alerts
|
495
|
+
@severityThreshold = severity_threshold
|
496
|
+
end
|
497
|
+
|
498
|
+
include Sanitize
|
499
|
+
|
500
|
+
def to_xml
|
501
|
+
xml = '<vulnFilter '
|
502
|
+
xml << %Q{ type_mask="#{replace_entities(typeMask)}"}
|
503
|
+
xml << %Q{ maxAlerts="#{replace_entities(maxAlerts)}"}
|
504
|
+
xml << %Q{ severity_threshold="#{replace_entities(severityThreshold)}"}
|
505
|
+
xml << '/>'
|
506
|
+
xml
|
507
|
+
end
|
508
|
+
|
509
|
+
end
|
510
|
+
end
|