nexpose 0.2.8 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,368 @@
1
+ module Nexpose
2
+ module NexposeAPI
3
+ include XMLUtils
4
+
5
+ # Retrieve vulnerability exceptions.
6
+ #
7
+ # @param [String] status Filter exceptions by the current status.
8
+ # @see Nexpose::VulnException::Status
9
+ # @param [String] duration A time interval in the format "PnYnMnDTnHnMnS".
10
+ # @return [Array[VulnException]] List of matching vulnerability exceptions.
11
+ #
12
+ def list_vuln_exceptions(status = nil, duration = nil)
13
+ option = {}
14
+ option['status'] = status if status
15
+ option['time-duration'] = duration if duration
16
+ xml = make_xml('VulnerabilityExceptionListingRequest', option)
17
+ response = execute(xml, '1.2')
18
+
19
+ xs = []
20
+ if response.success
21
+ response.res.elements.each('//VulnerabilityException') do |ve|
22
+ xs << VulnException.parse(ve)
23
+ end
24
+ end
25
+ xs
26
+ end
27
+
28
+ alias_method :vuln_exceptions, :list_vuln_exceptions
29
+
30
+ # Resubmit a vulnerability exception request with a new comment and reason
31
+ # after an exception has been rejected.
32
+ #
33
+ # You can only resubmit a request that has a "Rejected" status; if an
34
+ # exception is "Approved" or "Under Review" you will receive an error
35
+ # message stating that the exception request cannot be resubmitted.
36
+ #
37
+ # @param [Fixnum] id Unique identifier of the exception to resubmit.
38
+ # @param [String] comment Comment to justify the exception resubmission.
39
+ # @param [String] reason The reason for the exception status, if changing.
40
+ # @see Nexpose::VulnException::Reason
41
+ # @return [Boolean] Whether or not the resubmission was valid.
42
+ #
43
+ def resubmit_vuln_exception(id, comment, reason = nil)
44
+ options = { 'exception-id' => id }
45
+ options['reason'] = reason if reason
46
+ xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
47
+ comment_xml = make_xml('comment', {}, comment, false)
48
+ xml.add_element(comment_xml)
49
+ r = execute(xml, '1.2')
50
+ r.success
51
+ end
52
+
53
+ # Recall a vulnerability exception. Recall is used by a submitter to undo an
54
+ # exception request that has not been approved yet.
55
+ #
56
+ # You can only recall a vulnerability exception that has 'Under Review'
57
+ # status.
58
+ #
59
+ # @param [Fixnum] id Unique identifier of the exception to resubmit.
60
+ # @return [Boolean] Whether or not the recall was accepted by the console.
61
+ #
62
+ def recall_vuln_exception(id)
63
+ xml = make_xml('VulnerabilityExceptionRecallRequest',
64
+ { 'exception-id' => id })
65
+ execute(xml, '1.2').success
66
+ end
67
+
68
+ # Delete an existing vulnerability exception.
69
+ #
70
+ # @param [Fixnum] id The ID of a vuln exception.
71
+ # @return [Boolean] Whether or not deletion was successful.
72
+ #
73
+ def delete_vuln_exception(id)
74
+ xml = make_xml('VulnerabilityExceptionDeleteRequest',
75
+ { 'exception-id' => id })
76
+ execute(xml, '1.2').success
77
+ end
78
+ end
79
+
80
+ # A vulnerability exception.
81
+ #
82
+ # Certain attributes are necessary for some exception scopes, even though
83
+ # they are optional otherwise.
84
+ # • An exception for all instances of a vulnerability on all assets only
85
+ # requires the vuln_id attribute. The device_id, vuln_key and port
86
+ # attributes are ignored for this scope type.
87
+ # • An exception for all instances on a specific asset requires the vuln_id
88
+ # and device_id attributes. The vuln_key and port attributes are ignored for
89
+ # this scope type.
90
+ # • An exception for a specific instance of a vulnerability on a specific
91
+ # asset requires the vuln_id, device_id. Additionally, the port and/or the
92
+ # key attribute must be specified.
93
+ #
94
+ class VulnException
95
+
96
+ # Unique identifier assigned to an exception.
97
+ attr_accessor :id
98
+ # Unique identifier of a vulnerability.
99
+ attr_accessor :vuln_id
100
+ # The name of submitter of the exception.
101
+ attr_accessor :submitter
102
+ # The name of the reviewer of the exception.
103
+ attr_accessor :reviewer
104
+ # The state of the exception in the work flow process.
105
+ # @see Nexpose::VulnException::Status
106
+ attr_accessor :status
107
+ # The reason for the exception status.
108
+ # @see Nexpose::VulnException::Reason
109
+ attr_accessor :reason
110
+ # The scope of the exception.
111
+ # @see Nexpose::VulnException::Scope
112
+ attr_accessor :scope
113
+ # ID of device, if this exception applies to only one device.
114
+ attr_accessor :device_id
115
+ # Port on a device, if this exception applies to a specific port.
116
+ attr_accessor :port
117
+ # The specific vulnerable component in a discovered instance of the
118
+ # vulnerability referenced by the vuln_id, such as a program, file or user
119
+ # account.
120
+ attr_accessor :vuln_key
121
+ # The date an exception will expire, causing the vulnerability to be
122
+ # included in report risk scores.
123
+ attr_accessor :expiration
124
+ # Any comment provided by the submitter.
125
+ attr_accessor :submitter_comment
126
+ # Any comment provided by the reviewer.
127
+ attr_accessor :reviewer_comment
128
+
129
+ def initialize(vuln_id, scope, reason, status = nil)
130
+ @vuln_id, @scope, @reason, @status = vuln_id, scope, reason, status
131
+ end
132
+
133
+ # Submit this exception on the security console.
134
+ #
135
+ # @param [Connection] connection Connection to security console.
136
+ # @return [Fixnum] Newly assigned exception ID.
137
+ #
138
+ def save(connection, comment = nil)
139
+ validate
140
+
141
+ xml = connection.make_xml('VulnerabilityExceptionCreateRequest')
142
+ xml.add_attributes({ 'vuln-id' => @vuln_id,
143
+ 'scope' => @scope,
144
+ 'reason' => @reason })
145
+ case @scope
146
+ when Scope::ALL_INSTANCES_ON_A_SPECIFIC_ASSET
147
+ xml.add_attributes({ 'device-id' => @device_id })
148
+ when Scope::SPECIFIC_INSTANCE_OF_SPECIFIC_ASSET
149
+ xml.add_attributes({ 'device-id' => @device_id,
150
+ 'port-no' => @port,
151
+ 'vuln-key' => @vuln_key })
152
+ end
153
+
154
+ @submitter_comment = comment if comment
155
+ if @submitter_comment
156
+ comment = REXML::Element.new('comment')
157
+ comment.add_text(comment)
158
+ xml.add_element(comment)
159
+ end
160
+
161
+ response = connection.execute(xml, '1.2')
162
+ @id = response.attributes['exception-id'].to_i if response.success
163
+ end
164
+
165
+ # Resubmit a vulnerability exception request with a new comment and reason
166
+ # after an exception has been rejected.
167
+ #
168
+ # You can only resubmit a request that has a "Rejected" status; if an
169
+ # exception is "Approved" or "Under Review" you will receive an error
170
+ # message stating that the exception request cannot be resubmitted.
171
+ #
172
+ # This call will use the object's current state to resubmit.
173
+ #
174
+ # @param [Connection] connection Connection to security console.
175
+ # @return [Boolean] Whether or not the resubmission was valid.
176
+ #
177
+ def resubmit(connection)
178
+ raise ArgumentError.new('Only Rejected exceptions can be resubmitted.') unless @status == Status::REJECTED
179
+ connection.resubmit_vuln_exception(@id, @submitter_comment, @reason)
180
+ end
181
+
182
+ # Recall a vulnerability exception. Recall is used by a submitter to undo an
183
+ # exception request that has not been approved yet.
184
+ #
185
+ # You can only recall a vulnerability exception that has 'Under Review'
186
+ # status.
187
+ #
188
+ # @param [Connection] connection Connection to security console.
189
+ # @return [Boolean] Whether or not the recall was accepted by the console.
190
+ #
191
+ def recall(connection)
192
+ connection.recall_vuln_exception(id)
193
+ end
194
+
195
+ # Approve a vulnerability exception request, update comments and expiration
196
+ # dates on vulnerability exceptions that are "Under Review".
197
+ #
198
+ # @param [Connection] connection Connection to security console.
199
+ # @param [String] comment Comment to accompany the approval.
200
+ # @return [Boolean] Whether or not the approval was accepted by the console.
201
+ #
202
+ def approve(connection, comment = nil)
203
+ xml = connection.make_xml('VulnerabilityExceptionApproveRequest',
204
+ { 'exception-id' => @id })
205
+ if comment
206
+ cxml = REXML::Element.new('comment')
207
+ cxml.add_text(comment)
208
+ xml.add_element(cxml)
209
+ @reviewer_comment = comment
210
+ end
211
+
212
+ connection.execute(xml, '1.2').success
213
+ end
214
+
215
+ # Reject a vulnerability exception request and update comments for the
216
+ # vulnerability exception request.
217
+ #
218
+ # @param [Connection] connection Connection to security console.
219
+ # @param [String] comment Comment to accompany the rejection.
220
+ # @return [Boolean] Whether or not the reject was accepted by the console.
221
+ #
222
+ def reject(connection, comment = nil)
223
+ xml = connection.make_xml('VulnerabilityExceptionRejectRequest',
224
+ { 'exception-id' => @id })
225
+ if comment
226
+ cxml = REXML::Element.new('comment')
227
+ cxml.add_text(comment)
228
+ xml.add_element(cxml)
229
+ end
230
+
231
+ connection.execute(xml, '1.2').success
232
+ end
233
+
234
+ # Deletes this vulnerability exception.
235
+ #
236
+ # @param [Connection] connection Connection to security console.
237
+ # @return [Boolean] Whether or not deletion was successful.
238
+ #
239
+ def delete(connection)
240
+ connection.delete_vuln_exception(@id)
241
+ end
242
+
243
+ # Update security console with submitter comment on this vulnerability
244
+ # exceptions.
245
+ #
246
+ # Cannot update a submit comment unless exception is under review or has
247
+ # expired.
248
+ #
249
+ # @param [Connection] connection Connection to security console.
250
+ # @param [String] comment Submitter comment on this exception.
251
+ # @return [Boolean] Whether the comment was successfully submitted.
252
+ #
253
+ def update_submitter_comment(connection, comment)
254
+ xml = connection.make_xml('VulnerabilityExceptionUpdateCommentRequest',
255
+ { 'exception-id' => @id })
256
+ cxml = REXML::Element.new('submitter-comment')
257
+ cxml.add_text(comment)
258
+ xml.add_element(cxml)
259
+ @submitter_comment = comment
260
+
261
+ connection.execute(xml, '1.2').success
262
+ end
263
+
264
+ # Update security console with reviewer comment on this vulnerability
265
+ # exceptions.
266
+ #
267
+ # @param [Connection] connection Connection to security console.
268
+ # @param [String] comment Reviewer comment on this exception.
269
+ # @return [Boolean] Whether the comment was successfully submitted.
270
+ #
271
+ def update_reviewer_comment(connection, comment)
272
+ xml = connection.make_xml('VulnerabilityExceptionUpdateCommentRequest',
273
+ { 'exception-id' => @id })
274
+ cxml = REXML::Element.new('reviewer-comment')
275
+ cxml.add_text(comment)
276
+ xml.add_element(cxml)
277
+ @reviewer_comment = comment
278
+
279
+ connection.execute(xml, '1.2').success
280
+ end
281
+
282
+ # Update the expiration date for this exception.
283
+ # The expiration time cannot be in the past.
284
+ #
285
+ # @param [Connection] connection Connection to security console.
286
+ # @param [String] new_date Date in the format "YYYY-MM-DD".
287
+ # @return [Boolean] Whether the update was successfully submitted.
288
+ #
289
+ def update_expiration_date(connection, new_date)
290
+ xml = connection.make_xml('VulnerabilityExceptionUpdateExpirationDateRequest',
291
+ { 'exception-id' => @id,
292
+ 'expiration-date' => new_date })
293
+ connection.execute(xml, '1.2').success
294
+ end
295
+
296
+ # Validate that this exception meets to requires for the assigned scope.
297
+ #
298
+ def validate
299
+ raise ArgumentError.new('No vuln_id.') unless @vuln_id
300
+ raise ArgumentError.new('No scope.') unless @scope
301
+ raise ArgumentError.new('No reason.') unless @reason
302
+
303
+ case @scope
304
+ when Scope::ALL_INSTANCES
305
+ @device_id = @port = @vuln_key = nil
306
+ when Scope::ALL_INSTANCES_ON_A_SPECIFIC_ASSET
307
+ raise ArgumentError.new('No device_id.') unless @device_id
308
+ @port = @vuln_key = nil
309
+ when Scope::SPECIFIC_INSTANCE_OF_SPECIFIC_ASSET
310
+ raise ArgumentError.new('No device_id.') unless @device_id
311
+ raise ArgumentError.new('Port or vuln_key is required.') unless @port || @vuln_key
312
+ else
313
+ raise ArgumentError.new("Invalid scope: #{@scope}")
314
+ end
315
+ end
316
+
317
+ def self.parse(xml)
318
+ exception = new(xml.attributes['vuln-id'],
319
+ xml.attributes['scope'],
320
+ xml.attributes['reason'],
321
+ xml.attributes['status'])
322
+
323
+ exception.id = xml.attributes['exception-id']
324
+ exception.submitter = xml.attributes['submitter']
325
+ exception.reviewer = xml.attributes['reviewer']
326
+ exception.device_id = xml.attributes['device-id']
327
+ exception.port = xml.attributes['port-no']
328
+ exception.vuln_key = xml.attributes['vuln-key']
329
+ # TODO: Convert to Date/Time object?
330
+ exception.expiration = xml.attributes['expiration-date']
331
+
332
+ submitter_comment = xml.elements['submitter-comment']
333
+ exception.submitter_comment = submitter_comment.text if submitter_comment
334
+ reviewer_comment = xml.elements['reviewer-comment']
335
+ exception.reviewer_comment = reviewer_comment.text if reviewer_comment
336
+
337
+ exception
338
+ end
339
+
340
+ # The state of a vulnerability exception in the work flow process.
341
+ #
342
+ module Status
343
+ UNDER_REVIEW = 'Under Review'
344
+ APPROVED = 'Approved'
345
+ REJECTED = 'Rejected'
346
+ DELETED = 'Deleted'
347
+ end
348
+
349
+ # The reason for the exception status.
350
+ #
351
+ module Reason
352
+ FALSE_POSITIVE = 'False Positive'
353
+ COMPENSATING_CONTROL = 'Compensating Control'
354
+ ACCEPTABLE_USE = 'Acceptable Use'
355
+ ACCEPTABLE_RISK = 'Acceptable Risk'
356
+ OTHER = 'Other'
357
+ end
358
+
359
+ # The scope of the exception.
360
+ #
361
+ module Scope
362
+ ALL_INSTANCES = 'All Instances'
363
+ ALL_INSTANCES_ON_A_SPECIFIC_ASSET = 'All Instances on a Specific Asset'
364
+ ALL_INSTANCES_IN_A_SPECIFIC_SITE = 'All Instances in a Specific Site'
365
+ SPECIFIC_INSTANCE_OF_SPECIFIC_ASSET = 'Specific Instance of Specific Asset'
366
+ end
367
+ end
368
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexpose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - HD Moore
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-07-30 00:00:00.000000000 Z
13
+ date: 2013-09-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: librex
@@ -54,25 +54,33 @@ files:
54
54
  - README.markdown
55
55
  - Rakefile
56
56
  - lib/nexpose.rb
57
+ - lib/nexpose/pool.rb
57
58
  - lib/nexpose/group.rb
59
+ - lib/nexpose/device.rb
60
+ - lib/nexpose/report_template.rb
58
61
  - lib/nexpose/ticket.rb
59
62
  - lib/nexpose/common.rb
60
- - lib/nexpose/scan_engine.rb
63
+ - lib/nexpose/data_table.rb
64
+ - lib/nexpose/dag.rb
61
65
  - lib/nexpose/creds.rb
62
66
  - lib/nexpose/api_request.rb
63
67
  - lib/nexpose/role.rb
68
+ - lib/nexpose/engine.rb
64
69
  - lib/nexpose/manage.rb
65
70
  - lib/nexpose/scan.rb
71
+ - lib/nexpose/scan_template.rb
66
72
  - lib/nexpose/report.rb
67
73
  - lib/nexpose/vuln.rb
74
+ - lib/nexpose/ajax.rb
68
75
  - lib/nexpose/util.rb
69
76
  - lib/nexpose/site.rb
77
+ - lib/nexpose/filter.rb
70
78
  - lib/nexpose/alert.rb
71
79
  - lib/nexpose/silo.rb
80
+ - lib/nexpose/vuln_exception.rb
72
81
  - lib/nexpose/user.rb
73
82
  - lib/nexpose/tags
74
83
  - lib/nexpose/connection.rb
75
- - lib/nexpose/misc.rb
76
84
  - lib/nexpose/error.rb
77
85
  - lib/README.md
78
86
  homepage: https://github.com/rapid7/nexpose-client
data/lib/nexpose/misc.rb DELETED
@@ -1,35 +0,0 @@
1
- module Nexpose
2
- module NexposeAPI
3
- include XMLUtils
4
-
5
- def device_delete(param)
6
- r = execute(make_xml('DeviceDeleteRequest', {'device-id' => param}))
7
- r.success
8
- end
9
-
10
- # Lists all the users for the NSC along with the user details.
11
- #
12
- def list_users
13
- r = execute(make_xml('UserListingRequest'))
14
- if r.success
15
- res = []
16
- r.res.elements.each('//UserSummary') do |user_summary|
17
- res << {
18
- :auth_source => user_summary.attributes['authSource'],
19
- :auth_module => user_summary.attributes['authModule'],
20
- :user_name => user_summary.attributes['userName'],
21
- :full_name => user_summary.attributes['fullName'],
22
- :email => user_summary.attributes['email'],
23
- :is_admin => user_summary.attributes['isAdmin'].to_s.chomp.eql?('1'),
24
- :is_disabled => user_summary.attributes['disabled'].to_s.chomp.eql?('1'),
25
- :site_count => user_summary.attributes['siteCount'],
26
- :group_count => user_summary.attributes['groupCount']
27
- }
28
- end
29
- res
30
- else
31
- false
32
- end
33
- end
34
- end
35
- end