nexpose 7.0.0 → 7.0.1

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.
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
@@ -6,7 +6,7 @@ module Nexpose
6
6
  def list_tickets
7
7
  # TODO: Should take in filters as arguments.
8
8
  xml = make_xml('TicketListingRequest')
9
- r = execute(xml, '1.2')
9
+ r = execute(xml, '1.2')
10
10
  tickets = []
11
11
  if r.success
12
12
  r.res.elements.each('TicketListingResponse/TicketSummary') do |summary|
@@ -16,7 +16,7 @@ module Nexpose
16
16
  tickets
17
17
  end
18
18
 
19
- alias_method :tickets, :list_tickets
19
+ alias tickets list_tickets
20
20
 
21
21
  # Deletes a Nexpose ticket.
22
22
  #
@@ -57,8 +57,8 @@ module Nexpose
57
57
 
58
58
  # The asset the ticket is created for.
59
59
  attr_accessor :asset_id
60
- alias :device_id :asset_id
61
- alias :device_id= :asset_id=
60
+ alias device_id asset_id
61
+ alias device_id= asset_id=
62
62
 
63
63
  # The login name of person to whom the ticket is assigned.
64
64
  # The user must have view asset privilege on the asset specified in the asset-id attribute.
@@ -78,43 +78,43 @@ module Nexpose
78
78
  attr_accessor :state
79
79
 
80
80
  def initialize(name, id)
81
- @id, @name = id, name
81
+ @id = id
82
+ @name = name
82
83
  end
83
84
 
84
85
  def self.parse(xml)
85
- ticket = new(xml.attributes['name'],
86
- xml.attributes['id'].to_i)
87
- ticket.asset_id = xml.attributes['device-id'].to_i
88
- ticket.assigned_to = xml.attributes['assigned-to']
89
- lookup = Ticket::Priority.constants.reduce({}) { |a, e| a[Ticket::Priority.const_get(e)] = e; a }
90
- ticket.priority = lookup[xml.attributes['priority']]
91
- ticket.author = xml.attributes['author']
92
- ticket.created_on = DateTime.parse(xml.attributes['created-on']).to_time
86
+ ticket = new(xml.attributes['name'], xml.attributes['id'].to_i)
87
+ ticket.asset_id = xml.attributes['device-id'].to_i
88
+ ticket.assigned_to = xml.attributes['assigned-to']
89
+ lookup = Ticket::Priority.constants.reduce({}) { |a, e| a[Ticket::Priority.const_get(e)] = e; a }
90
+ ticket.priority = lookup[xml.attributes['priority']]
91
+ ticket.author = xml.attributes['author']
92
+ ticket.created_on = DateTime.parse(xml.attributes['created-on']).to_time
93
93
  ticket.created_on -= ticket.created_on.gmt_offset
94
- lookup = Ticket::State.constants.reduce({}) { |a, e| a[Ticket::State.const_get(e)] = e; a }
95
- ticket.state = lookup[xml.attributes['state']]
94
+ lookup = Ticket::State.constants.reduce({}) { |a, e| a[Ticket::State.const_get(e)] = e; a }
95
+ ticket.state = lookup[xml.attributes['state']]
96
96
  ticket
97
97
  end
98
98
 
99
99
  module State
100
- OPEN = 'O'
101
- ASSIGNED = 'A'
102
- MODIFIED = 'M'
103
- FIXED = 'X'
104
- PARTIAL = 'P'
105
- REJECTED_FIX = 'R'
106
- PRIORITIZED = 'Z'
100
+ OPEN = 'O'
101
+ ASSIGNED = 'A'
102
+ MODIFIED = 'M'
103
+ FIXED = 'X'
104
+ PARTIAL = 'P'
105
+ REJECTED_FIX = 'R'
106
+ PRIORITIZED = 'Z'
107
107
  NOT_REPRODUCIBLE = 'F'
108
- NOT_ISSUE = 'I'
109
- CLOSED = 'C'
110
- UNKNOWN = 'U'
108
+ NOT_ISSUE = 'I'
109
+ CLOSED = 'C'
110
+ UNKNOWN = 'U'
111
111
  end
112
112
 
113
113
  module Priority
114
- LOW = 'low'
114
+ LOW = 'low'
115
115
  MODERATE = 'moderate'
116
- NORMAL = 'normal'
117
- HIGH = 'high'
116
+ NORMAL = 'normal'
117
+ HIGH = 'high'
118
118
  CRITICAL = 'critical'
119
119
  end
120
120
  end
@@ -131,11 +131,12 @@ module Nexpose
131
131
  attr_accessor :history
132
132
 
133
133
  def initialize(name, id = nil)
134
- @id, @name = id, name
135
- @priority = Priority::NORMAL
134
+ @id = id
135
+ @name = name
136
+ @priority = Priority::NORMAL
136
137
  @vulnerabilities = []
137
- @comments = []
138
- @history = []
138
+ @comments = []
139
+ @history = []
139
140
  end
140
141
 
141
142
  # Save this ticket to a Nexpose console.
@@ -213,7 +214,7 @@ module Nexpose
213
214
  ticket.history << Event.parse(entry)
214
215
  end
215
216
 
216
- ticket.comments = ticket.history.select { |h| h.description == 'Added comment' }.map { |e| e.comment }
217
+ ticket.comments = ticket.history.select { |h| h.description == 'Added comment' }.map(&:comment)
217
218
 
218
219
  ticket
219
220
  end
@@ -232,22 +233,24 @@ module Nexpose
232
233
  attr_accessor :comment
233
234
 
234
235
  def initialize(state, author, created)
235
- @state, @author, @created = state, author, created
236
+ @state = state
237
+ @author = author
238
+ @created = created
236
239
  end
237
240
 
238
241
  def self.parse(xml)
239
- author = xml.attributes['author']
240
- created_on = DateTime.parse(xml.attributes['created-on']).to_time
242
+ author = xml.attributes['author']
243
+ created_on = DateTime.parse(xml.attributes['created-on']).to_time
241
244
  created_on -= created_on.gmt_offset
242
245
 
243
- event = REXML::XPath.first(xml, 'Event')
244
- lookup = Ticket::State.constants.reduce({}) { |a, e| a[Ticket::State.const_get(e)] = e; a }
245
- state = lookup[event.attributes['state']]
246
- desc = event.text
246
+ event = REXML::XPath.first(xml, 'Event')
247
+ lookup = Ticket::State.constants.reduce({}) { |a, e| a[Ticket::State.const_get(e)] = e; a }
248
+ state = lookup[event.attributes['state']]
249
+ desc = event.text
247
250
 
248
- event = new(state, author, created_on)
251
+ event = new(state, author, created_on)
249
252
 
250
- comment = REXML::XPath.first(xml, 'Comment')
253
+ comment = REXML::XPath.first(xml, 'Comment')
251
254
  event.comment = comment.text if comment
252
255
 
253
256
  event.description = desc if desc
@@ -18,7 +18,7 @@ module Nexpose
18
18
  arr
19
19
  end
20
20
 
21
- alias_method :users, :list_users
21
+ alias users list_users
22
22
 
23
23
  # Retrieve the User ID based upon the user's login name.
24
24
  #
@@ -47,16 +47,16 @@ module Nexpose
47
47
  attr_reader :is_admin, :is_disabled, :is_locked, :site_count, :group_count
48
48
 
49
49
  def initialize(id, auth_source, auth_module, name, full_name, email, is_admin, is_disabled, is_locked, site_count, group_count)
50
- @id = id
50
+ @id = id
51
51
  @auth_source = auth_source
52
52
  @auth_module = auth_module
53
- @name = name
54
- @full_name = full_name
55
- @email = email
56
- @is_admin = is_admin
53
+ @name = name
54
+ @full_name = full_name
55
+ @email = email
56
+ @is_admin = is_admin
57
57
  @is_disabled = is_disabled
58
- @is_locked = is_locked
59
- @site_count = site_count
58
+ @is_locked = is_locked
59
+ @site_count = site_count
60
60
  @group_count = group_count
61
61
  end
62
62
 
@@ -97,41 +97,41 @@ module Nexpose
97
97
  attr_accessor :all_sites, :all_groups
98
98
 
99
99
  def initialize(name, full_name, password, role_name = 'user', id = -1, enabled = 1, email = nil, all_sites = false, all_groups = false, token = nil)
100
- @name = name
101
- @password = password
102
- @token = token
103
- @role_name = role_name
104
- @authsrcid = ('global-admin'.eql? @role_name) ? '1' : '2'
105
- @id = id
106
- @enabled = enabled
107
- @full_name = full_name
108
- @email = email
109
- @all_sites = all_sites || role_name == 'global-admin'
100
+ @name = name
101
+ @password = password
102
+ @token = token
103
+ @role_name = role_name
104
+ @authsrcid = 'global-admin'.eql?(@role_name) ? '1' : '2'
105
+ @id = id
106
+ @enabled = enabled
107
+ @full_name = full_name
108
+ @email = email
109
+ @all_sites = all_sites || role_name == 'global-admin'
110
110
  @all_groups = all_groups || role_name == 'global-admin'
111
- @sites = []
112
- @groups = []
111
+ @sites = []
112
+ @groups = []
113
113
  end
114
114
 
115
115
  def to_xml
116
116
  xml = '<UserConfig'
117
- xml << %Q{ id="#{@id}"}
118
- xml << %Q{ authsrcid="#{@authsrcid}"}
119
- xml << %Q{ name="#{replace_entities(@name)}"}
120
- xml << %Q{ fullname="#{replace_entities(@full_name)}"}
121
- xml << %Q{ role-name="#{replace_entities(@role_name)}"}
122
- xml << %Q{ password="#{replace_entities(@password)}"} if @password
123
- xml << %Q{ token="#{replace_entities(@token)}"} if @token
124
- xml << %Q{ email="#{replace_entities(@email)}"} if @email
125
- xml << %Q{ enabled="#{@enabled}"}
117
+ xml << %( id="#{@id}" )
118
+ xml << %( authsrcid="#{@authsrcid}" )
119
+ xml << %( name="#{replace_entities(@name)}" )
120
+ xml << %( fullname="#{replace_entities(@full_name)}" )
121
+ xml << %( role-name="#{replace_entities(@role_name)}" )
122
+ xml << %( password="#{replace_entities(@password)}" ) if @password
123
+ xml << %( token="#{replace_entities(@token)}" ) if @token
124
+ xml << %( email="#{replace_entities(@email)}" ) if @email
125
+ xml << %( enabled="#{@enabled}" )
126
126
  # These two fields are keying off role_name to work around a defect.
127
- xml << %Q{ allGroups="#{@all_groups || @role_name == 'global-admin'}"}
128
- xml << %Q{ allSites="#{@all_sites || @role_name == 'global-admin'}"}
127
+ xml << %( allGroups="#{@all_groups || @role_name == 'global-admin'}" )
128
+ xml << %( allSites="#{@all_sites || @role_name == 'global-admin'}" )
129
129
  xml << '>'
130
130
  @sites.each do |site|
131
- xml << %Q{<site id="#{site}" />}
131
+ xml << %( <site id="#{site}" /> )
132
132
  end
133
133
  @groups.each do |group|
134
- xml << %Q{<group id="#{group}" />}
134
+ xml << %( <group id="#{group}" /> )
135
135
  end
136
136
  xml << '</UserConfig>'
137
137
  end
@@ -155,22 +155,22 @@ module Nexpose
155
155
  # Issue a UserConfigRequest to load an existing UserConfig from Nexpose.
156
156
  def self.load(connection, user_id)
157
157
  xml = '<UserConfigRequest session-id="' + connection.session_id + '"'
158
- xml << %Q{ id="#{user_id}"}
158
+ xml << %( id="#{user_id}" )
159
159
  xml << ' />'
160
160
  r = connection.execute(xml, '1.1')
161
161
  if r.success
162
162
  r.res.elements.each('UserConfigResponse/UserConfig') do |config|
163
- id = config.attributes['id']
164
- role_name = config.attributes['role-name']
165
- #authsrcid = config.attributes['authsrcid']
166
- name = config.attributes['name']
167
- fullname = config.attributes['fullname']
168
-
169
- email = config.attributes['email']
170
- password = config.attributes['password']
171
- token = config.attributes['token']
172
- enabled = config.attributes['enabled'].to_i
173
- all_sites = config.attributes['allSites'] == 'true' ? true : false
163
+ id = config.attributes['id']
164
+ role_name = config.attributes['role-name']
165
+ # authsrcid = config.attributes['authsrcid']
166
+ name = config.attributes['name']
167
+ fullname = config.attributes['fullname']
168
+
169
+ email = config.attributes['email']
170
+ password = config.attributes['password']
171
+ token = config.attributes['token']
172
+ enabled = config.attributes['enabled'].to_i
173
+ all_sites = config.attributes['allSites'] == 'true' ? true : false
174
174
  all_groups = config.attributes['allGroups'] == 'true' ? true : false
175
175
  # Not trying to load sites and groups.
176
176
  # Looks like API currently doesn't return that info to load.
@@ -30,7 +30,7 @@ module Nexpose
30
30
  # '1' if the call succeeded.
31
31
  #
32
32
  def self.success?(xml_string)
33
- xml = ::REXML::Document.new(xml_string.to_s)
33
+ xml = ::REXML::Document.new(xml_string.to_s)
34
34
  success = ::REXML::XPath.first(xml, '//@success')
35
35
  !success.nil? && success.value.to_i == 1
36
36
  end
@@ -1,4 +1,4 @@
1
1
  module Nexpose
2
2
  # The latest version of the Nexpose gem
3
- VERSION = '7.0.0'
3
+ VERSION = '7.0.1'.freeze
4
4
  end
@@ -20,15 +20,15 @@ module Nexpose
20
20
  vulns << XML::VulnerabilitySummary.parse(vuln)
21
21
  else
22
22
  vulns << XML::Vulnerability.new(vuln.attributes['id'],
23
- vuln.attributes['title'],
24
- vuln.attributes['severity'].to_i)
23
+ vuln.attributes['title'],
24
+ vuln.attributes['severity'].to_i)
25
25
  end
26
26
  end
27
27
  end
28
28
  vulns
29
29
  end
30
30
 
31
- alias_method :vulns, :list_vulns
31
+ alias vulns list_vulns
32
32
 
33
33
  # Retrieve a list of the different vulnerability check categories.
34
34
  #
@@ -39,7 +39,7 @@ module Nexpose
39
39
  data.map { |c| c['Category'] }
40
40
  end
41
41
 
42
- alias_method :vuln_categories, :list_vuln_categories
42
+ alias vuln_categories list_vuln_categories
43
43
 
44
44
  # Retrieve a list of the different vulnerability check types.
45
45
  #
@@ -49,7 +49,7 @@ module Nexpose
49
49
  data = DataTable._get_dyn_table(self, '/data/vulnerability/checktypes/dyntable.xml?tableID=VulnCheckCategorySynopsis')
50
50
  data.map { |c| c['Category'] }
51
51
  end
52
- alias_method :list_vuln_types, :vuln_types
52
+ alias list_vuln_types vuln_types
53
53
 
54
54
  # Retrieve details for a vulnerability.
55
55
  #
@@ -111,7 +111,9 @@ module Nexpose
111
111
  attr_reader :severity
112
112
 
113
113
  def initialize(id, title, severity)
114
- @id, @title, @severity = id, title, severity.to_i
114
+ @id = id
115
+ @title = title
116
+ @severity = severity.to_i
115
117
  end
116
118
  end
117
119
 
@@ -126,10 +128,10 @@ module Nexpose
126
128
  attr_reader :check_type
127
129
 
128
130
  def initialize(json)
129
- @id = json['Vuln ID']
130
- @check_id = json['Vuln Check ID']
131
- @title = json['Vulnerability']
132
- @severity = json['Severity'].to_i
131
+ @id = json['Vuln ID']
132
+ @check_id = json['Vuln Check ID']
133
+ @title = json['Vulnerability']
134
+ @severity = json['Severity'].to_i
133
135
  @check_type = json['Check Type']
134
136
  @categories = json['Category'].split(/, */)
135
137
  end
@@ -165,15 +167,15 @@ module Nexpose
165
167
  xml.attributes['severity'].to_i)
166
168
 
167
169
  vuln.pci_severity = xml.attributes['pciSeverity'].to_i
168
- vuln.safe = xml.attributes['safe'] == 'true' # or xml.attributes['safe'] == '1'
169
- vuln.added = Date.parse(xml.attributes['added'])
170
- vuln.modified = Date.parse(xml.attributes['modified'])
171
- vuln.credentials = xml.attributes['requiresCredentials'] == 'true'
170
+ vuln.safe = xml.attributes['safe'] == 'true' # or xml.attributes['safe'] == '1'
171
+ vuln.added = Date.parse(xml.attributes['added'])
172
+ vuln.modified = Date.parse(xml.attributes['modified'])
173
+ vuln.credentials = xml.attributes['requiresCredentials'] == 'true'
172
174
 
173
175
  # These three fields are optional in the XSD.
174
- vuln.published = Date.parse(xml.attributes['published']) if xml.attributes['published']
175
- vuln.cvss_vector = xml.attributes['cvssVector'] if xml.attributes['cvssVector']
176
- vuln.cvss_score = xml.attributes['cvssScore'].to_f if xml.attributes['cvssScore']
176
+ vuln.published = Date.parse(xml.attributes['published']) if xml.attributes['published']
177
+ vuln.cvss_vector = xml.attributes['cvssVector'] if xml.attributes['cvssVector']
178
+ vuln.cvss_score = xml.attributes['cvssScore'].to_f if xml.attributes['cvssScore']
177
179
  vuln
178
180
  end
179
181
 
@@ -194,16 +196,16 @@ module Nexpose
194
196
  attr_accessor :solution
195
197
 
196
198
  def initialize(id, title, severity)
197
- @id, @title, @severity = id, title, severity
199
+ @id = id
200
+ @title = title
201
+ @severity = severity
198
202
  @references = []
199
203
  end
200
204
 
201
205
  def self.parse(xml)
202
- vuln = parse_attributes(xml)
203
-
206
+ vuln = parse_attributes(xml)
204
207
  vuln.description = REXML::XPath.first(xml, 'description').text
205
- vuln.solution = REXML::XPath.first(xml, 'solution').text
206
-
208
+ vuln.solution = REXML::XPath.first(xml, 'solution').text
207
209
  xml.elements.each('references/reference') do |ref|
208
210
  vuln.references << Reference.new(ref.attributes['source'], ref.text)
209
211
  end
@@ -218,7 +220,7 @@ module Nexpose
218
220
  attr_reader :reference
219
221
 
220
222
  def initialize(source, reference)
221
- @source = source
223
+ @source = source
222
224
  @reference = reference
223
225
  end
224
226
  end
@@ -251,18 +253,18 @@ module Nexpose
251
253
  attr_reader :verified
252
254
 
253
255
  def initialize(json)
254
- @id = json['nexVulnID']
255
- @console_id = json['vulnID']
256
- @title = json['title']
256
+ @id = json['nexVulnID']
257
+ @console_id = json['vulnID']
258
+ @title = json['title']
257
259
  @cvss_vector = json['cvssBase']
258
- @cvss_score = json['cvssScore']
259
- @risk = json['riskScore']
260
- @published = Time.at(json['publishedDate'] / 1000)
261
- @severity = json['severity']
262
- @instances = json['vulnInstanceCount']
263
- @exploit = json['mainExploit']
264
- @malware = json['malwareCount']
265
- @verified = DateTime.iso8601(json['verifiedDate'].slice(0, 15)).to_time if json['verifiedDate']
260
+ @cvss_score = json['cvssScore']
261
+ @risk = json['riskScore']
262
+ @published = Time.at(json['publishedDate'] / 1000)
263
+ @severity = json['severity']
264
+ @instances = json['vulnInstanceCount']
265
+ @exploit = json['mainExploit']
266
+ @malware = json['malwareCount']
267
+ @verified = DateTime.iso8601(json['verifiedDate'].slice(0, 15)).to_time if json['verifiedDate']
266
268
  end
267
269
  end
268
270
 
@@ -272,16 +274,16 @@ module Nexpose
272
274
  #
273
275
  class VulnSynopsis < VulnFinding
274
276
  def initialize(hash)
275
- @id = hash['Vuln ID'].to_i
276
- @title = hash['Vulnerability']
277
+ @id = hash['Vuln ID'].to_i
278
+ @title = hash['Vulnerability']
277
279
  @cvss_vector = hash['CVSS Base Vector']
278
- @cvss_score = hash['CVSS Score'].to_f
279
- @risk = hash['Risk'].to_f
280
- @published = Time.at(hash['Published On'].to_i / 1000)
281
- @severity = hash['Severity'].to_i
282
- @instances = hash['Instances'].to_i
283
- @exploit = hash['ExploitSource']
284
- @malware = hash['MalwareSource'] == 'true'
280
+ @cvss_score = hash['CVSS Score'].to_f
281
+ @risk = hash['Risk'].to_f
282
+ @published = Time.at(hash['Published On'].to_i / 1000)
283
+ @severity = hash['Severity'].to_i
284
+ @instances = hash['Instances'].to_i
285
+ @exploit = hash['ExploitSource']
286
+ @malware = hash['MalwareSource'] == 'true'
285
287
  end
286
288
  end
287
289