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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -3
- data/Gemfile.lock +1 -1
- data/lib/nexpose/ajax.rb +12 -16
- data/lib/nexpose/alert.rb +20 -21
- data/lib/nexpose/api.rb +3 -3
- data/lib/nexpose/asset.rb +23 -23
- data/lib/nexpose/blackout.rb +6 -14
- data/lib/nexpose/common.rb +87 -92
- data/lib/nexpose/connection.rb +8 -10
- data/lib/nexpose/console.rb +9 -9
- data/lib/nexpose/dag.rb +2 -2
- data/lib/nexpose/data_table.rb +8 -12
- data/lib/nexpose/device.rb +35 -34
- data/lib/nexpose/discovery.rb +69 -69
- data/lib/nexpose/discovery/filter.rb +7 -8
- data/lib/nexpose/engine.rb +22 -21
- data/lib/nexpose/error.rb +7 -5
- data/lib/nexpose/external.rb +21 -16
- data/lib/nexpose/filter.rb +51 -52
- data/lib/nexpose/global_blackout.rb +6 -7
- data/lib/nexpose/global_settings.rb +2 -3
- data/lib/nexpose/group.rb +25 -19
- data/lib/nexpose/json_serializer.rb +4 -14
- data/lib/nexpose/maint.rb +8 -9
- data/lib/nexpose/manage.rb +2 -2
- data/lib/nexpose/multi_tenant_user.rb +42 -42
- data/lib/nexpose/password_policy.rb +14 -14
- data/lib/nexpose/pool.rb +6 -5
- data/lib/nexpose/report.rb +30 -34
- data/lib/nexpose/report_template.rb +17 -18
- data/lib/nexpose/role.rb +64 -55
- data/lib/nexpose/scan.rb +77 -60
- data/lib/nexpose/scan_template.rb +17 -17
- data/lib/nexpose/scheduled_backup.rb +8 -8
- data/lib/nexpose/scheduled_maintenance.rb +9 -9
- data/lib/nexpose/shared_credential.rb +30 -33
- data/lib/nexpose/shared_secret.rb +5 -5
- data/lib/nexpose/silo.rb +68 -66
- data/lib/nexpose/silo_profile.rb +47 -50
- data/lib/nexpose/site.rb +101 -123
- data/lib/nexpose/site_credentials.rb +15 -17
- data/lib/nexpose/tag.rb +73 -80
- data/lib/nexpose/ticket.rb +45 -42
- data/lib/nexpose/user.rb +45 -45
- data/lib/nexpose/util.rb +1 -1
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/vuln.rb +45 -43
- data/lib/nexpose/vuln_def.rb +7 -7
- data/lib/nexpose/vuln_exception.rb +35 -36
- data/lib/nexpose/wait.rb +32 -28
- data/lib/nexpose/web_credentials.rb +34 -36
- metadata +2 -2
@@ -19,9 +19,8 @@ module Nexpose
|
|
19
19
|
# Private constructor. See #load method for retrieving a settings object.
|
20
20
|
#
|
21
21
|
def initialize(xml)
|
22
|
-
@xml
|
23
|
-
|
24
|
-
@asset_linking = parse_asset_linking_from_xml(xml)
|
22
|
+
@xml = xml
|
23
|
+
@asset_linking = parse_asset_linking_from_xml(xml)
|
25
24
|
@asset_exclusions = HostOrIP.parse(xml)
|
26
25
|
@control_scanning = parse_control_scanning_from_xml(xml)
|
27
26
|
end
|
data/lib/nexpose/group.rb
CHANGED
@@ -10,11 +10,11 @@ module Nexpose
|
|
10
10
|
# @return [Boolean] Whether group deletion succeeded.
|
11
11
|
#
|
12
12
|
def delete_asset_group(id)
|
13
|
-
r = execute(make_xml('AssetGroupDeleteRequest', {'group-id' => id}))
|
13
|
+
r = execute(make_xml('AssetGroupDeleteRequest', { 'group-id' => id }))
|
14
14
|
r.success
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
alias delete_group delete_asset_group
|
18
18
|
|
19
19
|
# Retrieve an array of all asset groups the user is authorized to view or
|
20
20
|
# manage.
|
@@ -23,7 +23,6 @@ module Nexpose
|
|
23
23
|
#
|
24
24
|
def list_asset_groups
|
25
25
|
r = execute(make_xml('AssetGroupListingRequest'))
|
26
|
-
|
27
26
|
groups = []
|
28
27
|
if r.success
|
29
28
|
r.res.elements.each('AssetGroupListingResponse/AssetGroupSummary') do |group|
|
@@ -37,8 +36,8 @@ module Nexpose
|
|
37
36
|
groups
|
38
37
|
end
|
39
38
|
|
40
|
-
|
41
|
-
|
39
|
+
alias groups list_asset_groups
|
40
|
+
alias asset_groups list_asset_groups
|
42
41
|
end
|
43
42
|
|
44
43
|
# Summary value object for asset group information.
|
@@ -47,7 +46,11 @@ module Nexpose
|
|
47
46
|
attr_reader :id, :name, :description, :risk_score, :dynamic
|
48
47
|
|
49
48
|
def initialize(id, name, desc, risk, dynamic)
|
50
|
-
@id
|
49
|
+
@id = id
|
50
|
+
@name = name
|
51
|
+
@description = desc
|
52
|
+
@risk_score = risk
|
53
|
+
@dynamic = dynamic
|
51
54
|
end
|
52
55
|
|
53
56
|
def dynamic?
|
@@ -68,17 +71,20 @@ module Nexpose
|
|
68
71
|
class AssetGroup < AssetGroupSummary
|
69
72
|
include Sanitize
|
70
73
|
|
71
|
-
attr_accessor :name, :description, :id
|
74
|
+
attr_accessor :name, :description, :id, :tags
|
72
75
|
|
73
76
|
# Array[Device] of devices associated with this asset group.
|
74
77
|
attr_accessor :assets
|
75
|
-
alias
|
76
|
-
alias
|
78
|
+
alias devices assets
|
79
|
+
alias devices= assets=
|
77
80
|
|
78
81
|
def initialize(name, desc, id = -1, risk = 0.0)
|
79
|
-
@name
|
80
|
-
@
|
81
|
-
@
|
82
|
+
@name = name
|
83
|
+
@description = desc
|
84
|
+
@id = id
|
85
|
+
@risk_score = risk
|
86
|
+
@assets = []
|
87
|
+
@tags = []
|
82
88
|
end
|
83
89
|
|
84
90
|
def save(connection)
|
@@ -86,7 +92,7 @@ module Nexpose
|
|
86
92
|
xml << to_xml
|
87
93
|
xml << '</AssetGroupSaveRequest>'
|
88
94
|
res = connection.execute(xml)
|
89
|
-
@id = res.attributes['group-id'].to_i if res.success
|
95
|
+
@id = res.attributes['group-id'].to_i if res.success && @id < 1
|
90
96
|
end
|
91
97
|
|
92
98
|
# Generate an XML representation of this group configuration
|
@@ -95,8 +101,8 @@ module Nexpose
|
|
95
101
|
#
|
96
102
|
def as_xml
|
97
103
|
xml = REXML::Element.new('AssetGroup')
|
98
|
-
xml.attributes['id']
|
99
|
-
xml.attributes['name']
|
104
|
+
xml.attributes['id'] = @id
|
105
|
+
xml.attributes['name'] = @name
|
100
106
|
xml.attributes['description'] = @description
|
101
107
|
|
102
108
|
if @description && !@description.empty?
|
@@ -106,7 +112,7 @@ module Nexpose
|
|
106
112
|
end
|
107
113
|
|
108
114
|
elem = REXML::Element.new('Devices')
|
109
|
-
@assets.each { |a| elem.add_element('device', {'id' => a.id}) }
|
115
|
+
@assets.each { |a| elem.add_element('device', { 'id' => a.id }) }
|
110
116
|
xml.add_element(elem)
|
111
117
|
|
112
118
|
unless tags.empty?
|
@@ -134,8 +140,8 @@ module Nexpose
|
|
134
140
|
# @return [Hash] Hash of site ID to Scan launch information for each scan.
|
135
141
|
#
|
136
142
|
def rescan_assets(connection)
|
137
|
-
|
138
|
-
|
143
|
+
scans = {}
|
144
|
+
sites_ids = @assets.map(&:site_id).uniq
|
139
145
|
sites_ids.each do |site_id|
|
140
146
|
to_scan = @assets.select { |d| d.site_id == site_id }
|
141
147
|
scans[site_id] = connection.scan_devices(to_scan)
|
@@ -153,7 +159,7 @@ module Nexpose
|
|
153
159
|
#
|
154
160
|
def self.load(connection, id)
|
155
161
|
xml = %(<AssetGroupConfigRequest session-id="#{connection.session_id}" group-id="#{id}"/>)
|
156
|
-
r
|
162
|
+
r = APIRequest.execute(connection.url, xml)
|
157
163
|
parse(r.res)
|
158
164
|
end
|
159
165
|
|
@@ -6,13 +6,11 @@ module Nexpose
|
|
6
6
|
data.each do |key, value|
|
7
7
|
if respond_to?(key)
|
8
8
|
property = value
|
9
|
-
|
10
9
|
if value.respond_to? :each
|
11
10
|
obj = resolve_type(key)
|
12
|
-
|
13
11
|
unless obj.nil?
|
14
12
|
if value.is_a?(Array)
|
15
|
-
property = value.map { |dv|
|
13
|
+
property = value.map { |dv| ((dv.respond_to? :each) ? create_object(obj, dv).deserialize(dv) : dv) }
|
16
14
|
else
|
17
15
|
property = create_object(obj, value).deserialize(value)
|
18
16
|
end
|
@@ -20,20 +18,15 @@ module Nexpose
|
|
20
18
|
elsif value.is_a?(String) && value.match(/^\d{8}T\d{6}\.\d{3}/)
|
21
19
|
property = ISO8601.to_time(value)
|
22
20
|
end
|
23
|
-
|
24
21
|
instance_variable_set("@#{key}", property)
|
25
22
|
end
|
26
23
|
end
|
27
|
-
|
28
24
|
self
|
29
25
|
end
|
30
26
|
|
31
|
-
def serialize
|
27
|
+
def serialize
|
32
28
|
hash = to_hash(Hash.new)
|
33
|
-
|
34
|
-
unless hash.nil?
|
35
|
-
JSON.generate(hash)
|
36
|
-
end
|
29
|
+
JSON.generate(hash) unless hash.nil?
|
37
30
|
end
|
38
31
|
|
39
32
|
def to_hash(hash)
|
@@ -41,7 +34,6 @@ module Nexpose
|
|
41
34
|
value = self.instance_variable_get(m)
|
42
35
|
hash[m.to_s.delete('@')] = do_hash(value)
|
43
36
|
end
|
44
|
-
|
45
37
|
hash
|
46
38
|
end
|
47
39
|
|
@@ -51,12 +43,10 @@ module Nexpose
|
|
51
43
|
if obj.is_a?(Array)
|
52
44
|
obj = obj.map do |el|
|
53
45
|
do_hash(el)
|
54
|
-
|
55
46
|
end
|
56
47
|
elsif obj.class.included_modules.include? JsonSerializer
|
57
48
|
obj = obj.to_hash(Hash.new)
|
58
49
|
end
|
59
|
-
|
60
50
|
obj
|
61
51
|
end
|
62
52
|
|
@@ -89,4 +79,4 @@ module Nexpose
|
|
89
79
|
class_name
|
90
80
|
end
|
91
81
|
end
|
92
|
-
end
|
82
|
+
end
|
data/lib/nexpose/maint.rb
CHANGED
@@ -46,11 +46,10 @@ module Nexpose
|
|
46
46
|
#
|
47
47
|
def db_maintenance(clean_up = false, compress = false, reindex = false)
|
48
48
|
return unless compress || clean_up || reindex
|
49
|
-
parameters = { 'cmd' => 'startMaintenance',
|
50
|
-
|
51
|
-
parameters['cleanup'] = 1 if clean_up
|
49
|
+
parameters = { 'cmd' => 'startMaintenance', 'targetTask' => 'dbMaintenance' }
|
50
|
+
parameters['cleanup'] = 1 if clean_up
|
52
51
|
parameters['compress'] = 1 if compress
|
53
|
-
parameters['reindex']
|
52
|
+
parameters['reindex'] = 1 if reindex
|
54
53
|
xml = AJAX.form_post(self, '/admin/global/maintenance/maintCmd.txml', parameters)
|
55
54
|
if !!(xml =~ /succeded="true"/)
|
56
55
|
_maintenance_restart
|
@@ -85,12 +84,12 @@ module Nexpose
|
|
85
84
|
attr_reader :size
|
86
85
|
|
87
86
|
def initialize(name, date, description, version, independent, size)
|
88
|
-
@name
|
89
|
-
@date
|
90
|
-
@description
|
91
|
-
@version
|
87
|
+
@name = name
|
88
|
+
@date = date
|
89
|
+
@description = description
|
90
|
+
@version = version
|
92
91
|
@platform_independent = independent
|
93
|
-
@size
|
92
|
+
@size = size
|
94
93
|
end
|
95
94
|
|
96
95
|
# Restore this backup to the Nexpose console.
|
data/lib/nexpose/manage.rb
CHANGED
@@ -47,9 +47,9 @@ module Nexpose
|
|
47
47
|
# Includes Product, Content, and Java versions.
|
48
48
|
#
|
49
49
|
def engine_versions
|
50
|
-
info
|
50
|
+
info = console_command('version engines')
|
51
51
|
versions = []
|
52
|
-
engines
|
52
|
+
engines = info.sub('VERSION INFORMATION\n', '').split(/\n\n/)
|
53
53
|
engines.each do |eng|
|
54
54
|
engdata = {}
|
55
55
|
eng.split(/\n/).each do |kv|
|
@@ -17,14 +17,14 @@ module Nexpose
|
|
17
17
|
end
|
18
18
|
arr
|
19
19
|
end
|
20
|
-
|
20
|
+
alias silo_users list_silo_users
|
21
21
|
|
22
22
|
# Delete the specified silo user
|
23
23
|
#
|
24
24
|
# @return Whether or not the delete request succeeded.
|
25
25
|
#
|
26
26
|
def delete_silo_user(user_id)
|
27
|
-
r = execute(make_xml('MultiTenantUserDeleteRequest', {'user-id' => user_id}), '1.2')
|
27
|
+
r = execute(make_xml('MultiTenantUserDeleteRequest', { 'user-id' => user_id }), '1.2')
|
28
28
|
r.success
|
29
29
|
end
|
30
30
|
end
|
@@ -42,21 +42,21 @@ module Nexpose
|
|
42
42
|
attr_reader :locked
|
43
43
|
|
44
44
|
def initialize(&block)
|
45
|
-
instance_eval
|
45
|
+
instance_eval(&block) if block_given?
|
46
46
|
end
|
47
47
|
|
48
48
|
def self.parse(xml)
|
49
49
|
new do
|
50
|
-
@id
|
51
|
-
@full_name
|
52
|
-
@user_name
|
53
|
-
@email
|
54
|
-
@superuser
|
55
|
-
@enabled
|
50
|
+
@id = xml.attributes['id'].to_i
|
51
|
+
@full_name = xml.attributes['full-name']
|
52
|
+
@user_name = xml.attributes['user-name']
|
53
|
+
@email = xml.attributes['email']
|
54
|
+
@superuser = xml.attributes['superuser'].to_s.chomp.eql?('true')
|
55
|
+
@enabled = xml.attributes['enabled'].to_s.chomp.eql?('true')
|
56
56
|
@auth_module = xml.attributes['auth-module']
|
57
57
|
@auth_source = xml.attributes['auth-source']
|
58
|
-
@silo_count
|
59
|
-
@locked
|
58
|
+
@silo_count = xml.attributes['silo-count'].to_i
|
59
|
+
@locked = xml.attributes['locked'].to_s.chomp.eql?('true')
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -73,13 +73,13 @@ module Nexpose
|
|
73
73
|
attr_accessor :silo_access
|
74
74
|
|
75
75
|
def initialize(&block)
|
76
|
-
instance_eval
|
76
|
+
instance_eval(&block) if block_given?
|
77
77
|
|
78
78
|
@silo_access = Array(@silo_access)
|
79
79
|
end
|
80
80
|
|
81
81
|
def save(connection)
|
82
|
-
if
|
82
|
+
if @id
|
83
83
|
update(connection)
|
84
84
|
else
|
85
85
|
create(connection)
|
@@ -112,14 +112,14 @@ module Nexpose
|
|
112
112
|
|
113
113
|
def as_xml
|
114
114
|
xml = REXML::Element.new('MultiTenantUserConfig')
|
115
|
-
xml.add_attributes({'id'
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
115
|
+
xml.add_attributes({ 'id' => @id,
|
116
|
+
'full-name' => @full_name,
|
117
|
+
'user-name' => @user_name,
|
118
|
+
'authsrcid' => @auth_source_id,
|
119
|
+
'email' => @email,
|
120
|
+
'password' => @password,
|
121
|
+
'superuser' => @superuser,
|
122
|
+
'enabled' => @enabled })
|
123
123
|
siloaccesses = xml.add_element('SiloAccesses')
|
124
124
|
@silo_access.each { |silo_access| siloaccesses.add_element(silo_access.as_xml) }
|
125
125
|
xml
|
@@ -135,20 +135,20 @@ module Nexpose
|
|
135
135
|
|
136
136
|
def self.parse(xml)
|
137
137
|
new do |user|
|
138
|
-
user.id
|
139
|
-
user.full_name
|
140
|
-
user.user_name
|
141
|
-
user.email
|
142
|
-
user.superuser
|
143
|
-
user.enabled
|
138
|
+
user.id = xml.attributes['id'].to_i
|
139
|
+
user.full_name = xml.attributes['full-name']
|
140
|
+
user.user_name = xml.attributes['user-name']
|
141
|
+
user.email = xml.attributes['email']
|
142
|
+
user.superuser = xml.attributes['superuser'].to_s.chomp.eql?('true')
|
143
|
+
user.enabled = xml.attributes['enabled'].to_s.chomp.eql?('true')
|
144
144
|
user.auth_source_id = xml.attributes['authsrcid'].to_i
|
145
|
-
user.silo_access
|
145
|
+
user.silo_access = []
|
146
146
|
xml.elements.each('SiloAccesses/SiloAccess') { |access| user.silo_access << SiloAccess.parse(access) }
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
150
|
def self.load(connection, user_id)
|
151
|
-
r = connection.execute(connection.make_xml('MultiTenantUserConfigRequest', {'user-id' => user_id}), '1.2')
|
151
|
+
r = connection.execute(connection.make_xml('MultiTenantUserConfigRequest', { 'user-id' => user_id }), '1.2')
|
152
152
|
|
153
153
|
if r.success
|
154
154
|
r.res.elements.each('MultiTenantUserConfigResponse/MultiTenantUserConfig') do |config|
|
@@ -169,30 +169,30 @@ module Nexpose
|
|
169
169
|
attr_accessor :groups
|
170
170
|
|
171
171
|
def initialize(&block)
|
172
|
-
instance_eval
|
172
|
+
instance_eval(&block) if block_given?
|
173
173
|
@sites = Array(@sites)
|
174
174
|
@groups = Array(@groups)
|
175
175
|
end
|
176
176
|
|
177
177
|
def as_xml
|
178
178
|
xml = REXML::Element.new('SiloAccess')
|
179
|
-
xml.add_attributes({'all-groups'
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
179
|
+
xml.add_attributes({ 'all-groups' => @all_groups,
|
180
|
+
'all-sites' => @all_sites,
|
181
|
+
'role-name' => @role_name,
|
182
|
+
'silo-id' => @silo_id,
|
183
|
+
'default-silo' => @default })
|
184
184
|
|
185
185
|
unless @groups.empty?
|
186
186
|
groups = xml.add_element('AllowedGroups')
|
187
187
|
@groups.each do |group|
|
188
|
-
groups.add_element('AllowedGroup', {'id' => group})
|
188
|
+
groups.add_element('AllowedGroup', { 'id' => group })
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
192
|
unless @sites.empty?
|
193
193
|
sites = xml.add_element('AllowedSites')
|
194
194
|
@sites.each do |site|
|
195
|
-
sites.add_element('AllowedSite', {'id' => site})
|
195
|
+
sites.add_element('AllowedSite', { 'id' => site })
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
@@ -206,11 +206,11 @@ module Nexpose
|
|
206
206
|
def self.parse(xml)
|
207
207
|
new do |access|
|
208
208
|
access.all_groups = xml.attributes['all-groups'].to_s.chomp.eql?('true')
|
209
|
-
access.all_sites
|
210
|
-
access.role_name
|
211
|
-
access.silo_id
|
212
|
-
access.default
|
213
|
-
access.sites
|
209
|
+
access.all_sites = xml.attributes['all-sites'].to_s.chomp.eql?('true')
|
210
|
+
access.role_name = xml.attributes['role-name']
|
211
|
+
access.silo_id = xml.attributes['silo-id']
|
212
|
+
access.default = xml.attributes['default-silo'].to_s.chomp.eql?('true')
|
213
|
+
access.sites = []
|
214
214
|
xml.elements.each('AllowedSites/AllowedSite') { |site| access.sites << site.attributes['id'].to_i }
|
215
215
|
access.groups = []
|
216
216
|
xml.elements.each('AllowedGroups/AllowedGroup') { |group| access.groups << group.attributes['id'].to_i }
|
@@ -11,12 +11,12 @@ module Nexpose
|
|
11
11
|
attr_accessor :expiration_days
|
12
12
|
|
13
13
|
def initialize(policy_name:, min_length:, max_length:, special_chars:, capitals:, digits:, expiration_days: 0)
|
14
|
-
@policy_name
|
15
|
-
@min_length
|
16
|
-
@max_length
|
17
|
-
@special_chars
|
18
|
-
@capitals
|
19
|
-
@digits
|
14
|
+
@policy_name = policy_name.to_s
|
15
|
+
@min_length = min_length.to_i
|
16
|
+
@max_length = max_length.to_i
|
17
|
+
@special_chars = special_chars.to_i
|
18
|
+
@capitals = capitals.to_i
|
19
|
+
@digits = digits.to_i
|
20
20
|
@expiration_days = expiration_days.to_i
|
21
21
|
end
|
22
22
|
|
@@ -32,13 +32,13 @@ module Nexpose
|
|
32
32
|
|
33
33
|
def to_h
|
34
34
|
{
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
policyName: @policy_name,
|
36
|
+
minLength: @min_length,
|
37
|
+
maxLength: @max_length,
|
38
|
+
specialChars: @special_chars,
|
39
|
+
capitals: @capitals,
|
40
|
+
digits: @digits,
|
41
|
+
expirationDays: @expiration_days
|
42
42
|
}
|
43
43
|
end
|
44
44
|
|
@@ -52,7 +52,7 @@ module Nexpose
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def self.load(nsc)
|
55
|
-
uri
|
55
|
+
uri = '/api/2.1/password_policy/'
|
56
56
|
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
57
57
|
hash = JSON.parse(resp, symbolize_names: true)
|
58
58
|
self.from_hash(hash)
|