nexpose 0.9.8 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/nexpose.rb +8 -4
- data/lib/nexpose/ajax.rb +29 -4
- data/lib/nexpose/alert.rb +160 -177
- data/lib/nexpose/api.rb +18 -0
- data/lib/nexpose/common.rb +144 -10
- data/lib/nexpose/credential.rb +185 -1
- data/lib/nexpose/discovery.rb +141 -16
- data/lib/nexpose/discovery/filter.rb +26 -3
- data/lib/nexpose/engine.rb +16 -0
- data/lib/nexpose/json_serializer.rb +92 -0
- data/lib/nexpose/scan.rb +131 -23
- data/lib/nexpose/scan_template.rb +1 -1
- data/lib/nexpose/shared_secret.rb +31 -0
- data/lib/nexpose/site.rb +339 -317
- data/lib/nexpose/site_credentials.rb +178 -0
- data/lib/nexpose/tag.rb +42 -1
- data/lib/nexpose/util.rb +11 -16
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/wait.rb +103 -0
- data/lib/nexpose/web_credentials.rb +252 -0
- metadata +18 -8
- data/lib/nexpose/site_credential.rb +0 -323
data/lib/nexpose/api.rb
CHANGED
@@ -82,4 +82,22 @@ module Nexpose
|
|
82
82
|
Object.const_get('Nexpose').const_get(str)
|
83
83
|
end
|
84
84
|
end
|
85
|
+
|
86
|
+
module TypedAccessor
|
87
|
+
def typed_accessor(name, type)
|
88
|
+
|
89
|
+
# here we dynamically define accessor methods
|
90
|
+
define_method(name) do
|
91
|
+
instance_variable_get("@#{name}")
|
92
|
+
end
|
93
|
+
|
94
|
+
define_method("#{name}=") do |value|
|
95
|
+
instance_variable_set("@#{name}", value)
|
96
|
+
end
|
97
|
+
|
98
|
+
define_method("#{name}_type") do
|
99
|
+
type
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
85
103
|
end
|
data/lib/nexpose/common.rb
CHANGED
@@ -91,8 +91,44 @@ module Nexpose
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
# Configuration structure for ad-hoc schedules
|
95
|
+
class AdHocSchedule < APIObject
|
96
|
+
# Start time in ISO8601 format
|
97
|
+
attr_accessor :start
|
98
|
+
|
99
|
+
# The template to use to scan the assets
|
100
|
+
attr_accessor :scan_template_id
|
101
|
+
|
102
|
+
# The amount of time, in minutes, to allow execution before stopping.
|
103
|
+
attr_accessor :max_duration
|
104
|
+
|
105
|
+
def initialize(start, scan_template_id, max_duration = nil)
|
106
|
+
@start = start
|
107
|
+
@scan_template_id = scan_template_id
|
108
|
+
@max_duration = max_duration if max_duration
|
109
|
+
end
|
110
|
+
|
111
|
+
def as_xml
|
112
|
+
xml = REXML::Element.new('AdHocSchedule')
|
113
|
+
xml.attributes['start'] = @start
|
114
|
+
xml.attributes['maxDuration'] = @max_duration if @max_duration
|
115
|
+
xml.attributes['template'] = @scan_template_id
|
116
|
+
xml
|
117
|
+
end
|
118
|
+
|
119
|
+
def from_hash(hash)
|
120
|
+
schedule = AdHocSchedule.new(hash[:start], hash[:scan_template_id])
|
121
|
+
schedule.max_duration = hash[:max_duration] if hash[:max_duration]
|
122
|
+
schedule
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_xml
|
126
|
+
as_xml.to_s
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
94
130
|
# Configuration structure for schedules.
|
95
|
-
class Schedule
|
131
|
+
class Schedule < APIObject
|
96
132
|
# Whether or not this schedule is enabled.
|
97
133
|
attr_accessor :enabled
|
98
134
|
# Valid schedule types: daily, hourly, monthly-date, monthly-day, weekly.
|
@@ -107,8 +143,8 @@ module Nexpose
|
|
107
143
|
# The date after which the schedule is disabled, in ISO 8601 format.
|
108
144
|
attr_accessor :not_valid_after
|
109
145
|
|
146
|
+
# TODO: Remove this unused attribute
|
110
147
|
attr_accessor :incremental
|
111
|
-
attr_accessor :repeater_type
|
112
148
|
|
113
149
|
# Extended attributes added with the new scheduler implementation
|
114
150
|
attr_accessor :is_extended
|
@@ -120,23 +156,89 @@ module Nexpose
|
|
120
156
|
attr_accessor :start_month
|
121
157
|
attr_accessor :timezone
|
122
158
|
attr_accessor :next_run_time
|
123
|
-
attr_accessor :template
|
124
159
|
|
125
|
-
|
160
|
+
# scan-schedule attributes
|
161
|
+
attr_accessor :repeater_type
|
162
|
+
attr_accessor :scan_template_id
|
163
|
+
|
164
|
+
# @param [Time] start
|
165
|
+
def initialize(type, interval, start, enabled = true, scan_template_id = nil)
|
126
166
|
@type = type
|
127
167
|
@interval = interval
|
128
168
|
@start = start
|
129
169
|
@enabled = enabled
|
170
|
+
@scan_template_id = scan_template_id
|
130
171
|
end
|
131
172
|
|
132
173
|
def self.from_hash(hash)
|
133
|
-
|
134
|
-
hash
|
135
|
-
|
174
|
+
start = nil
|
175
|
+
start = Nexpose::ISO8601.to_time(hash[:start_date]) if hash[:start_date]
|
176
|
+
repeat_scan_hash = hash[:repeat_scan]
|
177
|
+
if repeat_scan_hash.nil?
|
178
|
+
schedule = new('daily', 0, start)
|
179
|
+
else
|
180
|
+
schedule = new(repeat_scan_hash[:type], repeat_scan_hash[:interval], start)
|
181
|
+
end
|
182
|
+
schedule.enabled = hash[:enabled].nil? ? true : hash[:enabled]
|
183
|
+
schedule.scan_template_id = hash[:scan_template_id]
|
184
|
+
schedule.start = Nexpose::ISO8601.to_time(hash[:start_date]) if hash[:start_date]
|
185
|
+
schedule.max_duration = hash[:maximum_scan_duration] if hash[:maximum_scan_duration]
|
186
|
+
schedule.not_valid_after = Nexpose::ISO8601.to_time(hash[:not_valid_after_date]) if hash[:not_valid_after_date]
|
187
|
+
schedule.timezone = hash[:time_zone] if hash[:time_zone]
|
188
|
+
schedule.next_run_time = hash[:next_run_time] if hash[:next_run_time]
|
189
|
+
|
190
|
+
unless repeat_scan_hash.nil?
|
191
|
+
schedule.type = repeat_scan_hash[:type]
|
192
|
+
schedule.interval = repeat_scan_hash[:interval]
|
193
|
+
schedule.repeater_type = 'restart' if repeat_scan_hash[:on_repeat] == 'restart-scan'
|
194
|
+
schedule.repeater_type = 'continue' if repeat_scan_hash[:on_repeat] == 'resume-scan'
|
195
|
+
|
196
|
+
schedule.is_extended = repeat_scan_hash[:is_extended] if repeat_scan_hash[:is_extended]
|
197
|
+
schedule.hour = repeat_scan_hash[:hour] if repeat_scan_hash[:hour]
|
198
|
+
schedule.minute = repeat_scan_hash[:minute] if repeat_scan_hash[:minute]
|
199
|
+
schedule.date = repeat_scan_hash[:date] if repeat_scan_hash[:date]
|
200
|
+
schedule.day = repeat_scan_hash[:day] if repeat_scan_hash[:day]
|
201
|
+
schedule.occurrence = repeat_scan_hash[:occurrence] if repeat_scan_hash[:occurrence]
|
202
|
+
schedule.start_month = repeat_scan_hash[:start_month] if repeat_scan_hash[:start_month]
|
136
203
|
end
|
204
|
+
|
137
205
|
schedule
|
138
206
|
end
|
139
207
|
|
208
|
+
def to_h
|
209
|
+
schedule_hash = {
|
210
|
+
enabled: @enabled,
|
211
|
+
scan_template_id: @scan_template_id,
|
212
|
+
maximum_scan_duration: @max_duration
|
213
|
+
}
|
214
|
+
schedule_hash[:start_date] = Nexpose::ISO8601.to_string(@start) if @start
|
215
|
+
schedule_hash[:not_valid_after_date] = Nexpose::ISO8601.to_string(@not_valid_after) if @not_valid_after
|
216
|
+
schedule_hash[:time_zone] = @timezone if @timezone
|
217
|
+
|
218
|
+
unless (@type.nil? || @interval == 0) && !@is_extended
|
219
|
+
repeat_scan_hash = {
|
220
|
+
type: @type,
|
221
|
+
interval: @interval
|
222
|
+
}
|
223
|
+
repeat_scan_hash[:on_repeat] = 'restart-scan' if @repeater_type == 'restart'
|
224
|
+
repeat_scan_hash[:on_repeat] = 'resume-scan' if @repeater_type == 'continue'
|
225
|
+
|
226
|
+
if @is_extended
|
227
|
+
repeat_scan_hash[:is_extended] = @is_extended
|
228
|
+
repeat_scan_hash[:hour] = @hour if @hour
|
229
|
+
repeat_scan_hash[:minute] = @minute if @minute
|
230
|
+
repeat_scan_hash[:date] = @date if @date
|
231
|
+
repeat_scan_hash[:day] = @day if @day
|
232
|
+
repeat_scan_hash[:occurrence] = @occurrence if @occurrence
|
233
|
+
repeat_scan_hash[:start_month] = @start_month if @start_month
|
234
|
+
end
|
235
|
+
|
236
|
+
schedule_hash[:repeat_scan] = repeat_scan_hash
|
237
|
+
end
|
238
|
+
|
239
|
+
schedule_hash
|
240
|
+
end
|
241
|
+
|
140
242
|
def as_xml
|
141
243
|
xml = REXML::Element.new('Schedule')
|
142
244
|
xml.attributes['enabled'] = @enabled ? 1 : 0
|
@@ -155,7 +257,7 @@ module Nexpose
|
|
155
257
|
xml.attributes['occurrence'] = @occurrence if @occurrence
|
156
258
|
xml.attributes['start_month'] = @start_month if @start_month
|
157
259
|
xml.attributes['timezone'] = @timezone if @timezone
|
158
|
-
xml.attributes['template'] = @
|
260
|
+
xml.attributes['template'] = @scan_template_id if @scan_template_id
|
159
261
|
xml
|
160
262
|
end
|
161
263
|
|
@@ -183,7 +285,7 @@ module Nexpose
|
|
183
285
|
schedule.start_month = xml.attributes['start_month'] if xml.attributes['start_month']
|
184
286
|
schedule.timezone = xml.attributes['timezone'] if xml.attributes['timezone']
|
185
287
|
schedule.next_run_time = xml.attributes['next_run_time'] if xml.attributes['next_run_time']
|
186
|
-
schedule.
|
288
|
+
schedule.scan_template_id = xml.attributes['template'] if xml.attributes['template']
|
187
289
|
schedule
|
188
290
|
end
|
189
291
|
|
@@ -200,7 +302,7 @@ module Nexpose
|
|
200
302
|
end
|
201
303
|
|
202
304
|
# Organization configuration, as used in Site and Silo.
|
203
|
-
class Organization
|
305
|
+
class Organization < APIObject
|
204
306
|
attr_accessor :name
|
205
307
|
attr_accessor :url
|
206
308
|
attr_accessor :primary_contact
|
@@ -217,6 +319,38 @@ module Nexpose
|
|
217
319
|
instance_eval(&block) if block_given?
|
218
320
|
end
|
219
321
|
|
322
|
+
def to_h
|
323
|
+
{ name: name,
|
324
|
+
url: url,
|
325
|
+
primary_contact: primary_contact,
|
326
|
+
job_title: job_title,
|
327
|
+
email: email,
|
328
|
+
telephone: telephone,
|
329
|
+
address: address,
|
330
|
+
state: state,
|
331
|
+
city: city,
|
332
|
+
zip: zip,
|
333
|
+
country: country
|
334
|
+
}
|
335
|
+
end
|
336
|
+
|
337
|
+
# Create organization object from hash
|
338
|
+
def self.create(hash)
|
339
|
+
new do |org|
|
340
|
+
org.name = hash[:name]
|
341
|
+
org.url = hash[:url]
|
342
|
+
org.primary_contact = hash[:primary_contact]
|
343
|
+
org.job_title = hash[:job_title]
|
344
|
+
org.email = hash[:email]
|
345
|
+
org.telephone = hash[:telephone]
|
346
|
+
org.address = hash[:address]
|
347
|
+
org.state = hash[:state]
|
348
|
+
org.city = hash[:city]
|
349
|
+
org.zip = hash[:zip]
|
350
|
+
org.country = hash[:country]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
220
354
|
def self.parse(xml)
|
221
355
|
new do |org|
|
222
356
|
org.name = xml.attributes['name']
|
data/lib/nexpose/credential.rb
CHANGED
@@ -2,7 +2,7 @@ module Nexpose
|
|
2
2
|
|
3
3
|
# Contains the shared methods for the SiteCredential and SharedCredential Objects.
|
4
4
|
# See Nexpose::SiteCredential or Nexpose::SharedCredential for additional info.
|
5
|
-
class Credential
|
5
|
+
class Credential < APIObject
|
6
6
|
|
7
7
|
# Mapping of Common Ports.
|
8
8
|
DEFAULT_PORTS = { 'cvs' => 2401,
|
@@ -27,6 +27,13 @@ module Nexpose
|
|
27
27
|
'db2' => 50000 }
|
28
28
|
|
29
29
|
|
30
|
+
# Credential scope
|
31
|
+
module Scope
|
32
|
+
ALL_SITES_ENABLED_DEFAULT = 'A'
|
33
|
+
ALL_SITES_DISABLED_DEFAULT = 'G'
|
34
|
+
SITE_SPECIFIC = 'S'
|
35
|
+
end
|
36
|
+
|
30
37
|
# Credential Service/Type Options.
|
31
38
|
module Service
|
32
39
|
CVS = 'cvs' # Concurrent Versioning System (CVS)
|
@@ -61,7 +68,23 @@ module Nexpose
|
|
61
68
|
PBRUN = 'PBRUN'
|
62
69
|
end
|
63
70
|
|
71
|
+
#Authentication type for SNMP version 3
|
72
|
+
module AuthenticationType
|
73
|
+
NOAUTH = 'noauth' # No authentication protocol
|
74
|
+
SHA = 'sha' # SHA authentication protocol
|
75
|
+
MD5 = 'md5' # MD5 authentication protocol
|
76
|
+
end
|
64
77
|
|
78
|
+
# PrivacyType for snmp version 3
|
79
|
+
module PrivacyType
|
80
|
+
NOPRIV = 'nopriv' # No privacy protocol
|
81
|
+
DES = 'des' # DES privacy protocol
|
82
|
+
AES128 = 'aes128' # AES128 privacy protocol
|
83
|
+
AES192 = 'aes192' # AES192 privacy protocol
|
84
|
+
AES192WITH3DESKEYEXTENSION = 'aes192with3deskeyextension' # AES192 with 3 DES key extension privacy protocol
|
85
|
+
AES256 = 'aes256' # AES256 privacy protocol
|
86
|
+
AES265WITH3DESKEYEXTENSION = 'aes265with3deskeyextension' # AES256 with 3 DES key extension privacy protocol
|
87
|
+
end
|
65
88
|
# Test this credential against a target where the credentials should apply.
|
66
89
|
# Only works for a newly created credential. Loading an existing credential
|
67
90
|
# will likely fail.
|
@@ -102,6 +125,167 @@ module Nexpose
|
|
102
125
|
siteid: siteid }
|
103
126
|
end
|
104
127
|
|
128
|
+
# sets the Concurrent Versioning System (CVS) service
|
129
|
+
def set_cvs_service(username = nil, password = nil)
|
130
|
+
@user_name = username
|
131
|
+
@password = password
|
132
|
+
@service = Service::CVS
|
133
|
+
end
|
134
|
+
|
135
|
+
# sets the DB2 service
|
136
|
+
def set_db2_service(database = nil, username = nil, password = nil)
|
137
|
+
@database = database
|
138
|
+
@user_name = username
|
139
|
+
@password = password
|
140
|
+
@service = Service::DB2
|
141
|
+
end
|
142
|
+
|
143
|
+
# sets the File Transfer Protocol (FTP) service
|
144
|
+
def set_ftp_service(username = nil, password = nil)
|
145
|
+
@user_name = username
|
146
|
+
@password = password
|
147
|
+
@service = Service::FTP
|
148
|
+
end
|
149
|
+
|
150
|
+
# sets the IBM AS/400 service.
|
151
|
+
def set_as400_service(domain = nil, username = nil, password = nil)
|
152
|
+
@domain = domain
|
153
|
+
@user_name = username
|
154
|
+
@password = password
|
155
|
+
@service = Service::AS400
|
156
|
+
end
|
157
|
+
|
158
|
+
# sets the Lotus Notes/Domino service.
|
159
|
+
def set_notes_service(password = nil)
|
160
|
+
@notes_id_password = password
|
161
|
+
@service = Service::NOTES
|
162
|
+
end
|
163
|
+
|
164
|
+
# sets the Microsoft SQL Server service.
|
165
|
+
def set_tds_service(database = nil, domain = nil, username = nil, password = nil)
|
166
|
+
@database = database
|
167
|
+
@domain = domain
|
168
|
+
@use_windows_auth = domain.nil?
|
169
|
+
@user_name = username
|
170
|
+
@password = password
|
171
|
+
@service = Service::TDS
|
172
|
+
end
|
173
|
+
|
174
|
+
# sets the Microsoft Windows/Samba (SMB/CIFS) service.
|
175
|
+
def set_cifs_service(domain = nil, username = nil, password = nil)
|
176
|
+
@domain = domain
|
177
|
+
@user_name = username
|
178
|
+
@password = password
|
179
|
+
@service = Service::CIFS
|
180
|
+
end
|
181
|
+
|
182
|
+
# sets the Microsoft Windows/Samba LM/NTLM Hash (SMB/CIFS) service.
|
183
|
+
def set_cifshash_service(domain = nil, username = nil, password = nil)
|
184
|
+
@domain = domain
|
185
|
+
@user_name = username
|
186
|
+
@password = password
|
187
|
+
@service = Service::CIFSHASH
|
188
|
+
end
|
189
|
+
|
190
|
+
# sets the MySQL Server service.
|
191
|
+
def set_mysql_service(database = nil, username = nil, password = nil)
|
192
|
+
@database = database
|
193
|
+
@user_name = username
|
194
|
+
@password = password
|
195
|
+
@service = Service::MYSQL
|
196
|
+
end
|
197
|
+
|
198
|
+
# sets the Oracle service.
|
199
|
+
def set_oracle_service(sid = nil, username = nil, password = nil)
|
200
|
+
@database = sid
|
201
|
+
@user_name = username
|
202
|
+
@password = password
|
203
|
+
@service = Service::ORACLE
|
204
|
+
end
|
205
|
+
|
206
|
+
# sets the Post Office Protocol (POP) service.
|
207
|
+
def set_pop_service(username = nil, password = nil)
|
208
|
+
@user_name = username
|
209
|
+
@password = password
|
210
|
+
@service = Service::POP
|
211
|
+
end
|
212
|
+
|
213
|
+
# sets the PostgreSQL service.
|
214
|
+
def set_postgresql_service(database = nil, username = nil, password = nil)
|
215
|
+
@database = database
|
216
|
+
@user_name = username
|
217
|
+
@password = password
|
218
|
+
@service = Service::POSTGRESQL
|
219
|
+
end
|
220
|
+
|
221
|
+
# sets the Remote Execution service.
|
222
|
+
def set_remote_execution_service(username = nil, password = nil)
|
223
|
+
@user_name = username
|
224
|
+
@password = password
|
225
|
+
@service = Service::REMOTE_EXECUTION
|
226
|
+
end
|
227
|
+
|
228
|
+
# sets the Secure Shell (SSH) service.
|
229
|
+
def set_ssh_service(username = nil, password = nil, elevation_type = nil, elevation_user = nil, elevation_password = nil)
|
230
|
+
@user_name = username
|
231
|
+
@password = password
|
232
|
+
@permission_elevation_type = elevation_type || ElevationType::NONE
|
233
|
+
@permission_elevation_user = elevation_user
|
234
|
+
@permission_elevation_password = elevation_password
|
235
|
+
@service = Service::SSH
|
236
|
+
end
|
237
|
+
|
238
|
+
# sets the Secure Shell (SSH) Public Key service.
|
239
|
+
def set_ssh_key_service(username, pemkey, password = nil, elevation_type = nil, elevation_user = nil, elevation_password = nil)
|
240
|
+
@user_name = username
|
241
|
+
@password = password
|
242
|
+
@pem_format_private_key = pemkey
|
243
|
+
@permission_elevation_type = elevation_type || ElevationType::NONE
|
244
|
+
@permission_elevation_user = elevation_user
|
245
|
+
@permission_elevation_password = elevation_password
|
246
|
+
@service = Service::SSH_KEY
|
247
|
+
end
|
248
|
+
|
249
|
+
# sets the Simple Network Management Protocol v1/v2c service.
|
250
|
+
def set_snmp_service(community_name = nil)
|
251
|
+
@community_name = community_name
|
252
|
+
@service = Service::SNMP
|
253
|
+
end
|
254
|
+
|
255
|
+
# sets the Simple Network Management Protocol v3 service.
|
256
|
+
def set_snmpv3_service(authentication_type = AuthenticationType::NOAUTH, username = nil, password = nil, privacy_type = PrivacyType::NOPRIV, privacy_password = nil)
|
257
|
+
@authentication_type = authentication_type
|
258
|
+
@user_name = username
|
259
|
+
@password = password
|
260
|
+
@privacy_type = privacy_type
|
261
|
+
@privacy_password = privacy_password
|
262
|
+
@service = Service::SNMPV3
|
263
|
+
end
|
264
|
+
|
265
|
+
# sets the Sybase SQL Server service.
|
266
|
+
def set_sybase_service(database = nil, domain = nil, username = nil, password = nil)
|
267
|
+
@database = database
|
268
|
+
@domain = domain
|
269
|
+
@use_windows_auth = domain.nil?
|
270
|
+
@user_name = username
|
271
|
+
@password = password
|
272
|
+
@service = Service::SYBASE
|
273
|
+
end
|
274
|
+
|
275
|
+
# sets the Telnet service.
|
276
|
+
def set_telnet_service(username = nil, password = nil)
|
277
|
+
@user_name = username
|
278
|
+
@password = password
|
279
|
+
@service = Service::TELNET
|
280
|
+
end
|
281
|
+
|
282
|
+
# sets the Web Site HTTP Authentication service.
|
283
|
+
def set_http_service(domain = nil, username = nil, password = nil)
|
284
|
+
@domain = domain
|
285
|
+
@user_name = username
|
286
|
+
@password = password
|
287
|
+
@service = Service::HTTP
|
288
|
+
end
|
105
289
|
end
|
106
290
|
|
107
291
|
|