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.
@@ -1,36 +1,36 @@
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!(/</, "&lt;")
9
- ret.gsub!(/>/, "&gt;")
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
1
+ module Nexpose
2
+ module Sanitize
3
+ def replace_entities(str)
4
+ ret = str.dup
5
+ ret.gsub!(/&/, "&amp;")
6
+ ret.gsub!(/'/, "&apos;")
7
+ ret.gsub!(/"/, "&quot;")
8
+ ret.gsub!(/</, "&lt;")
9
+ ret.gsub!(/>/, "&gt;")
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
@@ -1,520 +1,510 @@
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
- if !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
- if !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
- if !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
- if !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
- if !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
- if !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\d{4}-(\d{2})-(\d{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
- if !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
-
337
- # true if an error condition exists; false otherwise
338
- attr_reader :error
339
- # Error message string
340
- attr_reader :error_msg
341
- # The last XML request sent by this object
342
- attr_reader :request_xml
343
- # The last XML response received by this object
344
- attr_reader :response_xml
345
- # The NSC Connection associated with this object
346
- attr_reader :connection
347
- # Array containing (VulnerabilitySummary*)
348
- attr_reader :vulnerability_summaries
349
- # The number of vulnerability definitions
350
- attr_reader :vulnerability_count
351
-
352
- # Constructor
353
- # VulnerabilityListing(connection)
354
- def initialize(connection)
355
- @error = false
356
- @vulnerability_summaries = []
357
- @connection = connection
358
-
359
- r = @connection.execute('<VulnerabilityListingRequest session-id="' + @connection.session_id + '"/>')
360
-
361
- if (r.success)
362
- r.res.elements.each('VulnerabilityListingResponse/VulnerabilitySummary') do |v|
363
- @vulnerability_summaries.push(VulnerabilitySummary.new(v.attributes['id'], v.attributes["title"], v.attributes["severity"]))
364
- end
365
- else
366
- @error = true
367
- @error_msg = 'VulnerabilitySummaryRequest Parse Error'
368
- end
369
- @vulnerability_count = @vulnerability_summaries.length
370
- end
371
- end
372
-
373
- # === Description
374
- # Object that represents the summary of an entry in the vulnerability database
375
- #
376
- class VulnerabilitySummary
377
-
378
- # The unique ID string for this vulnerability
379
- attr_reader :id
380
- # The title of this vulnerability
381
- attr_reader :title
382
- # The severity of this vulnerability (1 10)
383
- attr_reader :severity
384
-
385
- # Constructor
386
- # VulnerabilitySummary(id, title, severity)
387
- def initialize(id, title, severity)
388
- @id = id
389
- @title = title
390
- @severity = severity
391
-
392
- end
393
-
394
- end
395
-
396
- # === Description
397
- # Object that represents the details for an entry in the vulnerability database
398
- #
399
- class VulnerabilityDetail
400
- # true if an error condition exists; false otherwise
401
- attr_reader :error
402
- # Error message string
403
- attr_reader :error_msg
404
- # The last XML request sent by this object
405
- attr_reader :request_xml
406
- # The last XML response received by this object
407
- attr_reader :response_xml
408
- # The NSC Connection associated with this object
409
- attr_reader :connection
410
- # The unique ID string for this vulnerability
411
- attr_reader :id
412
- # The title of this vulnerability
413
- attr_reader :title
414
- # The severity of this vulnerability (1 – 10)
415
- attr_reader :severity
416
- # The pciSeverity of this vulnerability
417
- attr_reader :pciSeverity
418
- # The CVSS score of this vulnerability
419
- attr_reader :cvssScore
420
- # The CVSS vector of this vulnerability
421
- attr_reader :cvssVector
422
- # The date this vulnerability was published
423
- attr_reader :published
424
- # The date this vulnerability was added to NeXpose
425
- attr_reader :added
426
- # The last date this vulnerability was modified
427
- attr_reader :modified
428
- # The HTML Description of this vulnerability
429
- attr_reader :description
430
- # External References for this vulnerability
431
- # Array containing (Reference)
432
- attr_reader :references
433
- # The HTML Solution for this vulnerability
434
- attr_reader :solution
435
-
436
- # Constructor
437
- # VulnerabilityListing(connection,id)
438
- def initialize(connection, id)
439
-
440
- @error = false
441
- @connection = connection
442
- @id = id
443
- @references = []
444
-
445
- r = @connection.execute('<VulnerabilityDetailsRequest session-id="' + @connection.session_id + '" vuln-id="' + @id + '"/>')
446
-
447
- if (r.success)
448
- r.res.elements.each('VulnerabilityDetailsResponse/Vulnerability') do |v|
449
- @id = v.attributes['id']
450
- @title = v.attributes["title"]
451
- @severity = v.attributes["severity"]
452
- @pciSeverity = v.attributes['pciSeverity']
453
- @cvssScore = v.attributes['cvssScore']
454
- @cvssVector = v.attributes['cvssVector']
455
- @published = v.attributes['published']
456
- @added = v.attributes['added']
457
- @modified = v.attributes['modified']
458
-
459
- v.elements.each('description') do |d|
460
- @description = d.to_s.gsub(/\<\/?description\>/i, '')
461
- end
462
-
463
- v.elements.each('solution') do |s|
464
- @solution = s.to_s.gsub(/\<\/?solution\>/i, '')
465
- end
466
-
467
- v.elements.each('references/reference') do |r|
468
- @references.push(Reference.new(r.attributes['source'], r.text))
469
- end
470
- end
471
- else
472
- @error = true
473
- @error_msg = 'VulnerabilitySummaryRequest Parse Error'
474
- end
475
-
476
- end
477
- end
478
-
479
- # === Description
480
- #
481
- class Reference
482
-
483
- attr_reader :source
484
- attr_reader :reference
485
-
486
- def initialize(source, reference)
487
- @source = source
488
- @reference = reference
489
- end
490
- end
491
-
492
- # TODO: review
493
- # === Description
494
- #
495
- class VulnFilter
496
-
497
- attr_reader :typeMask
498
- attr_reader :maxAlerts
499
- attr_reader :severityThreshold
500
-
501
- def initialize(typeMask, severityThreshold, maxAlerts = -1)
502
- @typeMask = typeMask
503
- @maxAlerts = maxAlerts
504
- @severityThreshold = severityThreshold
505
- end
506
-
507
- include Sanitize
508
-
509
- def to_xml
510
- xml = "<vulnFilter "
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