nexpose 0.0.98 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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