nexpose 7.0.0 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -3
  3. data/Gemfile.lock +1 -1
  4. data/lib/nexpose/ajax.rb +12 -16
  5. data/lib/nexpose/alert.rb +20 -21
  6. data/lib/nexpose/api.rb +3 -3
  7. data/lib/nexpose/asset.rb +23 -23
  8. data/lib/nexpose/blackout.rb +6 -14
  9. data/lib/nexpose/common.rb +87 -92
  10. data/lib/nexpose/connection.rb +8 -10
  11. data/lib/nexpose/console.rb +9 -9
  12. data/lib/nexpose/dag.rb +2 -2
  13. data/lib/nexpose/data_table.rb +8 -12
  14. data/lib/nexpose/device.rb +35 -34
  15. data/lib/nexpose/discovery.rb +69 -69
  16. data/lib/nexpose/discovery/filter.rb +7 -8
  17. data/lib/nexpose/engine.rb +22 -21
  18. data/lib/nexpose/error.rb +7 -5
  19. data/lib/nexpose/external.rb +21 -16
  20. data/lib/nexpose/filter.rb +51 -52
  21. data/lib/nexpose/global_blackout.rb +6 -7
  22. data/lib/nexpose/global_settings.rb +2 -3
  23. data/lib/nexpose/group.rb +25 -19
  24. data/lib/nexpose/json_serializer.rb +4 -14
  25. data/lib/nexpose/maint.rb +8 -9
  26. data/lib/nexpose/manage.rb +2 -2
  27. data/lib/nexpose/multi_tenant_user.rb +42 -42
  28. data/lib/nexpose/password_policy.rb +14 -14
  29. data/lib/nexpose/pool.rb +6 -5
  30. data/lib/nexpose/report.rb +30 -34
  31. data/lib/nexpose/report_template.rb +17 -18
  32. data/lib/nexpose/role.rb +64 -55
  33. data/lib/nexpose/scan.rb +77 -60
  34. data/lib/nexpose/scan_template.rb +17 -17
  35. data/lib/nexpose/scheduled_backup.rb +8 -8
  36. data/lib/nexpose/scheduled_maintenance.rb +9 -9
  37. data/lib/nexpose/shared_credential.rb +30 -33
  38. data/lib/nexpose/shared_secret.rb +5 -5
  39. data/lib/nexpose/silo.rb +68 -66
  40. data/lib/nexpose/silo_profile.rb +47 -50
  41. data/lib/nexpose/site.rb +101 -123
  42. data/lib/nexpose/site_credentials.rb +15 -17
  43. data/lib/nexpose/tag.rb +73 -80
  44. data/lib/nexpose/ticket.rb +45 -42
  45. data/lib/nexpose/user.rb +45 -45
  46. data/lib/nexpose/util.rb +1 -1
  47. data/lib/nexpose/version.rb +1 -1
  48. data/lib/nexpose/vuln.rb +45 -43
  49. data/lib/nexpose/vuln_def.rb +7 -7
  50. data/lib/nexpose/vuln_exception.rb +35 -36
  51. data/lib/nexpose/wait.rb +32 -28
  52. data/lib/nexpose/web_credentials.rb +34 -36
  53. metadata +2 -2
@@ -8,7 +8,7 @@ module Nexpose
8
8
  # @return [Array[VulnerabilityDefinition]] Collection of vulnerability definitions.
9
9
  #
10
10
  def all_vulns
11
- uri = '/api/2.0/vulnerability_definitions'
11
+ uri = '/api/2.0/vulnerability_definitions'
12
12
  resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, per_page: 2_147_483_647)
13
13
  json = JSON.parse(resp, symbolize_names: true)
14
14
  json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
@@ -20,7 +20,7 @@ module Nexpose
20
20
  # @return [Array[VulnerabilityDefinition]] A list of vuln definitions which check the CVE.
21
21
  #
22
22
  def find_vulns_by_cve(cve)
23
- uri = '/api/2.0/vulnerability_definitions'
23
+ uri = '/api/2.0/vulnerability_definitions'
24
24
  resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, cve: cve)
25
25
  json = JSON.parse(resp, symbolize_names: true)
26
26
  json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
@@ -40,7 +40,7 @@ module Nexpose
40
40
  # check the vulnerability.
41
41
  #
42
42
  def find_vulns_by_ref(source, id)
43
- uri = '/api/2.0/vulnerability_definitions'
43
+ uri = '/api/2.0/vulnerability_definitions'
44
44
  resp = AJAX.get(self,
45
45
  uri,
46
46
  AJAX::CONTENT_TYPE::JSON,
@@ -62,10 +62,10 @@ module Nexpose
62
62
  # the provided value.
63
63
  #
64
64
  def find_vulns_by_title(title, all_words = true)
65
- uri = '/api/2.0/vulnerability_definitions'
65
+ uri = '/api/2.0/vulnerability_definitions'
66
66
  params = { title: title, all_words: all_words }
67
- resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, params)
68
- json = JSON.parse(resp, symbolize_names: true)
67
+ resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, params)
68
+ json = JSON.parse(resp, symbolize_names: true)
69
69
  json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
70
70
  end
71
71
  end
@@ -121,7 +121,7 @@ module Nexpose
121
121
  # @return [VulnerabilityDefinition] The requested vulnerability definition, if found.
122
122
  #
123
123
  def self.load(nsc, id)
124
- uri = "/api/2.0/vulnerability_definitions/#{id}"
124
+ uri = "/api/2.0/vulnerability_definitions/#{id}"
125
125
  resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
126
126
  hash = JSON.parse(resp, symbolize_names: true)
127
127
  new.object_from_hash(nsc, hash)
@@ -60,11 +60,9 @@ module Nexpose
60
60
  results << ve
61
61
  end
62
62
  results.keep_if { |v| v.status == status } unless status.nil?
63
- return results
63
+ results
64
64
  end
65
-
66
- alias_method :vuln_exceptions, :list_vuln_exceptions
67
-
65
+ alias vuln_exceptions list_vuln_exceptions
68
66
 
69
67
  # Resubmit a vulnerability exception request with a new comment and reason
70
68
  # after an exception has been rejected.
@@ -80,10 +78,10 @@ module Nexpose
80
78
  # @return [Boolean] Whether or not the resubmission was valid.
81
79
  #
82
80
  def resubmit_vuln_exception(id, comment, reason = nil)
83
- options = { 'exception-id' => id }
81
+ options = { 'exception-id' => id }
84
82
  options['reason'] = reason if reason
85
- xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
86
- comment_xml = make_xml('comment', {}, comment, false)
83
+ xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
84
+ comment_xml = make_xml('comment', {}, comment, false)
87
85
  xml.add_element(comment_xml)
88
86
  r = execute(xml, '1.2')
89
87
  r.success
@@ -115,22 +113,21 @@ module Nexpose
115
113
  execute(xml, '1.2').success
116
114
  end
117
115
 
118
-
119
116
  private
120
117
 
121
- def is_valid_vuln_exception_status?(status)
122
- return true if status.nil?
123
- valid_status = []
124
- Nexpose::VulnException::Status.constants.each {|con| valid_status << Nexpose::VulnException::Status.const_get(con) }
125
- valid_status << Nexpose::VulnException::Status.constants.map(&:to_s).map(&:downcase)
126
- valid_status.flatten.map(&:downcase).include?(status.downcase)
127
- end
118
+ def is_valid_vuln_exception_status?(status)
119
+ return true if status.nil?
120
+ valid_status = []
121
+ Nexpose::VulnException::Status.constants.each { |con| valid_status << Nexpose::VulnException::Status.const_get(con) }
122
+ valid_status << Nexpose::VulnException::Status.constants.map(&:to_s).map(&:downcase)
123
+ valid_status.flatten.map(&:downcase).include?(status.downcase)
124
+ end
128
125
 
129
- def status_string_to_constant(status)
130
- Nexpose::VulnException::Status.constants.find do |name|
131
- Nexpose::VulnException::Status.const_get(name).to_s.downcase==status.downcase || status.to_sym.downcase == name.downcase
132
- end
126
+ def status_string_to_constant(status)
127
+ Nexpose::VulnException::Status.constants.find do |name|
128
+ Nexpose::VulnException::Status.const_get(name).to_s.downcase == status.downcase || status.to_sym.downcase == name.downcase
133
129
  end
130
+ end
134
131
 
135
132
  end
136
133
 
@@ -138,13 +135,13 @@ module Nexpose
138
135
  #
139
136
  # Certain attributes are necessary for some exception scopes, even though
140
137
  # they are optional otherwise.
141
- # An exception for all instances of a vulnerability on all assets only
138
+ # - An exception for all instances of a vulnerability on all assets only
142
139
  # requires the vuln_id attribute. The asset_id, vuln_key and port
143
140
  # attributes are ignored for this scope type.
144
- # An exception for all instances on a specific asset requires the vuln_id
141
+ # - An exception for all instances on a specific asset requires the vuln_id
145
142
  # and asset_id attributes. The vuln_key and port attributes are ignored for
146
143
  # this scope type.
147
- # An exception for a specific instance of a vulnerability on a specific
144
+ # - An exception for a specific instance of a vulnerability on a specific
148
145
  # asset requires the vuln_id, asset_id. Additionally, the port and/or the
149
146
  # key attribute must be specified.
150
147
  #
@@ -169,8 +166,8 @@ module Nexpose
169
166
  attr_accessor :scope
170
167
  # ID of asset, if this exception applies to only one asset.
171
168
  attr_accessor :asset_id
172
- alias :device_id :asset_id
173
- alias :device_id= :asset_id=
169
+ alias device_id asset_id
170
+ alias device_id= asset_id=
174
171
  # Id of the site, if this exception applies to all instances on a site
175
172
  attr_accessor :site_id
176
173
  # ID of the Asset Group, if this exception applies to all instances on an asset group
@@ -193,9 +190,11 @@ module Nexpose
193
190
  # Date when Submit occurred [Time]
194
191
  attr_accessor :submit_date
195
192
 
196
-
197
193
  def initialize(vuln_id, scope, reason, status = nil)
198
- @vuln_id, @scope, @reason, @status = vuln_id, scope, reason, status
194
+ @vuln_id = vuln_id
195
+ @scope = scope
196
+ @reason = reason
197
+ @status = status
199
198
  end
200
199
 
201
200
  # Submit this exception on the security console.
@@ -413,27 +412,27 @@ module Nexpose
413
412
  #
414
413
  module Status
415
414
  UNDER_REVIEW = 'Under Review'
416
- APPROVED = 'Approved'
417
- REJECTED = 'Rejected'
418
- DELETED = 'Deleted'
415
+ APPROVED = 'Approved'
416
+ REJECTED = 'Rejected'
417
+ DELETED = 'Deleted'
419
418
  end
420
419
 
421
420
  # The reason for the exception status.
422
421
  #
423
422
  module Reason
424
- FALSE_POSITIVE = 'False Positive'
423
+ FALSE_POSITIVE = 'False Positive'
425
424
  COMPENSATING_CONTROL = 'Compensating Control'
426
- ACCEPTABLE_USE = 'Acceptable Use'
427
- ACCEPTABLE_RISK = 'Acceptable Risk'
428
- OTHER = 'Other'
425
+ ACCEPTABLE_USE = 'Acceptable Use'
426
+ ACCEPTABLE_RISK = 'Acceptable Risk'
427
+ OTHER = 'Other'
429
428
  end
430
429
 
431
430
  # The scope of the exception.
432
431
  #
433
432
  module Scope
434
- ALL_INSTANCES = 'All Instances'
435
- ALL_INSTANCES_ON_A_SPECIFIC_ASSET = 'All Instances on a Specific Asset'
436
- ALL_INSTANCES_IN_A_SPECIFIC_SITE = 'All Instances in a Specific Site'
433
+ ALL_INSTANCES = 'All Instances'
434
+ ALL_INSTANCES_ON_A_SPECIFIC_ASSET = 'All Instances on a Specific Asset'
435
+ ALL_INSTANCES_IN_A_SPECIFIC_SITE = 'All Instances in a Specific Site'
437
436
  SPECIFIC_INSTANCE_OF_SPECIFIC_ASSET = 'Specific Instance of Specific Asset'
438
437
  end
439
438
  end
@@ -1,12 +1,13 @@
1
1
  module Nexpose
2
+
2
3
  class Wait
3
4
  attr_reader :error_message, :ready, :retry_count, :timeout, :polling_interval
4
5
 
5
6
  def initialize(retry_count: nil, timeout: nil, polling_interval: nil)
6
- @error_message = 'Default General Failure in Nexpose::Wait'
7
- @ready = false
8
- @retry_count = retry_count.to_i
9
- @timeout = timeout
7
+ @error_message = 'Default General Failure in Nexpose::Wait'
8
+ @ready = false
9
+ @retry_count = retry_count.to_i
10
+ @timeout = timeout
10
11
  @polling_interval = polling_interval
11
12
  end
12
13
 
@@ -18,49 +19,49 @@ module Nexpose
18
19
  poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
19
20
  poller.wait(report_status_proc(nexpose_connection: nexpose_connection, report_id: report_id))
20
21
  @ready = true
21
- rescue TimeoutError
22
- @ready = false
23
- retry if timeout_retry?
24
- @error_message = "Timeout Waiting for Report to Generate - Report Config ID: #{report_id}"
25
- rescue NoMethodError => error
26
- @ready = false
27
- @error_message = "Error Report Config ID: #{report_id} :: Report Probably Does Not Exist :: #{error}"
28
- rescue => error
29
- @ready = false
30
- @error_message = "Error Report Config ID: #{report_id} :: #{error}"
22
+ rescue Timeout::Error
23
+ @ready = false
24
+ retry if timeout_retry?
25
+ @error_message = "Timeout Waiting for Report to Generate - Report Config ID: #{report_id}"
26
+ rescue NoMethodError => error
27
+ @ready = false
28
+ @error_message = "Error Report Config ID: #{report_id} :: Report Probably Does Not Exist :: #{error}"
29
+ rescue => error
30
+ @ready = false
31
+ @error_message = "Error Report Config ID: #{report_id} :: #{error}"
31
32
  end
32
33
 
33
34
  def for_integration(nexpose_connection:, scan_id:, status: 'finished')
34
35
  poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
35
36
  poller.wait(integration_status_proc(nexpose_connection: nexpose_connection, scan_id: scan_id, status: status))
36
37
  @ready = true
37
- rescue TimeoutError
38
- @ready = false
39
- retry if timeout_retry?
40
- @error_message = "Timeout Waiting for Integration Status of '#{status}' - Scan ID: #{scan_id}"
41
- rescue Nexpose::APIError => error
42
- @ready = false
43
- @error_message = "API Error Waiting for Integration Scan ID: #{scan_id} :: #{error.req.error}"
38
+ rescue Timeout::Error
39
+ @ready = false
40
+ retry if timeout_retry?
41
+ @error_message = "Timeout Waiting for Integration Status of '#{status}' - Scan ID: #{scan_id}"
42
+ rescue Nexpose::APIError => error
43
+ @ready = false
44
+ @error_message = "API Error Waiting for Integration Scan ID: #{scan_id} :: #{error.req.error}"
44
45
  end
45
46
 
46
47
  def for_judgment(proc:, desc:)
47
48
  poller = Nexpose::Poller.new(timeout: @timeout, polling_interval: @polling_interval)
48
49
  poller.wait(proc)
49
50
  @ready = true
50
- rescue TimeoutError
51
- @ready = false
52
- retry if timeout_retry?
53
- @error_message = "Timeout Waiting for Judgment to Judge. #{desc}"
51
+ rescue Timeout::Error
52
+ @ready = false
53
+ retry if timeout_retry?
54
+ @error_message = "Timeout Waiting for Judgment to Judge. #{desc}"
54
55
  end
55
56
 
56
57
  private
57
58
 
58
59
  def report_status_proc(nexpose_connection:, report_id:)
59
- Proc.new { nexpose_connection.last_report(report_id).status == 'Generated' }
60
+ proc { nexpose_connection.last_report(report_id).status == 'Generated' }
60
61
  end
61
62
 
62
63
  def integration_status_proc(nexpose_connection:, scan_id:, status:)
63
- Proc.new { nexpose_connection.scan_status(scan_id).downcase == status.downcase }
64
+ proc { nexpose_connection.scan_status(scan_id).downcase == status.downcase }
64
65
  end
65
66
 
66
67
  def timeout_retry?
@@ -71,6 +72,7 @@ module Nexpose
71
72
  false
72
73
  end
73
74
  end
75
+
74
76
  end
75
77
 
76
78
  class Poller
@@ -89,7 +91,7 @@ module Nexpose
89
91
  @poll_begin = Time.now
90
92
  loop do
91
93
  break if condition.call
92
- raise TimeoutError if @poll_begin + @timeout < Time.now
94
+ raise Timeout::Error if @poll_begin + @timeout < Time.now
93
95
  sleep @polling_interval
94
96
  end
95
97
  end
@@ -105,5 +107,7 @@ module Nexpose
105
107
  default_polling = 1
106
108
  ENV['GLOBAL_POLLING_INTERVAL'].nil? ? default_polling : ENV['GLOBAL_POLLING_INTERVAL']
107
109
  end
110
+
108
111
  end
112
+
109
113
  end
@@ -4,14 +4,13 @@ module Nexpose
4
4
  module WebCredentials
5
5
 
6
6
  module WebAppAuthType
7
- HTML_FORM = 'htmlform' # Represent HTML form credentials.
7
+ HTML_FORM = 'htmlform' # Represent HTML form credentials.
8
8
  HTTP_HEADER = 'httpheaders' # Represent HTTP header credentials.
9
9
  end
10
10
 
11
11
  # Object that represents Header name-value pairs, associated with Web Session Authentication.
12
12
  #
13
13
  class Header
14
-
15
14
  # Name, one per Header
16
15
  attr_reader :name
17
16
  # Value, one per Header
@@ -19,7 +18,7 @@ module Nexpose
19
18
 
20
19
  # Construct with name value pair
21
20
  def initialize(name, value)
22
- @name = name
21
+ @name = name
23
22
  @value = value
24
23
  end
25
24
 
@@ -28,16 +27,16 @@ module Nexpose
28
27
  end
29
28
 
30
29
  def to_h
31
- header = Hash.new
30
+ header = {}
32
31
  header[@name] = @value
33
32
  header
34
33
  end
34
+
35
35
  end
36
36
 
37
37
  # Object that represents Headers, associated with Web Session Authentication.
38
38
  #
39
39
  class Headers < APIObject
40
-
41
40
  # A regular expression used to match against the response to identify authentication failures.
42
41
  attr_reader :soft403Pattern
43
42
  # Base URL of the application for which the form authentication applies.
@@ -48,20 +47,19 @@ module Nexpose
48
47
  attr_reader :name
49
48
  # is this enable for the site configuration
50
49
  attr_accessor :enabled
51
- #service type of header
50
+ # service type of header
52
51
  attr_reader :service
53
52
  # id of the header
54
53
  attr_reader :id
55
54
 
56
-
57
55
  def initialize(name, baseURL, soft403Pattern, id = -1, enabled = true)
58
- @headers = {}
59
- @name = name
60
- @baseURL = baseURL
56
+ @headers = {}
57
+ @name = name
58
+ @baseURL = baseURL
61
59
  @soft403Pattern = soft403Pattern
62
- @service = WebAppAuthType::HTTP_HEADER
63
- @enabled = enabled
64
- @id = id
60
+ @service = WebAppAuthType::HTTP_HEADER
61
+ @enabled = enabled
62
+ @id = id
65
63
  end
66
64
 
67
65
  def add_header(header)
@@ -79,8 +77,7 @@ module Nexpose
79
77
  name: name,
80
78
  headers: headers,
81
79
  baseURL: baseURL,
82
- soft403Pattern: soft403Pattern
83
- }
80
+ soft403Pattern: soft403Pattern }
84
81
  end
85
82
 
86
83
  def ==(other)
@@ -96,7 +93,8 @@ module Nexpose
96
93
  baseURL.eql?(other.baseURL) &&
97
94
  soft403Pattern.eql?(other.soft403Pattern)
98
95
  end
99
- end
96
+
97
+ end
100
98
 
101
99
  # When using HTML form, this represents the login form information.
102
100
  #
@@ -116,9 +114,9 @@ module Nexpose
116
114
  attr_reader :checked
117
115
 
118
116
  def initialize(name, value, type, dynamic, checked)
119
- @name = name
120
- @value = value
121
- @type = type
117
+ @name = name
118
+ @value = value
119
+ @type = type
122
120
  @dynamic = dynamic
123
121
  @checked = checked
124
122
  end
@@ -136,12 +134,12 @@ module Nexpose
136
134
  checked: checked
137
135
  }
138
136
  end
137
+
139
138
  end
140
139
 
141
140
  # When using HTML form, this represents the login form information.
142
141
  #
143
142
  class HTMLForm
144
-
145
143
  # The name of the form being submitted.
146
144
  attr_reader :name
147
145
  # The HTTP action (URL) through which to submit the login form.
@@ -154,11 +152,11 @@ module Nexpose
154
152
  attr_reader :fields
155
153
 
156
154
  def initialize(name, action, method, encType)
157
- @name = name
158
- @action = action
159
- @method = method
155
+ @name = name
156
+ @action = action
157
+ @method = method
160
158
  @encType = encType
161
- @fields = []
159
+ @fields = []
162
160
  end
163
161
 
164
162
  def add_field(field)
@@ -175,9 +173,9 @@ module Nexpose
175
173
  method: method,
176
174
  encType: encType,
177
175
  fields: fields,
178
- parentPage: action
179
- }
176
+ parentPage: action }
180
177
  end
178
+
181
179
  end
182
180
 
183
181
  # When using HTML form, this represents the login form information.
@@ -194,7 +192,7 @@ module Nexpose
194
192
  attr_reader :name
195
193
  # is this enable for the site configuration
196
194
  attr_accessor :enabled
197
- #service type of header
195
+ # service type of header
198
196
  attr_reader :service
199
197
  # id of the header
200
198
  attr_reader :id
@@ -202,13 +200,13 @@ module Nexpose
202
200
  attr_reader :form
203
201
 
204
202
  def initialize(name, baseURL, loginURL, soft403Pattern, id = -1, enabled = true)
205
- @name = name
206
- @baseURL = baseURL
207
- @loginURL = loginURL
203
+ @name = name
204
+ @baseURL = baseURL
205
+ @loginURL = loginURL
208
206
  @soft403Pattern = soft403Pattern
209
- @service = WebAppAuthType::HTML_FORM
210
- @enabled = enabled
211
- @id = id
207
+ @service = WebAppAuthType::HTML_FORM
208
+ @enabled = enabled
209
+ @id = id
212
210
  end
213
211
 
214
212
  def add_html_form(html_form)
@@ -227,8 +225,7 @@ module Nexpose
227
225
  form: form.to_h,
228
226
  baseURL: baseURL,
229
227
  loginURL: loginURL,
230
- soft403Pattern: soft403Pattern
231
- }
228
+ soft403Pattern: soft403Pattern }
232
229
  end
233
230
 
234
231
  def ==(other)
@@ -247,6 +244,7 @@ module Nexpose
247
244
  end
248
245
 
249
246
  end
247
+
250
248
  end
251
- end
252
249
 
250
+ end