nexpose 0.0.9 → 0.0.91
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/nexpose.rb +13 -3236
- data/lib/nexpose/api_request.rb +144 -0
- data/lib/nexpose/connection.rb +106 -0
- data/lib/nexpose/creds.rb +189 -0
- data/lib/nexpose/error.rb +21 -0
- data/lib/nexpose/misc.rb +122 -0
- data/lib/nexpose/report.rb +570 -0
- data/lib/nexpose/scan.rb +280 -0
- data/lib/nexpose/scan_engine.rb +147 -0
- data/lib/nexpose/silo.rb +347 -0
- data/lib/nexpose/site.rb +877 -0
- data/lib/nexpose/ticket.rb +108 -0
- data/lib/nexpose/util.rb +35 -0
- data/lib/nexpose/vuln.rb +520 -0
- data/nexpose.gemspec +3 -3
- metadata +22 -11
data/lib/nexpose.rb
CHANGED
@@ -53,3244 +53,22 @@ require 'net/https'
|
|
53
53
|
require 'net/http'
|
54
54
|
require 'uri'
|
55
55
|
require 'rex/mime'
|
56
|
+
require 'nexpose/error'
|
57
|
+
require 'nexpose/util'
|
58
|
+
require 'nexpose/api_request'
|
59
|
+
require 'nexpose/misc'
|
60
|
+
require 'nexpose/report'
|
61
|
+
require 'nexpose/scan'
|
62
|
+
require 'nexpose/scan_engine'
|
63
|
+
require 'nexpose/silo'
|
64
|
+
require 'nexpose/site'
|
65
|
+
require 'nexpose/ticket'
|
66
|
+
require 'nexpose/vuln'
|
67
|
+
require 'nexpose/creds'
|
68
|
+
require 'nexpose/connection'
|
56
69
|
|
57
70
|
module Nexpose
|
58
71
|
|
59
|
-
module Sanitize
|
60
|
-
def replace_entities(str)
|
61
|
-
ret = str.dup
|
62
|
-
ret.gsub!(/&/, "&")
|
63
|
-
ret.gsub!(/'/, "'")
|
64
|
-
ret.gsub!(/"/, """)
|
65
|
-
ret.gsub!(/</, "<")
|
66
|
-
ret.gsub!(/>/, ">")
|
67
|
-
ret
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class APIError < ::RuntimeError
|
72
|
-
attr_accessor :req, :reason
|
73
|
-
def initialize(req, reason = '')
|
74
|
-
self.req = req
|
75
|
-
self.reason = reason
|
76
|
-
end
|
77
|
-
def to_s
|
78
|
-
"NexposeAPI: #{self.reason}"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class AuthenticationFailed < APIError
|
83
|
-
def initialize(req)
|
84
|
-
self.req = req
|
85
|
-
self.reason = "Login Failed"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
module XMLUtils
|
90
|
-
def parse_xml(xml)
|
91
|
-
::REXML::Document.new(xml.to_s)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
class APIRequest
|
96
|
-
include XMLUtils
|
97
|
-
|
98
|
-
attr_reader :http
|
99
|
-
attr_reader :uri
|
100
|
-
attr_reader :headers
|
101
|
-
attr_reader :retry_count
|
102
|
-
attr_reader :time_out
|
103
|
-
attr_reader :pause
|
104
|
-
|
105
|
-
attr_reader :req
|
106
|
-
attr_reader :res
|
107
|
-
attr_reader :sid
|
108
|
-
attr_reader :success
|
109
|
-
|
110
|
-
attr_reader :error
|
111
|
-
attr_reader :trace
|
112
|
-
|
113
|
-
attr_reader :raw_response
|
114
|
-
attr_reader :raw_response_data
|
115
|
-
|
116
|
-
def initialize(req, url, api_version='1.1')
|
117
|
-
@url = url
|
118
|
-
@req = req
|
119
|
-
@api_version = api_version
|
120
|
-
@url = @url.sub('API_VERSION', @api_version)
|
121
|
-
prepare_http_client
|
122
|
-
end
|
123
|
-
|
124
|
-
def prepare_http_client
|
125
|
-
@retry_count = 0
|
126
|
-
@retry_count_max = 10
|
127
|
-
@time_out = 30
|
128
|
-
@pause = 2
|
129
|
-
@uri = URI.parse(@url)
|
130
|
-
@http = Net::HTTP.new(@uri.host, @uri.port)
|
131
|
-
@http.use_ssl = true
|
132
|
-
#
|
133
|
-
# XXX: This is obviously a security issue, however, we handle this at the client level by forcing
|
134
|
-
# a confirmation when the nexpose host is not localhost. In a perfect world, we would present
|
135
|
-
# the server signature before accepting it, but this requires either a direct callback inside
|
136
|
-
# of this module back to whatever UI, or opens a race condition between accept and attempt.
|
137
|
-
#
|
138
|
-
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
139
|
-
@headers = {'Content-Type' => 'text/xml'}
|
140
|
-
@success = false
|
141
|
-
end
|
142
|
-
|
143
|
-
def execute
|
144
|
-
@conn_tries = 0
|
145
|
-
|
146
|
-
begin
|
147
|
-
prepare_http_client
|
148
|
-
@raw_response = @http.post(@uri.path, @req, @headers)
|
149
|
-
@raw_response_data = @raw_response.read_body
|
150
|
-
@res = parse_xml(@raw_response_data)
|
151
|
-
|
152
|
-
if(not @res.root)
|
153
|
-
@error = "NeXpose service returned invalid XML"
|
154
|
-
return @sid
|
155
|
-
end
|
156
|
-
|
157
|
-
@sid = attributes['session-id']
|
158
|
-
|
159
|
-
if(attributes['success'] and attributes['success'].to_i == 1)
|
160
|
-
@success = true
|
161
|
-
elsif @api_version =~ /1.2/ and @res and (@res.get_elements '//Exception').count < 1
|
162
|
-
@success = true
|
163
|
-
else
|
164
|
-
@success = false
|
165
|
-
@res.elements.each('//Failure/Exception') do |s|
|
166
|
-
s.elements.each('message') do |m|
|
167
|
-
@error = m.text
|
168
|
-
end
|
169
|
-
s.elements.each('stacktrace') do |m|
|
170
|
-
@trace = m.text
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
# This is a hack to handle corner cases where a heavily loaded NeXpose instance
|
175
|
-
# drops our HTTP connection before processing. We try 5 times to establish a
|
176
|
-
# connection in these situations. The actual exception occurs in the Ruby
|
177
|
-
# http library, which is why we use such generic error classes.
|
178
|
-
rescue ::ArgumentError, ::NoMethodError
|
179
|
-
if @conn_tries < 5
|
180
|
-
@conn_tries += 1
|
181
|
-
retry
|
182
|
-
end
|
183
|
-
rescue ::Timeout::Error
|
184
|
-
if @conn_tries < 5
|
185
|
-
@conn_tries += 1
|
186
|
-
retry
|
187
|
-
end
|
188
|
-
@error = "NeXpose host did not respond"
|
189
|
-
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::EADDRNOTAVAIL
|
190
|
-
@error = "NeXpose host is unreachable"
|
191
|
-
# Handle console-level interrupts
|
192
|
-
rescue ::Interrupt
|
193
|
-
@error = "received a user interrupt"
|
194
|
-
rescue ::Errno::ECONNRESET,::Errno::ECONNREFUSED,::Errno::ENOTCONN,::Errno::ECONNABORTED
|
195
|
-
@error = "NeXpose service is not available"
|
196
|
-
rescue ::REXML::ParseException
|
197
|
-
@error = "NeXpose has not been properly licensed"
|
198
|
-
end
|
199
|
-
|
200
|
-
if ! (@success or @error)
|
201
|
-
@error = "NeXpose service returned an unrecognized response: #{@raw_response_data.inspect}"
|
202
|
-
end
|
203
|
-
|
204
|
-
@sid
|
205
|
-
end
|
206
|
-
|
207
|
-
def attributes(*args)
|
208
|
-
return if not @res.root
|
209
|
-
@res.root.attributes(*args)
|
210
|
-
end
|
211
|
-
|
212
|
-
def self.execute(url, req, api_version='1.1')
|
213
|
-
obj = self.new(req, url, api_version)
|
214
|
-
obj.execute
|
215
|
-
if(not obj.success)
|
216
|
-
raise APIError.new(obj, "Action failed: #{obj.error}")
|
217
|
-
end
|
218
|
-
obj
|
219
|
-
end
|
220
|
-
|
221
|
-
end
|
222
|
-
|
223
|
-
module NexposeAPI
|
224
|
-
|
225
|
-
def make_xml(name, opts={}, data='', append_session_id=true)
|
226
|
-
xml = REXML::Element.new(name)
|
227
|
-
if(@session_id and append_session_id)
|
228
|
-
xml.attributes['session-id'] = @session_id
|
229
|
-
end
|
230
|
-
|
231
|
-
opts.keys.each do |k|
|
232
|
-
xml.attributes[k] = "#{opts[k]}"
|
233
|
-
end
|
234
|
-
|
235
|
-
xml.text = data
|
236
|
-
|
237
|
-
xml
|
238
|
-
end
|
239
|
-
|
240
|
-
def scan_stop(param)
|
241
|
-
r = execute(make_xml('ScanStopRequest', { 'scan-id' => param }))
|
242
|
-
r.success
|
243
|
-
end
|
244
|
-
|
245
|
-
def scan_status(param)
|
246
|
-
r = execute(make_xml('ScanStatusRequest', { 'scan-id' => param }))
|
247
|
-
r.success ? r.attributes['status'] : nil
|
248
|
-
end
|
249
|
-
|
250
|
-
def scan_activity
|
251
|
-
r = execute(make_xml('ScanActivityRequest', { }))
|
252
|
-
if(r.success)
|
253
|
-
res = []
|
254
|
-
r.res.elements.each("//ScanSummary") do |scan|
|
255
|
-
res << {
|
256
|
-
:scan_id => scan.attributes['scan-id'].to_i,
|
257
|
-
:site_id => scan.attributes['site-id'].to_i,
|
258
|
-
:engine_id => scan.attributes['engine-id'].to_i,
|
259
|
-
:status => scan.attributes['status'].to_s,
|
260
|
-
:start_time => Date.parse(scan.attributes['startTime'].to_s).to_time
|
261
|
-
}
|
262
|
-
end
|
263
|
-
return res
|
264
|
-
else
|
265
|
-
return false
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
def scan_statistics(param)
|
270
|
-
r = execute(make_xml('ScanStatisticsRequest', {'scan-id' => param }))
|
271
|
-
if(r.success)
|
272
|
-
res = {}
|
273
|
-
r.res.elements.each("//ScanSummary/nodes") do |node|
|
274
|
-
res[:nodes] = {}
|
275
|
-
node.attributes.keys.each do |k|
|
276
|
-
res[:nodes][k] = node.attributes[k].to_i
|
277
|
-
end
|
278
|
-
end
|
279
|
-
r.res.elements.each("//ScanSummary/tasks") do |task|
|
280
|
-
res[:task] = {}
|
281
|
-
task.attributes.keys.each do |k|
|
282
|
-
res[:task][k] = task.attributes[k].to_i
|
283
|
-
end
|
284
|
-
end
|
285
|
-
r.res.elements.each("//ScanSummary/vulnerabilities") do |vuln|
|
286
|
-
res[:vulns] ||= {}
|
287
|
-
k = vuln.attributes['status'] + (vuln.attributes['severity'] ? ("-" + vuln.attributes['severity']) : '')
|
288
|
-
res[:vulns][k] = vuln.attributes['count'].to_i
|
289
|
-
end
|
290
|
-
r.res.elements.each("//ScanSummary") do |summ|
|
291
|
-
res[:summary] = {}
|
292
|
-
summ.attributes.keys.each do |k|
|
293
|
-
res[:summary][k] = summ.attributes[k]
|
294
|
-
if (res[:summary][k] =~ /^\d+$/)
|
295
|
-
res[:summary][k] = res[:summary][k].to_i
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
r.res.elements.each("//ScanSummary/message") do |message|
|
300
|
-
res[:message] = message.text
|
301
|
-
end
|
302
|
-
return res
|
303
|
-
else
|
304
|
-
return false
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
def report_generate(param)
|
309
|
-
r = execute(make_xml('ReportGenerateRequest', { 'report-id' => param }))
|
310
|
-
r.success
|
311
|
-
end
|
312
|
-
|
313
|
-
def report_last(param)
|
314
|
-
r = execute(make_xml('ReportHistoryRequest', { 'reportcfg-id' => param }))
|
315
|
-
res = nil
|
316
|
-
if(r.success)
|
317
|
-
stk = []
|
318
|
-
r.res.elements.each("//ReportSummary") do |rep|
|
319
|
-
stk << [ rep.attributes['id'].to_i, rep.attributes['report-URI'] ]
|
320
|
-
end
|
321
|
-
if (stk.length > 0)
|
322
|
-
stk.sort!{|a,b| b[0] <=> a[0]}
|
323
|
-
res = stk[0][1]
|
324
|
-
end
|
325
|
-
end
|
326
|
-
res
|
327
|
-
end
|
328
|
-
|
329
|
-
def report_history(param)
|
330
|
-
execute(make_xml('ReportHistoryRequest', { 'reportcfg-id' => param }))
|
331
|
-
end
|
332
|
-
|
333
|
-
def report_config_delete(param)
|
334
|
-
r = execute(make_xml('ReportDeleteRequest', { 'reportcfg-id' => param }))
|
335
|
-
r.success
|
336
|
-
end
|
337
|
-
|
338
|
-
def report_delete(param)
|
339
|
-
r = execute(make_xml('ReportDeleteRequest', { 'report-id' => param }))
|
340
|
-
r.success
|
341
|
-
end
|
342
|
-
|
343
|
-
def device_delete(param)
|
344
|
-
r = execute(make_xml('DeviceDeleteRequest', { 'site-id' => param }))
|
345
|
-
r.success
|
346
|
-
end
|
347
|
-
|
348
|
-
def asset_group_delete(connection, id, debug = false)
|
349
|
-
r = execute(make_xml('AssetGroupDeleteRequest', { 'group-id' => param }))
|
350
|
-
r.success
|
351
|
-
end
|
352
|
-
|
353
|
-
#
|
354
|
-
# Create a NeXpose ticket
|
355
|
-
#
|
356
|
-
# ticket_info: A hash of the data to be used to create a ticket in NeXpose:
|
357
|
-
# :name => The name of the ticket (Required)
|
358
|
-
# :device_id => The NeXpose device ID for the device being ticketed (Required)
|
359
|
-
# :assigned_to => The NeXpose user to whom this ticket is assigned (Required)
|
360
|
-
# :priority => "low,moderate,normal,high,critical" (Required)
|
361
|
-
#
|
362
|
-
# :vulnerabilities => An array of NeXpose vuln IDs. This is NOT the same as vuln ID. (Required)
|
363
|
-
# :comments => An array of comments to accompany this ticket
|
364
|
-
#
|
365
|
-
# @return The ticket ID if the ticket creation was successful, {@code false} otherwise
|
366
|
-
#
|
367
|
-
def create_ticket ticket_info
|
368
|
-
ticket_name = ticket_info[:name]
|
369
|
-
unless ticket_name
|
370
|
-
raise ArgumentError.new 'Ticket name is required'
|
371
|
-
end
|
372
|
-
|
373
|
-
device_id = ticket_info[:device_id]
|
374
|
-
unless device_id
|
375
|
-
raise ArgumentError.new 'Device ID is required'
|
376
|
-
end
|
377
|
-
|
378
|
-
assigned_to = ticket_info[:assigned_to]
|
379
|
-
unless assigned_to
|
380
|
-
raise ArgumentError.new 'Assignee name is required'
|
381
|
-
end
|
382
|
-
|
383
|
-
priority = ticket_info[:priority]
|
384
|
-
unless priority
|
385
|
-
raise ArgumentError.new 'Ticket priority is required'
|
386
|
-
end
|
387
|
-
|
388
|
-
vulnerabilities = ticket_info[:vulnerabilities]
|
389
|
-
if not vulnerabilities or vulnerabilities.count < 1
|
390
|
-
raise ArgumentError.new 'Vulnerabilities are required'
|
391
|
-
end
|
392
|
-
|
393
|
-
comments = ticket_info[:comments]
|
394
|
-
base_xml = make_xml 'TicketCreateRequest'
|
395
|
-
|
396
|
-
required_attributes = {
|
397
|
-
'name' => ticket_name,
|
398
|
-
'priority' => priority,
|
399
|
-
'device-id' => device_id,
|
400
|
-
'assigned-to' => assigned_to
|
401
|
-
}
|
402
|
-
|
403
|
-
create_request_xml = REXML::Element.new 'TicketCreate'
|
404
|
-
create_request_xml.add_attributes required_attributes
|
405
|
-
|
406
|
-
# Add vulnerabilities
|
407
|
-
vulnerabilities_xml = REXML::Element.new 'Vulnerabilities'
|
408
|
-
vulnerabilities.each do |vuln_id|
|
409
|
-
vulnerabilities_xml.add_element 'Vulnerability', {'id' => vuln_id}
|
410
|
-
end
|
411
|
-
create_request_xml.add_element vulnerabilities_xml
|
412
|
-
|
413
|
-
# Add comments
|
414
|
-
if comments and comments.count > 0
|
415
|
-
comments_xml = REXML::Element.new 'Comments'
|
416
|
-
comments.each do |comment|
|
417
|
-
comment_xml = REXML::Element.new 'Comment'
|
418
|
-
comment_xml.add_text comment
|
419
|
-
comments_xml.add_element comment_xml
|
420
|
-
end
|
421
|
-
|
422
|
-
create_request_xml.add_element comments_xml
|
423
|
-
end
|
424
|
-
|
425
|
-
base_xml.add_element create_request_xml
|
426
|
-
r = execute base_xml, '1.2'
|
427
|
-
if r.success
|
428
|
-
r.res.elements.each('TicketCreateResponse') do |group|
|
429
|
-
return group.attributes['id'].to_i
|
430
|
-
end
|
431
|
-
else
|
432
|
-
false
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
#
|
437
|
-
# Deletes a NeXpose ticket.
|
438
|
-
#
|
439
|
-
# ticket_ids: An array of ticket IDs to be deleted.
|
440
|
-
#
|
441
|
-
# @returns {@code true} iff the call was successfull. {@code false} otherwise.
|
442
|
-
#
|
443
|
-
def delete_ticket ticket_ids
|
444
|
-
if not ticket_ids or ticket_ids.count < 1
|
445
|
-
raise ArgumentError.new 'The tickets to delete should not be null or empty'
|
446
|
-
end
|
447
|
-
|
448
|
-
base_xml = make_xml 'TicketDeleteRequest'
|
449
|
-
ticket_ids.each do |id|
|
450
|
-
base_xml.add_element 'Ticket', {'id' => id}
|
451
|
-
end
|
452
|
-
|
453
|
-
(execute base_xml, '1.2').success
|
454
|
-
end
|
455
|
-
|
456
|
-
#-------------------------------------------------------------------------
|
457
|
-
# Returns all asset group information
|
458
|
-
#-------------------------------------------------------------------------
|
459
|
-
def asset_groups_listing()
|
460
|
-
r = execute(make_xml('AssetGroupListingRequest'))
|
461
|
-
|
462
|
-
if r.success
|
463
|
-
res = []
|
464
|
-
r.res.elements.each('//AssetGroupSummary') do |group|
|
465
|
-
res << {
|
466
|
-
:asset_group_id => group.attributes['id'].to_i,
|
467
|
-
:name => group.attributes['name'].to_s,
|
468
|
-
:description => group.attributes['description'].to_s,
|
469
|
-
:risk_score => group.attributes['riskscore'].to_f,
|
470
|
-
}
|
471
|
-
end
|
472
|
-
res
|
473
|
-
else
|
474
|
-
false
|
475
|
-
end
|
476
|
-
end
|
477
|
-
|
478
|
-
#-------------------------------------------------------------------------
|
479
|
-
# Returns an asset group configuration information for a specific group ID
|
480
|
-
#-------------------------------------------------------------------------
|
481
|
-
def asset_group_config(group_id)
|
482
|
-
r = execute(make_xml('AssetGroupConfigRequest', {'group-id' => group_id}))
|
483
|
-
|
484
|
-
if r.success
|
485
|
-
res = []
|
486
|
-
r.res.elements.each('//Devices/device') do |device_info|
|
487
|
-
res << {
|
488
|
-
:device_id => device_info.attributes['id'].to_i,
|
489
|
-
:site_id => device_info.attributes['site-id'].to_i,
|
490
|
-
:address => device_info.attributes['address'].to_s,
|
491
|
-
:riskfactor => device_info.attributes['riskfactor'].to_f,
|
492
|
-
}
|
493
|
-
end
|
494
|
-
res
|
495
|
-
else
|
496
|
-
false
|
497
|
-
end
|
498
|
-
end
|
499
|
-
|
500
|
-
#-----------------------------------------------------------------------
|
501
|
-
# Starts device specific site scanning.
|
502
|
-
#
|
503
|
-
# devices - An Array of device IDs
|
504
|
-
# hosts - An Array of Hashes [o]=>{:range=>"to,from"} [1]=>{:host=>host}
|
505
|
-
#-----------------------------------------------------------------------
|
506
|
-
def site_device_scan_start(site_id, devices, hosts)
|
507
|
-
|
508
|
-
if hosts == nil and devices == nil
|
509
|
-
raise ArgumentError.new("Both the device and host list is nil")
|
510
|
-
end
|
511
|
-
|
512
|
-
xml = make_xml('SiteDevicesScanRequest', {'site-id' => site_id})
|
513
|
-
|
514
|
-
if devices != nil
|
515
|
-
inner_xml = REXML::Element.new 'Devices'
|
516
|
-
for device_id in devices
|
517
|
-
inner_xml.add_element 'device', {'id' => "#{device_id}"}
|
518
|
-
end
|
519
|
-
xml.add_element inner_xml
|
520
|
-
end
|
521
|
-
|
522
|
-
if hosts != nil
|
523
|
-
inner_xml = REXML::Element.new 'Hosts'
|
524
|
-
hosts.each_index do |x|
|
525
|
-
if hosts[x].key? :range
|
526
|
-
to = hosts[x][:range].split(',')[0]
|
527
|
-
from = hosts[x][:range].split(',')[1]
|
528
|
-
inner_xml.add_element 'range', {'to' => "#{to}", 'from' => "#{from}"}
|
529
|
-
end
|
530
|
-
if hosts[x].key? :host
|
531
|
-
host_element = REXML::Element.new 'host'
|
532
|
-
host_element.text = "#{hosts[x][:host]}"
|
533
|
-
inner_xml.add_element host_element
|
534
|
-
end
|
535
|
-
end
|
536
|
-
xml.add_element inner_xml
|
537
|
-
end
|
538
|
-
|
539
|
-
r = execute xml
|
540
|
-
if r.success
|
541
|
-
r.res.elements.each('//Scan') do |scan_info|
|
542
|
-
return {
|
543
|
-
:scan_id => scan_info.attributes['scan-id'].to_i,
|
544
|
-
:engine_id => scan_info.attributes['engine-id'].to_i
|
545
|
-
}
|
546
|
-
end
|
547
|
-
else
|
548
|
-
false
|
549
|
-
end
|
550
|
-
end
|
551
|
-
|
552
|
-
#
|
553
|
-
# Lists all the users for the NSC along with the user details.
|
554
|
-
#
|
555
|
-
def list_users
|
556
|
-
r = execute(make_xml('UserListingRequest'))
|
557
|
-
if r.success
|
558
|
-
res = []
|
559
|
-
r.res.elements.each('//UserSummary') do |user_summary|
|
560
|
-
res << {
|
561
|
-
:auth_source => user_summary.attributes['authSource'],
|
562
|
-
:auth_module => user_summary.attributes['authModule'],
|
563
|
-
:user_name => user_summary.attributes['userName'],
|
564
|
-
:full_name => user_summary.attributes['fullName'],
|
565
|
-
:email => user_summary.attributes['email'],
|
566
|
-
:is_admin => user_summary.attributes['isAdmin'].to_s.chomp.eql?('1'),
|
567
|
-
:is_disabled => user_summary.attributes['disabled'].to_s.chomp.eql?('1'),
|
568
|
-
:site_count => user_summary.attributes['siteCount'],
|
569
|
-
:group_count => user_summary.attributes['groupCount']
|
570
|
-
}
|
571
|
-
end
|
572
|
-
res
|
573
|
-
else
|
574
|
-
false
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
def site_delete(param)
|
579
|
-
r = execute(make_xml('SiteDeleteRequest', { 'site-id' => param }))
|
580
|
-
r.success
|
581
|
-
end
|
582
|
-
|
583
|
-
def site_listing
|
584
|
-
r = execute(make_xml('SiteListingRequest', { }))
|
585
|
-
|
586
|
-
if(r.success)
|
587
|
-
res = []
|
588
|
-
r.res.elements.each("//SiteSummary") do |site|
|
589
|
-
res << {
|
590
|
-
:site_id => site.attributes['id'].to_i,
|
591
|
-
:name => site.attributes['name'].to_s,
|
592
|
-
:risk_factor => site.attributes['riskfactor'].to_f,
|
593
|
-
:risk_score => site.attributes['riskscore'].to_f,
|
594
|
-
}
|
595
|
-
end
|
596
|
-
return res
|
597
|
-
else
|
598
|
-
return false
|
599
|
-
end
|
600
|
-
end
|
601
|
-
|
602
|
-
#-----------------------------------------------------------------------
|
603
|
-
# TODO: Needs to be expanded to included details
|
604
|
-
#-----------------------------------------------------------------------
|
605
|
-
def site_scan_history(site_id)
|
606
|
-
r = execute(make_xml('SiteScanHistoryRequest', {'site-id' => site_id.to_s}))
|
607
|
-
|
608
|
-
if (r.success)
|
609
|
-
res = []
|
610
|
-
r.res.elements.each("//ScanSummary") do |site_scan_history|
|
611
|
-
res << {
|
612
|
-
:site_id => site_scan_history.attributes['site-id'].to_i,
|
613
|
-
:scan_id => site_scan_history.attributes['scan-id'].to_i,
|
614
|
-
:engine_id => site_scan_history.attributes['engine-id'].to_i,
|
615
|
-
:start_time => site_scan_history.attributes['startTime'].to_s,
|
616
|
-
:end_time => site_scan_history.attributes['endTime'].to_s
|
617
|
-
}
|
618
|
-
end
|
619
|
-
res
|
620
|
-
else
|
621
|
-
false
|
622
|
-
end
|
623
|
-
end
|
624
|
-
|
625
|
-
###################
|
626
|
-
# VULN EXCEPTIONS #
|
627
|
-
###################
|
628
|
-
|
629
|
-
#-----------------------------------------------------------------------
|
630
|
-
# Returns an array of vulnerability exceptions and their associated
|
631
|
-
# attributes.
|
632
|
-
#
|
633
|
-
# @param status - (optional) The status of the vulnerability exception:
|
634
|
-
# "Under Review", "Approved", "Rejected"
|
635
|
-
#-----------------------------------------------------------------------
|
636
|
-
def vuln_listing status=nil
|
637
|
-
option = {}
|
638
|
-
|
639
|
-
if status && !status.empty?
|
640
|
-
if status =~ /Under Review|Approved|Rejected/
|
641
|
-
option['status'] = status
|
642
|
-
else
|
643
|
-
raise ArgumentError.new 'The vulnerability status passed in is invalid!'
|
644
|
-
end
|
645
|
-
end
|
646
|
-
|
647
|
-
xml = make_xml('VulnerabilityExceptionListingRequest', option)
|
648
|
-
r = execute xml, '1.2'
|
649
|
-
|
650
|
-
if r.success
|
651
|
-
res = []
|
652
|
-
r.res.elements.each("//VulnerabilityException") do |ve|
|
653
|
-
submitter_comment = ve.elements['submitter-comment']
|
654
|
-
reviewer_comment = ve.elements['reviewer-comment']
|
655
|
-
res << {
|
656
|
-
:vuln_id => ve.attributes['vuln-id'],
|
657
|
-
:exception_id => ve.attributes['exception-id'],
|
658
|
-
:submitter => ve.attributes['submitter'],
|
659
|
-
:reviewer => ve.attributes['reviewer'],
|
660
|
-
:status => ve.attributes['status'],
|
661
|
-
:reason => ve.attributes['reason'],
|
662
|
-
:scope => ve.attributes['scope'],
|
663
|
-
:device_id => ve.attributes['device-id'],
|
664
|
-
:port_no => ve.attributes['port-no'],
|
665
|
-
:expiration_date => ve.attributes['expiration-date'],
|
666
|
-
:vuln_key => ve.attributes['vuln-key'],
|
667
|
-
:submitter_comment => submitter_comment.nil? ? '' : submitter_comment.text,
|
668
|
-
:reviewer_comment => reviewer_comment.nil? ? '' : reviewer_comment.text
|
669
|
-
}
|
670
|
-
end
|
671
|
-
res
|
672
|
-
else
|
673
|
-
false
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
677
|
-
#-------------------------------------------------------------------------------------------------------------------
|
678
|
-
# Creates a vulnerability exception.
|
679
|
-
#
|
680
|
-
# @param input - data used to create the vulnerability exception:
|
681
|
-
# :vuln_id - The Nexpose vulnerability ID.
|
682
|
-
# :reason - The reason for the exception
|
683
|
-
# values - "False Positive", "Compensating Control", "Acceptable Use", "Acceptable Risk", "Other"
|
684
|
-
# :scope - The scope type (NOTE: The case is important)
|
685
|
-
# values - "All Instances", "All Instances on a Specific Asset", "Specific Instance of a specific Asset"
|
686
|
-
# :comment - A user comment
|
687
|
-
# :device-id - Used for specific instances related to "All Instances on a Specific Asset" AND "Specific Instance of Specific Asset"
|
688
|
-
# :port - All assets on this port related to "Specific Instance of a specific Asset"
|
689
|
-
# :vuln-key - The vulnerability key related to the "Specific Instance of a specific Asset"
|
690
|
-
#
|
691
|
-
# @returns exception-id - The Id associated with this create request
|
692
|
-
#-------------------------------------------------------------------------------------------------------------------
|
693
|
-
def vuln_exception_create input
|
694
|
-
options = {}
|
695
|
-
|
696
|
-
if input.nil?
|
697
|
-
raise ArgumentError.new 'The input element cannot be null'
|
698
|
-
end
|
699
|
-
|
700
|
-
vuln_id = input[:vuln_id]
|
701
|
-
if !vuln_id
|
702
|
-
raise ArgumentError.new 'The vulnerability ID is required'
|
703
|
-
end
|
704
|
-
options['vuln-id'] = vuln_id
|
705
|
-
|
706
|
-
reason = input[:reason]
|
707
|
-
if reason.nil? || reason.empty?
|
708
|
-
raise ArgumentError.new 'The reason is required'
|
709
|
-
end
|
710
|
-
|
711
|
-
unless reason =~ /False Positive|Compensating Control|Acceptable Use|Acceptable Risk|Other/
|
712
|
-
raise ArgumentError.new 'The reason type is invalid'
|
713
|
-
end
|
714
|
-
options['reason'] = reason
|
715
|
-
|
716
|
-
scope = input[:scope]
|
717
|
-
if scope.nil? || scope.empty?
|
718
|
-
raise ArgumentError.new 'The scope is required'
|
719
|
-
end
|
720
|
-
|
721
|
-
# For scope case matters.
|
722
|
-
unless scope =~ /All Instances|All Instances on a Specific Asset|Specific Instance of Specific Asset/
|
723
|
-
raise ArgumentError.new 'The scope type is invalid'
|
724
|
-
end
|
725
|
-
|
726
|
-
if scope =~ /All Instances on a Specific Asset|Specific Instance of Specific Asset/
|
727
|
-
device_id = input[:device_id]
|
728
|
-
vuln_key = input[:vuln_key]
|
729
|
-
port = input[:port]
|
730
|
-
if device_id
|
731
|
-
options['device-id'] = device_id
|
732
|
-
end
|
733
|
-
|
734
|
-
if (scope =~ /All Instances on a Specific Asset/ && (vuln_key || port))
|
735
|
-
raise ArgumentError.new "Vulnerability key or port cannot be used with the scope specified"
|
736
|
-
end
|
737
|
-
|
738
|
-
if vuln_key
|
739
|
-
options['vuln-key'] = vuln_key
|
740
|
-
end
|
741
|
-
|
742
|
-
if port
|
743
|
-
options['port-no'] = port
|
744
|
-
end
|
745
|
-
end
|
746
|
-
options['scope'] = scope
|
747
|
-
|
748
|
-
xml = make_xml('VulnerabilityExceptionCreateRequest', options)
|
749
|
-
|
750
|
-
comment = input[:comment]
|
751
|
-
if comment && !comment.empty?
|
752
|
-
comment_xml = make_xml('comment', {}, comment, false)
|
753
|
-
xml.add_element comment_xml
|
754
|
-
else
|
755
|
-
raise ArgumentError.new 'The comment cannot be empty'
|
756
|
-
end
|
757
|
-
|
758
|
-
r = execute xml, '1.2'
|
759
|
-
if r.success
|
760
|
-
r.res.elements.each("//VulnerabilityExceptionCreateResponse") do |vecr|
|
761
|
-
return vecr.attributes['exception-id']
|
762
|
-
end
|
763
|
-
else
|
764
|
-
false
|
765
|
-
end
|
766
|
-
end
|
767
|
-
|
768
|
-
#-------------------------------------------------------------------------------------------------------------------
|
769
|
-
# Resubmit a vulnerability exception.
|
770
|
-
#
|
771
|
-
# @param input - data used to create the vulnerability exception:
|
772
|
-
# :vuln_id - The Nexpose vulnerability ID. (required)
|
773
|
-
# :reason - The reason for the exception (optional)
|
774
|
-
# values - "False Positive", "Compensating Control", "Acceptable Use", "Acceptable Risk", "Other"
|
775
|
-
# :comment - A user comment (required)
|
776
|
-
#-------------------------------------------------------------------------------------------------------------------
|
777
|
-
def vuln_exception_resubmit input
|
778
|
-
options = {}
|
779
|
-
|
780
|
-
if input.nil?
|
781
|
-
raise ArgumentError.new 'The input element cannot be null'
|
782
|
-
end
|
783
|
-
|
784
|
-
exception_id = input[:exception_id]
|
785
|
-
if !exception_id
|
786
|
-
raise ArgumentError.new 'The exception ID is required'
|
787
|
-
end
|
788
|
-
options['exception-id'] = exception_id
|
789
|
-
|
790
|
-
reason = input[:reason]
|
791
|
-
if !reason.nil? && !reason.empty?
|
792
|
-
unless reason =~ /False Positive|Compensating Control|Acceptable Use|Acceptable Risk|Other/
|
793
|
-
raise ArgumentError.new 'The reason type is invalid'
|
794
|
-
end
|
795
|
-
options['reason'] = reason
|
796
|
-
|
797
|
-
end
|
798
|
-
|
799
|
-
xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
|
800
|
-
|
801
|
-
comment = input[:comment]
|
802
|
-
if comment && !comment.empty?
|
803
|
-
comment_xml = make_xml('comment', {}, comment, false)
|
804
|
-
xml.add_element comment_xml
|
805
|
-
end
|
806
|
-
|
807
|
-
r = execute xml, '1.2'
|
808
|
-
r.success
|
809
|
-
end
|
810
|
-
|
811
|
-
#-------------------------------------------------------------------------------------------------------------------
|
812
|
-
# Allows a previously submitted exception that has not been approved to be withdrawn.
|
813
|
-
#
|
814
|
-
# @param exception_id - The exception id returned after the vuln exception was submitted for creation.
|
815
|
-
#-------------------------------------------------------------------------------------------------------------------
|
816
|
-
def vuln_exception_recall exception_id
|
817
|
-
xml = make_xml('VulnerabilityExceptionRecallRequest', {'exception-id' => exception_id})
|
818
|
-
r = execute xml, '1.2'
|
819
|
-
r.success
|
820
|
-
end
|
821
|
-
|
822
|
-
|
823
|
-
#-------------------------------------------------------------------------------------------------------------------
|
824
|
-
# Allows a submitted vulnerability exception to be approved.
|
825
|
-
#
|
826
|
-
# @param input:
|
827
|
-
# :exception_id - The exception id returned after the vuln exception was submitted for creation.
|
828
|
-
# :comment - An optional comment
|
829
|
-
#-------------------------------------------------------------------------------------------------------------------
|
830
|
-
def vuln_exception_approve input
|
831
|
-
exception_id = input[:exception_id]
|
832
|
-
if !exception_id
|
833
|
-
raise ArgumentError.new 'Exception Id is required'
|
834
|
-
end
|
835
|
-
|
836
|
-
xml = make_xml('VulnerabilityExceptionApproveRequest', {'exception-id' => exception_id})
|
837
|
-
comment = input[:comment]
|
838
|
-
if comment && !comment.empty?
|
839
|
-
comment_xml = make_xml('comment', {}, comment, false)
|
840
|
-
xml.add_element comment_xml
|
841
|
-
end
|
842
|
-
|
843
|
-
r = execute xml, '1.2'
|
844
|
-
r.success
|
845
|
-
end
|
846
|
-
|
847
|
-
#-------------------------------------------------------------------------------------------------------------------
|
848
|
-
# Rejects a submitted vulnerability exception to be approved.
|
849
|
-
#
|
850
|
-
# @param input:
|
851
|
-
# :exception_id - The exception id returned after the vuln exception was submitted for creation.
|
852
|
-
# :comment - An optional comment
|
853
|
-
#-------------------------------------------------------------------------------------------------------------------
|
854
|
-
def vuln_exception_reject input
|
855
|
-
exception_id = input[:exception_id]
|
856
|
-
if !exception_id
|
857
|
-
raise ArgumentError.new 'Exception Id is required'
|
858
|
-
end
|
859
|
-
|
860
|
-
xml = make_xml('VulnerabilityExceptionRejectRequest', {'exception-id' => exception_id})
|
861
|
-
comment = input[:comment]
|
862
|
-
if comment && !comment.empty?
|
863
|
-
comment_xml = make_xml('comment', {}, comment, false)
|
864
|
-
xml.add_element comment_xml
|
865
|
-
end
|
866
|
-
|
867
|
-
r = execute xml, '1.2'
|
868
|
-
r.success
|
869
|
-
end
|
870
|
-
|
871
|
-
#-------------------------------------------------------------------------------------------------------------------
|
872
|
-
# Updates a vulnerability exception comment.
|
873
|
-
#
|
874
|
-
# @param input:
|
875
|
-
# :exception_id - The exception id returned after the vuln exception was submitted for creation.
|
876
|
-
# :submitter_comment - The submitter comment
|
877
|
-
# :reviewer_comment - The reviewer comment
|
878
|
-
#-------------------------------------------------------------------------------------------------------------------
|
879
|
-
def vuln_exception_update_comment input
|
880
|
-
exception_id = input[:exception_id]
|
881
|
-
if !exception_id
|
882
|
-
raise ArgumentError.new 'Exception Id is required'
|
883
|
-
end
|
884
|
-
|
885
|
-
xml = make_xml('VulnerabilityExceptionUpdateCommentRequest', {'exception-id' => exception_id})
|
886
|
-
submitter_comment = input[:submitter_comment]
|
887
|
-
if submitter_comment && !submitter_comment.empty?
|
888
|
-
comment_xml = make_xml('submitter-comment', {}, submitter_comment, false)
|
889
|
-
xml.add_element comment_xml
|
890
|
-
end
|
891
|
-
|
892
|
-
reviewer_comment = input[:reviewer_comment]
|
893
|
-
if reviewer_comment && !reviewer_comment.empty?
|
894
|
-
comment_xml = make_xml('reviewer-comment', {}, reviewer_comment, false)
|
895
|
-
xml.add_element comment_xml
|
896
|
-
end
|
897
|
-
|
898
|
-
r = execute xml, '1.2'
|
899
|
-
r.success
|
900
|
-
end
|
901
|
-
|
902
|
-
#-------------------------------------------------------------------------------------------------------------------
|
903
|
-
# Update the expiration date for a vulnerability exception.
|
904
|
-
#
|
905
|
-
# @param input
|
906
|
-
# :exception_id - The exception id returned after the vulnerability exception was submitted for creation.
|
907
|
-
# :expiration_date - The new expiration date format: YYYY-MM-DD
|
908
|
-
#-------------------------------------------------------------------------------------------------------------------
|
909
|
-
def vuln_exception_update_expiration_date input
|
910
|
-
exception_id = input[:exception_id]
|
911
|
-
if !exception_id
|
912
|
-
raise ArgumentError.new 'Exception Id is required'
|
913
|
-
end
|
914
|
-
|
915
|
-
expiration_date = input[:expiration_date]
|
916
|
-
if expiration_date && !expiration_date.empty? && expiration_date =~ /\A\d{4}-(\d{2})-(\d{2})\z/
|
917
|
-
if $1.to_i > 12
|
918
|
-
raise ArgumentError.new 'The expiration date month value is invalid'
|
919
|
-
end
|
920
|
-
|
921
|
-
if $2.to_i > 31
|
922
|
-
raise ArgumentError.new 'The expiration date day value is invalid'
|
923
|
-
end
|
924
|
-
else
|
925
|
-
raise ArgumentError.new 'Expiration date is invalid'
|
926
|
-
end
|
927
|
-
|
928
|
-
options = {}
|
929
|
-
options['exception-id'] = exception_id
|
930
|
-
options['expiration-date'] = expiration_date
|
931
|
-
xml = make_xml('VulnerabilityExceptionUpdateExpirationDateRequest', options)
|
932
|
-
r = execute xml, '1.2'
|
933
|
-
r.success
|
934
|
-
end
|
935
|
-
|
936
|
-
#-------------------------------------------------------------------------------------------------------------------
|
937
|
-
# Deletes a submitted vulnerability exception to be approved.
|
938
|
-
#
|
939
|
-
# @param exception_id - The exception id returned after the vuln exception was submitted for creation.
|
940
|
-
#-------------------------------------------------------------------------------------------------------------------
|
941
|
-
def vuln_exception_delete exception_id
|
942
|
-
if !exception_id
|
943
|
-
raise ArgumentError.new 'Exception Id is required'
|
944
|
-
end
|
945
|
-
|
946
|
-
xml = make_xml('VulnerabilityExceptionDeleteRequest', {'exception-id' => exception_id})
|
947
|
-
r = execute xml, '1.2'
|
948
|
-
r.success
|
949
|
-
end
|
950
|
-
|
951
|
-
###################
|
952
|
-
# SILO MANAGEMENT #
|
953
|
-
###################
|
954
|
-
|
955
|
-
#########################
|
956
|
-
# MULTI-TENANT USER OPS #
|
957
|
-
#########################
|
958
|
-
|
959
|
-
#-------------------------------------------------------------------------
|
960
|
-
# Creates a multi-tenant user
|
961
|
-
#
|
962
|
-
# user_config - A map of the user data.
|
963
|
-
#
|
964
|
-
# REQUIRED PARAMS
|
965
|
-
# user-id, authsrcid, user-name, full-name, enabled, superuser
|
966
|
-
#
|
967
|
-
# OPTIONAL PARAMS
|
968
|
-
# email, password
|
969
|
-
#
|
970
|
-
# silo_configs - An array of maps of silo specific data
|
971
|
-
#
|
972
|
-
# REQUIRED PARAMS
|
973
|
-
# silo-id, role-name, all-groups, all-sites, default-silo
|
974
|
-
#
|
975
|
-
# allowed_groups/allowed_sites - An array of ids
|
976
|
-
#-------------------------------------------------------------------------
|
977
|
-
def create_multi_tenant_user(user_config, silo_configs)
|
978
|
-
xml = make_xml('MultiTenantUserCreateRequest')
|
979
|
-
mtu_config_xml = make_xml('MultiTenantUserConfig', user_config, '', false)
|
980
|
-
|
981
|
-
# Add the silo access
|
982
|
-
silo_xml = make_xml('SiloAccesses', {}, '', false)
|
983
|
-
silo_config_xml = make_xml('SiloAccess', {}, '', false)
|
984
|
-
silo_configs.keys.each do |k|
|
985
|
-
if k.eql? 'allowed_sites'
|
986
|
-
allowed_sites_xml = make_xml('AllowedSites', {}, '', false)
|
987
|
-
silo_configs['allowed_sites'].each do |allowed_site|
|
988
|
-
allowed_sites_xml.add_element make_xml('AllowedSite', {'id' => allowed_site}, '', false)
|
989
|
-
end
|
990
|
-
silo_config_xml.add_element allowed_sites_xml
|
991
|
-
elsif k.eql? 'allowed_groups'
|
992
|
-
allowed_groups_xml = make_xml('AllowedGroups', {}, '', false)
|
993
|
-
silo_configs['allowed_groups'].each do |allowed_group|
|
994
|
-
allowed_groups_xml.add_element make_xml('AllowedGroup', {'id' => allowed_group}, '', false)
|
995
|
-
end
|
996
|
-
silo_config_xml.add_element allowed_groups_xml
|
997
|
-
else
|
998
|
-
silo_config_xml.attributes[k] = silo_configs[k]
|
999
|
-
end
|
1000
|
-
end
|
1001
|
-
silo_xml.add_element silo_config_xml
|
1002
|
-
mtu_config_xml.add_element silo_xml
|
1003
|
-
xml.add_element mtu_config_xml
|
1004
|
-
r = execute xml, '1.2'
|
1005
|
-
r.success
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
|
1009
|
-
#-------------------------------------------------------------------------
|
1010
|
-
# Lists all the multi-tenant users and their attributes.
|
1011
|
-
#-------------------------------------------------------------------------
|
1012
|
-
def list_mtu
|
1013
|
-
xml = make_xml('MultiTenantUserListingRequest')
|
1014
|
-
r = execute xml, '1.2'
|
1015
|
-
|
1016
|
-
if r.success
|
1017
|
-
res = []
|
1018
|
-
r.res.elements.each("//MultiTenantUserSummary") do |mtu|
|
1019
|
-
res << {
|
1020
|
-
:id => mtu.attributes['id'],
|
1021
|
-
:full_name => mtu.attributes['full-name'],
|
1022
|
-
:user_name => mtu.attributes['user-name'],
|
1023
|
-
:email => mtu.attributes['email'],
|
1024
|
-
:super_user => mtu.attributes['superuser'],
|
1025
|
-
:enabled => mtu.attributes['enabled'],
|
1026
|
-
:auth_module => mtu.attributes['auth-module'],
|
1027
|
-
:silo_count => mtu.attributes['silo-count'],
|
1028
|
-
:locked => mtu.attributes['locked']
|
1029
|
-
}
|
1030
|
-
end
|
1031
|
-
res
|
1032
|
-
else
|
1033
|
-
false
|
1034
|
-
end
|
1035
|
-
end
|
1036
|
-
|
1037
|
-
#-------------------------------------------------------------------------
|
1038
|
-
# Delete a multi-tenant user
|
1039
|
-
#-------------------------------------------------------------------------
|
1040
|
-
def delete_mtu user_name, user_id
|
1041
|
-
using_user_name = (user_name and not user_name.empty?)
|
1042
|
-
xml = make_xml('MultiTenantUserDeleteRequest', (using_user_name ? {'user-name' => user_name} : {'user-id' => user_id}))
|
1043
|
-
r = execute xml, '1.2'
|
1044
|
-
r.success
|
1045
|
-
end
|
1046
|
-
|
1047
|
-
####################
|
1048
|
-
# SILO PROFILE OPS #
|
1049
|
-
####################
|
1050
|
-
|
1051
|
-
#-------------------------------------------------------------------------
|
1052
|
-
# Creates a silo profile
|
1053
|
-
#
|
1054
|
-
# silo_config - A map of the silo data.
|
1055
|
-
#
|
1056
|
-
# REQUIRED PARAMS
|
1057
|
-
# id, name, all‐licensed-modules, all‐global-engines, all-global-report-templates, all‐global-scan‐templates
|
1058
|
-
#
|
1059
|
-
# OPTIONAL PARAMS
|
1060
|
-
# description
|
1061
|
-
#
|
1062
|
-
# permissions - A map of an array of maps of silo specific data
|
1063
|
-
#
|
1064
|
-
# REQUIRED PARAMS
|
1065
|
-
# silo-id, role-name, all-groups, all-sites, default-silo
|
1066
|
-
#
|
1067
|
-
# allowed_groups/allowed_sites - An array of ids
|
1068
|
-
#-------------------------------------------------------------------------
|
1069
|
-
def create_silo_profile silo_profile_config, permissions
|
1070
|
-
xml = make_xml 'SiloProfileCreateRequest'
|
1071
|
-
spc_xml = make_xml('SiloProfileConfig', silo_profile_config, '', false)
|
1072
|
-
|
1073
|
-
# Add the permissions
|
1074
|
-
if permissions['global_report_templates']
|
1075
|
-
grt_xml = make_xml('GlobalReportTemplates', {}, '', false)
|
1076
|
-
permissions['global_report_templates'].each do |name|
|
1077
|
-
grt_xml.add_element make_xml('GlobalReportTemplate', {'name' => name}, '', false)
|
1078
|
-
end
|
1079
|
-
spc_xml.add_element grt_xml
|
1080
|
-
end
|
1081
|
-
|
1082
|
-
if permissions['global_scan_engines']
|
1083
|
-
gse_xml = make_xml('GlobalScanEngines', {}, '', false)
|
1084
|
-
permissions['global_scan_engines'].each do |name|
|
1085
|
-
gse_xml.add_element make_xml('GlobalScanEngine', {'name' => name}, '', false)
|
1086
|
-
end
|
1087
|
-
spc_xml.add_element gse_xml
|
1088
|
-
end
|
1089
|
-
|
1090
|
-
if permissions['global_scan_templates']
|
1091
|
-
gst_xml = make_xml('GlobalScanTemplates', {}, '', false)
|
1092
|
-
permissions['global_scan_templates'].each do |name|
|
1093
|
-
gst_xml.add_element make_xml('GlobalScanTemplate', {'name' => name}, '', false)
|
1094
|
-
end
|
1095
|
-
spc_xml.add_element gst_xml
|
1096
|
-
end
|
1097
|
-
|
1098
|
-
if permissions['licensed_modules']
|
1099
|
-
lm_xml = make_xml('LicensedModules', {}, '', false)
|
1100
|
-
permissions['licensed_modules'].each do |name|
|
1101
|
-
lm_xml.add_element make_xml('LicensedModule', {'name' => name}, '', false)
|
1102
|
-
end
|
1103
|
-
spc_xml.add_element lm_xml
|
1104
|
-
end
|
1105
|
-
|
1106
|
-
if permissions['restricted_report_formats']
|
1107
|
-
rrf_xml = make_xml('RestrictedReportFormats', {}, '', false)
|
1108
|
-
permissions['restricted_report_formats'].each do |name|
|
1109
|
-
rrf_xml.add_element make_xml('RestrictedReportFormat', {'name' => name}, '', false)
|
1110
|
-
end
|
1111
|
-
spc_xml.add_element rrf_xml
|
1112
|
-
end
|
1113
|
-
|
1114
|
-
if permissions['restricted_report_sections']
|
1115
|
-
rrs_xml = make_xml('RestrictedReportSections', {}, '', false)
|
1116
|
-
permissions['restricted_report_sections'].each do |name|
|
1117
|
-
rrs_xml.add_element make_xml('RestrictedReportSection', {'name' => name}, '', false)
|
1118
|
-
end
|
1119
|
-
spc_xml.add_element rrs_xml
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
xml.add_element spc_xml
|
1123
|
-
r = execute xml, '1.2'
|
1124
|
-
r.success
|
1125
|
-
end
|
1126
|
-
|
1127
|
-
#-------------------------------------------------------------------------
|
1128
|
-
# Lists all the silo profiles and their attributes.
|
1129
|
-
#-------------------------------------------------------------------------
|
1130
|
-
def list_silo_profiles
|
1131
|
-
xml = make_xml('SiloProfileListingRequest')
|
1132
|
-
r = execute xml, '1.2'
|
1133
|
-
|
1134
|
-
if r.success
|
1135
|
-
res = []
|
1136
|
-
r.res.elements.each("//SiloProfileSummary") do |silo_profile|
|
1137
|
-
res << {
|
1138
|
-
:id => silo_profile.attributes['id'],
|
1139
|
-
:name => silo_profile.attributes['name'],
|
1140
|
-
:description => silo_profile.attributes['description'],
|
1141
|
-
:global_report_template_count => silo_profile.attributes['global-report-template-count'],
|
1142
|
-
:global_scan_engine_count => silo_profile.attributes['global-scan-engine-count'],
|
1143
|
-
:global_scan_template_count => silo_profile.attributes['global-scan-template-count'],
|
1144
|
-
:licensed_module_count => silo_profile.attributes['licensed-module-count'],
|
1145
|
-
:restricted_report_section_count => silo_profile.attributes['restricted-report-section-count'],
|
1146
|
-
:all_licensed_modules => silo_profile.attributes['all-licensed-modules'],
|
1147
|
-
:all_global_engines => silo_profile.attributes['all-global-engines'],
|
1148
|
-
:all_global_report_templates => silo_profile.attributes['all-global-report-templates'],
|
1149
|
-
:all_global_scan_templates => silo_profile.attributes['all-global-scan-templates']
|
1150
|
-
}
|
1151
|
-
end
|
1152
|
-
res
|
1153
|
-
else
|
1154
|
-
false
|
1155
|
-
end
|
1156
|
-
end
|
1157
|
-
|
1158
|
-
#-------------------------------------------------------------------------
|
1159
|
-
# Delete a silo profile
|
1160
|
-
#-------------------------------------------------------------------------
|
1161
|
-
def delete_silo_profile name, id
|
1162
|
-
using_name = (name and not name.empty?)
|
1163
|
-
xml = make_xml('SiloProfileDeleteRequest', (using_name ? {'name' => name} : {'silo-profile-id' => id}))
|
1164
|
-
r = execute xml, '1.2'
|
1165
|
-
r.success
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
####################
|
1169
|
-
# SILO OPS #
|
1170
|
-
####################
|
1171
|
-
|
1172
|
-
#-------------------------------------------------------------------------
|
1173
|
-
# Creates a silo
|
1174
|
-
#
|
1175
|
-
# silo_config - A map of the silo creation data.
|
1176
|
-
#
|
1177
|
-
# REQUIRED PARAMS
|
1178
|
-
# id, name, silo-profile-id, max-assets, max-hosted-assets, max-users
|
1179
|
-
#
|
1180
|
-
# OPTIONAL PARAMS
|
1181
|
-
# description
|
1182
|
-
#-------------------------------------------------------------------------
|
1183
|
-
def create_silo silo_config
|
1184
|
-
xml = make_xml 'SiloCreateRequest'
|
1185
|
-
silo_config_xml = make_xml 'SiloConfig', {}, '', false
|
1186
|
-
|
1187
|
-
# Add the attributes
|
1188
|
-
silo_config.keys.each do |key|
|
1189
|
-
if not 'merchant'.eql? key and not 'organization'.eql? key
|
1190
|
-
silo_config_xml.attributes[key] = silo_config[key]
|
1191
|
-
end
|
1192
|
-
end
|
1193
|
-
|
1194
|
-
# Add Organization info
|
1195
|
-
if silo_config['organization']
|
1196
|
-
org_xml = make_xml 'Organization', {}, '', false
|
1197
|
-
silo_config['organization'].keys.each do |key|
|
1198
|
-
if not 'address'.eql? key
|
1199
|
-
org_xml.attributes[key] = silo_config['organization'][key]
|
1200
|
-
end
|
1201
|
-
end
|
1202
|
-
|
1203
|
-
address_xml = make_xml 'Address', silo_config['organization']['address'], '', false
|
1204
|
-
org_xml.add_element address_xml
|
1205
|
-
silo_config_xml.add_element org_xml
|
1206
|
-
end
|
1207
|
-
|
1208
|
-
# Add Merchant info
|
1209
|
-
if silo_config['merchant']
|
1210
|
-
merchant_xml = make_xml 'Merchant', {}, '', false
|
1211
|
-
|
1212
|
-
silo_config['merchant'].keys.each do |key|
|
1213
|
-
if not 'dba'.eql? key and not 'other_industries'.eql? key and not 'qsa'.eql? key and not 'address'.eql? key
|
1214
|
-
merchant_xml.attributes[key] = silo_config['merchant'][key]
|
1215
|
-
end
|
1216
|
-
end
|
1217
|
-
|
1218
|
-
# Add the merchant address
|
1219
|
-
merchant_address_xml = make_xml 'Address', silo_config['merchant']['address'], '', false
|
1220
|
-
merchant_xml.add_element merchant_address_xml
|
1221
|
-
|
1222
|
-
#Now add the complex data types
|
1223
|
-
if silo_config['merchant']['dba']
|
1224
|
-
dba_xml = make_xml 'DBAs', {}, '', false
|
1225
|
-
silo_config['merchant']['dba'].each do |name|
|
1226
|
-
dba_xml.add_element make_xml('DBA', {'name' => name}, '', false)
|
1227
|
-
end
|
1228
|
-
merchant_xml.add_element dba_xml
|
1229
|
-
end
|
1230
|
-
|
1231
|
-
if silo_config['merchant']['other_industries']
|
1232
|
-
ois_xml = make_xml 'OtherIndustries', {}, '', false
|
1233
|
-
silo_config['merchant']['other_industries'].each do |name|
|
1234
|
-
ois_xml.add_element make_xml('Industry', {'name' => name}, '', false)
|
1235
|
-
end
|
1236
|
-
merchant_xml.add_element ois_xml
|
1237
|
-
end
|
1238
|
-
|
1239
|
-
if silo_config['merchant']['qsa']
|
1240
|
-
qsa_xml = make_xml 'QSA', {}, '', false
|
1241
|
-
silo_config['merchant']['qsa'].keys.each do |key|
|
1242
|
-
if not 'address'.eql? key
|
1243
|
-
qsa_xml.attributes[key] = silo_config['merchant']['qsa'][key]
|
1244
|
-
end
|
1245
|
-
end
|
1246
|
-
|
1247
|
-
# Add the address for this QSA
|
1248
|
-
address_xml = make_xml 'Address', silo_config['merchant']['qsa']['address'], '', false
|
1249
|
-
|
1250
|
-
qsa_xml.add_element address_xml
|
1251
|
-
merchant_xml.add_element qsa_xml
|
1252
|
-
end
|
1253
|
-
silo_config_xml.add_element merchant_xml
|
1254
|
-
end
|
1255
|
-
|
1256
|
-
xml.add_element silo_config_xml
|
1257
|
-
r = execute xml, '1.2'
|
1258
|
-
r.success
|
1259
|
-
end
|
1260
|
-
|
1261
|
-
#-------------------------------------------------------------------------
|
1262
|
-
# Lists all the silos and their attributes.
|
1263
|
-
#-------------------------------------------------------------------------
|
1264
|
-
def list_silos
|
1265
|
-
xml = make_xml('SiloListingRequest')
|
1266
|
-
r = execute xml, '1.2'
|
1267
|
-
|
1268
|
-
if r.success
|
1269
|
-
res = []
|
1270
|
-
r.res.elements.each("//SiloSummary") do |silo_profile|
|
1271
|
-
res << {
|
1272
|
-
:id => silo_profile.attributes['id'],
|
1273
|
-
:name => silo_profile.attributes['name'],
|
1274
|
-
:description => silo_profile.attributes['description']
|
1275
|
-
}
|
1276
|
-
end
|
1277
|
-
res
|
1278
|
-
else
|
1279
|
-
false
|
1280
|
-
end
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
#-------------------------------------------------------------------------
|
1284
|
-
# Delete a silo
|
1285
|
-
#-------------------------------------------------------------------------
|
1286
|
-
def delete_silo name, id
|
1287
|
-
using_name = (name and not name.empty?)
|
1288
|
-
xml = make_xml('SiloDeleteRequest', (using_name ? {'silo-name' => name} : {'silo-id' => id}))
|
1289
|
-
r = execute xml, '1.2'
|
1290
|
-
r.success
|
1291
|
-
end
|
1292
|
-
|
1293
|
-
def site_device_listing(site_id)
|
1294
|
-
r = execute(make_xml('SiteDeviceListingRequest', { 'site-id' => site_id.to_s }))
|
1295
|
-
|
1296
|
-
if(r.success)
|
1297
|
-
res = []
|
1298
|
-
r.res.elements.each("//device") do |device|
|
1299
|
-
res << {
|
1300
|
-
:device_id => device.attributes['id'].to_i,
|
1301
|
-
:address => device.attributes['address'].to_s,
|
1302
|
-
:risk_factor => device.attributes['risk_factor'].to_f,
|
1303
|
-
:risk_score => device.attributes['risk_score'].to_f,
|
1304
|
-
}
|
1305
|
-
end
|
1306
|
-
return res
|
1307
|
-
else
|
1308
|
-
return false
|
1309
|
-
end
|
1310
|
-
end
|
1311
|
-
|
1312
|
-
def report_template_listing
|
1313
|
-
r = execute(make_xml('ReportTemplateListingRequest', { }))
|
1314
|
-
|
1315
|
-
if(r.success)
|
1316
|
-
res = []
|
1317
|
-
r.res.elements.each("//ReportTemplateSummary") do |template|
|
1318
|
-
desc = ''
|
1319
|
-
template.elements.each("//description") do |ent|
|
1320
|
-
desc = ent.text
|
1321
|
-
end
|
1322
|
-
|
1323
|
-
res << {
|
1324
|
-
:template_id => template.attributes['id'].to_s,
|
1325
|
-
:name => template.attributes['name'].to_s,
|
1326
|
-
:description => desc.to_s
|
1327
|
-
}
|
1328
|
-
end
|
1329
|
-
return res
|
1330
|
-
else
|
1331
|
-
return false
|
1332
|
-
end
|
1333
|
-
end
|
1334
|
-
|
1335
|
-
|
1336
|
-
def console_command(cmd_string)
|
1337
|
-
xml = make_xml('ConsoleCommandRequest', { })
|
1338
|
-
cmd = REXML::Element.new('Command')
|
1339
|
-
cmd.text = cmd_string
|
1340
|
-
xml << cmd
|
1341
|
-
|
1342
|
-
r = execute(xml)
|
1343
|
-
|
1344
|
-
if(r.success)
|
1345
|
-
res = ""
|
1346
|
-
r.res.elements.each("//Output") do |out|
|
1347
|
-
res << out.text.to_s
|
1348
|
-
end
|
1349
|
-
|
1350
|
-
return res
|
1351
|
-
else
|
1352
|
-
return false
|
1353
|
-
end
|
1354
|
-
end
|
1355
|
-
|
1356
|
-
def system_information
|
1357
|
-
r = execute(make_xml('SystemInformationRequest', { }))
|
1358
|
-
|
1359
|
-
if(r.success)
|
1360
|
-
res = {}
|
1361
|
-
r.res.elements.each("//Statistic") do |stat|
|
1362
|
-
res[ stat.attributes['name'].to_s ] = stat.text.to_s
|
1363
|
-
end
|
1364
|
-
|
1365
|
-
return res
|
1366
|
-
else
|
1367
|
-
return false
|
1368
|
-
end
|
1369
|
-
end
|
1370
|
-
|
1371
|
-
end
|
1372
|
-
|
1373
|
-
# === Description
|
1374
|
-
# Object that represents a connection to a NeXpose Security Console.
|
1375
|
-
#
|
1376
|
-
# === Examples
|
1377
|
-
# # Create a new Nexpose Connection on the default port
|
1378
|
-
# nsc = Connection.new("10.1.40.10","nxadmin","password")
|
1379
|
-
#
|
1380
|
-
# # Login to NSC and Establish a Session ID
|
1381
|
-
# nsc.login()
|
1382
|
-
#
|
1383
|
-
# # Check Session ID
|
1384
|
-
# if (nsc.session_id)
|
1385
|
-
# puts "Login Successful"
|
1386
|
-
# else
|
1387
|
-
# puts "Login Failure"
|
1388
|
-
# end
|
1389
|
-
#
|
1390
|
-
# # //Logout
|
1391
|
-
# logout_success = nsc.logout()
|
1392
|
-
# if (! logout_success)
|
1393
|
-
# puts "Logout Failure" + "<p>" + nsc.error_msg.to_s
|
1394
|
-
# end
|
1395
|
-
#
|
1396
|
-
class Connection
|
1397
|
-
include XMLUtils
|
1398
|
-
include NexposeAPI
|
1399
|
-
|
1400
|
-
# true if an error condition exists; false otherwise
|
1401
|
-
attr_reader :error
|
1402
|
-
# Error message string
|
1403
|
-
attr_reader :error_msg
|
1404
|
-
# The last XML request sent by this object
|
1405
|
-
attr_reader :request_xml
|
1406
|
-
# The last XML response received by this object
|
1407
|
-
attr_reader :response_xml
|
1408
|
-
# Session ID of this connection
|
1409
|
-
attr_reader :session_id
|
1410
|
-
# The hostname or IP Address of the NSC
|
1411
|
-
attr_reader :host
|
1412
|
-
# The port of the NSC (default is 3780)
|
1413
|
-
attr_reader :port
|
1414
|
-
# The username used to login to the NSC
|
1415
|
-
attr_reader :username
|
1416
|
-
# The password used to login to the NSC
|
1417
|
-
attr_reader :password
|
1418
|
-
# The URL for communication
|
1419
|
-
attr_reader :url
|
1420
|
-
|
1421
|
-
# Constructor for Connection
|
1422
|
-
def initialize(ip, user, pass, port = 3780, silo_id = nil)
|
1423
|
-
@host = ip
|
1424
|
-
@port = port
|
1425
|
-
@username = user
|
1426
|
-
@password = pass
|
1427
|
-
@silo_id = silo_id
|
1428
|
-
@session_id = nil
|
1429
|
-
@error = false
|
1430
|
-
@url = "https://#{@host}:#{@port}/api/API_VERSION/xml"
|
1431
|
-
end
|
1432
|
-
|
1433
|
-
# Establish a new connection and Session ID
|
1434
|
-
def login
|
1435
|
-
begin
|
1436
|
-
login_hash = { 'sync-id' => 0, 'password' => @password, 'user-id' => @username }
|
1437
|
-
unless @silo_id.nil?
|
1438
|
-
login_hash['silo-id'] = @silo_id
|
1439
|
-
end
|
1440
|
-
r = execute(make_xml('LoginRequest', login_hash))
|
1441
|
-
rescue APIError
|
1442
|
-
raise AuthenticationFailed.new(r)
|
1443
|
-
end
|
1444
|
-
if(r.success)
|
1445
|
-
@session_id = r.sid
|
1446
|
-
return true
|
1447
|
-
end
|
1448
|
-
end
|
1449
|
-
|
1450
|
-
# Logout of the current connection
|
1451
|
-
def logout
|
1452
|
-
r = execute(make_xml('LogoutRequest', {'sync-id' => 0}))
|
1453
|
-
if(r.success)
|
1454
|
-
return true
|
1455
|
-
end
|
1456
|
-
raise APIError.new(r, 'Logout failed')
|
1457
|
-
end
|
1458
|
-
|
1459
|
-
# Execute an API request
|
1460
|
-
def execute(xml, version = '1.1')
|
1461
|
-
@api_version = version
|
1462
|
-
APIRequest.execute(@url,xml.to_s, @api_version)
|
1463
|
-
end
|
1464
|
-
|
1465
|
-
# Download a specific URL
|
1466
|
-
def download(url)
|
1467
|
-
uri = URI.parse(url)
|
1468
|
-
http = Net::HTTP.new(@host, @port)
|
1469
|
-
http.use_ssl = true
|
1470
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # XXX: security issue
|
1471
|
-
headers = {'Cookie' => "nexposeCCSessionID=#{@session_id}"}
|
1472
|
-
resp, data = http.get(uri.path, headers)
|
1473
|
-
data
|
1474
|
-
end
|
1475
|
-
end
|
1476
|
-
|
1477
|
-
# === Description
|
1478
|
-
# Object that represents a listing of all of the sites available on an NSC.
|
1479
|
-
#
|
1480
|
-
# === Example
|
1481
|
-
# # Create a new Nexpose Connection on the default port and Login
|
1482
|
-
# nsc = Connection.new("10.1.40.10","nxadmin","password")
|
1483
|
-
# nsc->login();
|
1484
|
-
#
|
1485
|
-
# # Get Site Listing
|
1486
|
-
# sitelisting = SiteListing.new(nsc)
|
1487
|
-
#
|
1488
|
-
# # Enumerate through all of the SiteSummaries
|
1489
|
-
# sitelisting.sites.each do |sitesummary|
|
1490
|
-
# # Do some operation on each site
|
1491
|
-
# end
|
1492
|
-
#
|
1493
|
-
class SiteListing
|
1494
|
-
# true if an error condition exists; false otherwise
|
1495
|
-
attr_reader :error
|
1496
|
-
# Error message string
|
1497
|
-
attr_reader :error_msg
|
1498
|
-
# The last XML request sent by this object
|
1499
|
-
attr_reader :request_xml
|
1500
|
-
# The last XML response received by this object
|
1501
|
-
attr_reader :response_xml
|
1502
|
-
# The NSC Connection associated with this object
|
1503
|
-
attr_reader :connection
|
1504
|
-
# Array containing SiteSummary objects for each site in the connection
|
1505
|
-
attr_reader :sites
|
1506
|
-
# The number of sites
|
1507
|
-
attr_reader :site_count
|
1508
|
-
|
1509
|
-
# Constructor
|
1510
|
-
# SiteListing (connection)
|
1511
|
-
def initialize(connection)
|
1512
|
-
@sites = []
|
1513
|
-
|
1514
|
-
@connection = connection
|
1515
|
-
|
1516
|
-
r = @connection.execute('<SiteListingRequest session-id="' + @connection.session_id.to_s + '"/>')
|
1517
|
-
|
1518
|
-
if (r.success)
|
1519
|
-
parse(r.res)
|
1520
|
-
else
|
1521
|
-
raise APIError.new(r, "Failed to get site listing")
|
1522
|
-
end
|
1523
|
-
end
|
1524
|
-
|
1525
|
-
def parse(r)
|
1526
|
-
r.elements.each('SiteListingResponse/SiteSummary') do |s|
|
1527
|
-
site_summary = SiteSummary.new(
|
1528
|
-
s.attributes['id'].to_s,
|
1529
|
-
s.attributes['name'].to_s,
|
1530
|
-
s.attributes['description'].to_s,
|
1531
|
-
s.attributes['riskfactor'].to_s
|
1532
|
-
)
|
1533
|
-
@sites.push(site_summary)
|
1534
|
-
end
|
1535
|
-
@site_count = @sites.length
|
1536
|
-
end
|
1537
|
-
end
|
1538
|
-
|
1539
|
-
# === Description
|
1540
|
-
# Object that represents the summary of a NeXpose Site.
|
1541
|
-
#
|
1542
|
-
class SiteSummary
|
1543
|
-
# The Site ID
|
1544
|
-
attr_reader :id
|
1545
|
-
# The Site Name
|
1546
|
-
attr_reader :site_name
|
1547
|
-
# A Description of the Site
|
1548
|
-
attr_reader :description
|
1549
|
-
# User assigned risk multiplier
|
1550
|
-
attr_reader :riskfactor
|
1551
|
-
|
1552
|
-
# Constructor
|
1553
|
-
# SiteSummary(id, site_name, description, riskfactor = 1)
|
1554
|
-
def initialize(id, site_name, description, riskfactor = 1)
|
1555
|
-
@id = id
|
1556
|
-
@site_name = site_name
|
1557
|
-
@description = description
|
1558
|
-
@riskfactor = riskfactor
|
1559
|
-
end
|
1560
|
-
|
1561
|
-
def _set_id(id)
|
1562
|
-
@id = id
|
1563
|
-
end
|
1564
|
-
end
|
1565
|
-
|
1566
|
-
# === Description
|
1567
|
-
# Object that represents a single IP address or an inclusive range of IP addresses. If to is nil then the from field will be used to specify a single IP Address only.
|
1568
|
-
#
|
1569
|
-
class IPRange
|
1570
|
-
# Start of Range *Required
|
1571
|
-
attr_reader :from;
|
1572
|
-
# End of Range *Optional (If Null then IPRange is a single IP Address)
|
1573
|
-
attr_reader :to;
|
1574
|
-
|
1575
|
-
def initialize(from, to = nil)
|
1576
|
-
@from = from
|
1577
|
-
@to = to
|
1578
|
-
end
|
1579
|
-
|
1580
|
-
include Sanitize
|
1581
|
-
def to_xml
|
1582
|
-
if (to and not to.empty?)
|
1583
|
-
return %Q{<range from="#{from}" to="#{to}"/>}
|
1584
|
-
else
|
1585
|
-
return %Q{<range from="#{from}"/>}
|
1586
|
-
end
|
1587
|
-
end
|
1588
|
-
end
|
1589
|
-
|
1590
|
-
# === Description
|
1591
|
-
# Object that represents a hostname to be added to a site.
|
1592
|
-
class HostName
|
1593
|
-
|
1594
|
-
# The hostname
|
1595
|
-
attr_reader :hostname
|
1596
|
-
|
1597
|
-
def initialize(hostname)
|
1598
|
-
@hostname = hostname
|
1599
|
-
end
|
1600
|
-
|
1601
|
-
include Sanitize
|
1602
|
-
def to_xml
|
1603
|
-
"<hostname>#{replace_entities(hostname)}</hostname>"
|
1604
|
-
end
|
1605
|
-
end
|
1606
|
-
|
1607
|
-
# === Description
|
1608
|
-
# Object that represents the configuration of a Site. This object is automatically created when a new Site object is instantiated.
|
1609
|
-
#
|
1610
|
-
class SiteConfig
|
1611
|
-
# true if an error condition exists; false otherwise
|
1612
|
-
attr_reader :error
|
1613
|
-
# Error message string
|
1614
|
-
attr_reader :error_msg
|
1615
|
-
# The last XML request sent by this object
|
1616
|
-
attr_reader :request_xml
|
1617
|
-
# The last XML response received by this object
|
1618
|
-
attr_reader :response_xml
|
1619
|
-
# The NSC Connection associated with this object
|
1620
|
-
attr_reader :connection
|
1621
|
-
# The Site ID
|
1622
|
-
attr_reader :site_id
|
1623
|
-
# The Site Name
|
1624
|
-
attr_reader :site_name
|
1625
|
-
# A Description of the Site
|
1626
|
-
attr_reader :description
|
1627
|
-
# User assigned risk multiplier
|
1628
|
-
attr_reader :riskfactor
|
1629
|
-
# Array containing ((IPRange|HostName)*)
|
1630
|
-
attr_reader :hosts
|
1631
|
-
# Array containing (AdminCredentials*)
|
1632
|
-
attr_reader :credentials
|
1633
|
-
# Array containing ((SmtpAlera|SnmpAlert|SyslogAlert)*)
|
1634
|
-
attr_reader :alerts
|
1635
|
-
# ScanConfig object which holds Schedule and ScanTrigger Objects
|
1636
|
-
attr_reader :scanConfig
|
1637
|
-
|
1638
|
-
def initialize()
|
1639
|
-
@xml_tag_stack = Array.new()
|
1640
|
-
@hosts = Array.new()
|
1641
|
-
@credentials = Array.new()
|
1642
|
-
@alerts = Array.new()
|
1643
|
-
@error = false
|
1644
|
-
end
|
1645
|
-
|
1646
|
-
# Adds a new host to the hosts array
|
1647
|
-
def addHost(host)
|
1648
|
-
@hosts.push(host)
|
1649
|
-
end
|
1650
|
-
|
1651
|
-
# Adds a new alert to the alerts array
|
1652
|
-
def addAlert(alert)
|
1653
|
-
@alerts.push(alert)
|
1654
|
-
end
|
1655
|
-
|
1656
|
-
# Adds a new set of credentials to the credentials array
|
1657
|
-
def addCredentials(credential)
|
1658
|
-
@credentials.push(credential)
|
1659
|
-
end
|
1660
|
-
|
1661
|
-
# TODO
|
1662
|
-
def getSiteConfig(connection,site_id)
|
1663
|
-
@connection = connection
|
1664
|
-
@site_id = site_id
|
1665
|
-
|
1666
|
-
r = APIRequest.execute(@connection.url,'<SiteConfigRequest session-id="' + @connection.session_id + '" site-id="' + @site_id + '"/>')
|
1667
|
-
parse(r.res)
|
1668
|
-
end
|
1669
|
-
|
1670
|
-
def _set_site_id(site_id)
|
1671
|
-
@site_id = site_id
|
1672
|
-
end
|
1673
|
-
|
1674
|
-
def _set_site_name(site_name)
|
1675
|
-
@site_name = site_name
|
1676
|
-
end
|
1677
|
-
|
1678
|
-
def _set_description(description)
|
1679
|
-
@description = description
|
1680
|
-
end
|
1681
|
-
|
1682
|
-
def _set_riskfactor(riskfactor)
|
1683
|
-
@riskfactor = riskfactor
|
1684
|
-
end
|
1685
|
-
|
1686
|
-
def _set_scanConfig(scanConfig)
|
1687
|
-
@scanConfig = scanConfig
|
1688
|
-
end
|
1689
|
-
|
1690
|
-
def _set_connection(connection)
|
1691
|
-
@connection = connection
|
1692
|
-
end
|
1693
|
-
=begin
|
1694
|
-
<SiteConfigResponse success='1'>
|
1695
|
-
<Site name='Site1' id='243' description='' riskfactor='1.0'>
|
1696
|
-
<Hosts>
|
1697
|
-
<range from='127.0.0.1'/>
|
1698
|
-
</Hosts>
|
1699
|
-
<Credentials>
|
1700
|
-
</Credentials>
|
1701
|
-
<Alerting>
|
1702
|
-
</Alerting>
|
1703
|
-
<ScanConfig configID='243' name='Full audit' configVersion='3' engineID='2' templateID='full-audit'>
|
1704
|
-
<Schedules>
|
1705
|
-
</Schedules>
|
1706
|
-
<ScanTriggers>
|
1707
|
-
</ScanTriggers>
|
1708
|
-
</ScanConfig>
|
1709
|
-
</Site>
|
1710
|
-
|
1711
|
-
=end
|
1712
|
-
|
1713
|
-
def parse(response)
|
1714
|
-
response.elements.each('SiteConfigResponse/Site') do |s|
|
1715
|
-
@site_id = s.attributes['id']
|
1716
|
-
@site_name = s.attributes['name']
|
1717
|
-
@description = s.attributes['description']
|
1718
|
-
@riskfactor = s.attributes['riskfactor']
|
1719
|
-
s.elements.each('Hosts/range') do |r|
|
1720
|
-
@hosts.push(IPRange.new(r.attributes['from'],r.attributes['to']))
|
1721
|
-
end
|
1722
|
-
s.elements.each('ScanConfig') do |c|
|
1723
|
-
@scanConfig = ScanConfig.new(c.attributes['configID'],
|
1724
|
-
c.attributes['name'],
|
1725
|
-
c.attributes['configVersion'],
|
1726
|
-
c.attributes['templateID'])
|
1727
|
-
s.elements.each('Schedule') do |schedule|
|
1728
|
-
schedule = new Schedule(schedule.attributes["type"], schedule.attributes["interval"], schedule.attributes["start"], schedule.attributes["enabled"])
|
1729
|
-
@scanConfig.addSchedule(schedule)
|
1730
|
-
end
|
1731
|
-
end
|
1732
|
-
|
1733
|
-
s.elements.each('Alerting/Alert') do |a|
|
1734
|
-
|
1735
|
-
a.elements.each('smtpAlert') do |smtp|
|
1736
|
-
smtp_alert = SmtpAlert.new(a.attributes["name"], smtp.attributes["sender"], smtp.attributes["limitText"], a.attributes["enabled"])
|
1737
|
-
|
1738
|
-
smtp.elements.each('recipient') do |recipient|
|
1739
|
-
smtp_alert.addRecipient(recipient.text)
|
1740
|
-
end
|
1741
|
-
@alerts.push(smtp_alert)
|
1742
|
-
end
|
1743
|
-
|
1744
|
-
a.elements.each('snmpAlert') do |snmp|
|
1745
|
-
snmp_alert = SnmpAlert.new(a.attributes["name"], snmp.attributes["community"], snmp.attributes["server"], a.attributes["enabled"])
|
1746
|
-
@alerts.push(snmp_alert)
|
1747
|
-
end
|
1748
|
-
a.elements.each('syslogAlert') do |syslog|
|
1749
|
-
syslog_alert = SyslogAlert.new(a.attributes["name"], syslog.attributes["server"], a.attributes["enabled"])
|
1750
|
-
@alerts.push(syslog_alert)
|
1751
|
-
end
|
1752
|
-
|
1753
|
-
a.elements.each('vulnFilter') do |vulnFilter|
|
1754
|
-
|
1755
|
-
#vulnfilter = new VulnFilter.new(a.attributes["typemask"], a.attributes["severityThreshold"], $attrs["MAXALERTS"])
|
1756
|
-
# Pop off the top alert on the stack
|
1757
|
-
#$alert = @alerts.pop()
|
1758
|
-
# Add the new recipient string to the Alert Object
|
1759
|
-
#$alert.setVulnFilter($vulnfilter)
|
1760
|
-
# Push the alert back on to the alert stack
|
1761
|
-
#array_push($this->alerts, $alert)
|
1762
|
-
end
|
1763
|
-
|
1764
|
-
a.elements.each('scanFilter') do |scanFilter|
|
1765
|
-
#<scanFilter scanStop='0' scanFailed='0' scanStart='1'/>
|
1766
|
-
#scanfilter = ScanFilter.new(scanFilter.attributes['scanStop'],scanFilter.attributes['scanFailed'],scanFilter.attributes['scanStart'])
|
1767
|
-
#alert = @alerts.pop()
|
1768
|
-
#alert.setScanFilter(scanfilter)
|
1769
|
-
#@alerts.push(alert)
|
1770
|
-
end
|
1771
|
-
end
|
1772
|
-
end
|
1773
|
-
end
|
1774
|
-
end
|
1775
|
-
|
1776
|
-
# === Description
|
1777
|
-
# Object that represents the scan history of a site.
|
1778
|
-
#
|
1779
|
-
class SiteScanHistory
|
1780
|
-
# true if an error condition exists; false otherwise
|
1781
|
-
attr_reader :error
|
1782
|
-
# Error message string
|
1783
|
-
attr_reader :error_msg
|
1784
|
-
# The last XML request sent by this object
|
1785
|
-
attr_reader :request_xml
|
1786
|
-
# The last XML response received by this object
|
1787
|
-
attr_reader :response_xml
|
1788
|
-
# The NSC Connection associated with this object
|
1789
|
-
attr_reader :connection
|
1790
|
-
# The Site ID
|
1791
|
-
attr_reader :site_id
|
1792
|
-
# //Array containing (ScanSummary*)
|
1793
|
-
attr_reader :scan_summaries
|
1794
|
-
|
1795
|
-
def initialize(connection, id)
|
1796
|
-
@site_id = id
|
1797
|
-
@error = false
|
1798
|
-
@connection = connection
|
1799
|
-
@scan_summaries = Array.new()
|
1800
|
-
|
1801
|
-
r = @connection.execute('<SiteScanHistoryRequest' + ' session-id="' + @connection.session_id + '" site-id="' + @site_id + '"/>')
|
1802
|
-
status = r.success
|
1803
|
-
end
|
1804
|
-
end
|
1805
|
-
|
1806
|
-
# === Description
|
1807
|
-
# Object that represents a listing of devices for a site or the entire NSC. Note that only devices which are accessible to the account used to create the connection object will be returned. This object is created and populated automatically with the instantiation of a new Site object.
|
1808
|
-
#
|
1809
|
-
class SiteDeviceListing
|
1810
|
-
|
1811
|
-
# true if an error condition exists; false otherwise
|
1812
|
-
attr_reader :error
|
1813
|
-
# Error message string
|
1814
|
-
attr_reader :error_msg
|
1815
|
-
# The last XML request sent by this object
|
1816
|
-
attr_reader :request_xml
|
1817
|
-
# The last XML response received by this object
|
1818
|
-
attr_reader :response_xml
|
1819
|
-
# The NSC Connection associated with this object
|
1820
|
-
attr_reader :connection
|
1821
|
-
# The Site ID. 0 if all sites are specified.
|
1822
|
-
attr_reader :site_id
|
1823
|
-
# //Array of (Device)*
|
1824
|
-
attr_reader :devices
|
1825
|
-
|
1826
|
-
def initialize(connection, site_id = 0)
|
1827
|
-
|
1828
|
-
@site_id = site_id
|
1829
|
-
@error = false
|
1830
|
-
@connection = connection
|
1831
|
-
@devices = Array.new()
|
1832
|
-
|
1833
|
-
r = nil
|
1834
|
-
if (@site_id)
|
1835
|
-
r = @connection.execute('<SiteDeviceListingRequest session-id="' + connection.session_id + '" site-id="' + @site_id + '"/>')
|
1836
|
-
else
|
1837
|
-
r = @connection.execute('<SiteDeviceListingRequest session-id="' + connection.session_id + '"/>')
|
1838
|
-
end
|
1839
|
-
|
1840
|
-
if(r.success)
|
1841
|
-
response.elements.each('SiteDeviceListingResponse/SiteDevices/device') do |d|
|
1842
|
-
@devices.push(Device.new(d.attributes['id'],@site_id,d.attributes["address"],d.attributes["riskfactor"],d.attributes['riskscore']))
|
1843
|
-
end
|
1844
|
-
end
|
1845
|
-
end
|
1846
|
-
end
|
1847
|
-
|
1848
|
-
# === Description
|
1849
|
-
# Object that represents a site, including the site configuration, scan history, and device listing.
|
1850
|
-
#
|
1851
|
-
# === Example
|
1852
|
-
# # Create a new Nexpose Connection on the default port and Login
|
1853
|
-
# nsc = Connection.new("10.1.40.10","nxadmin","password")
|
1854
|
-
# nsc.login()
|
1855
|
-
#
|
1856
|
-
# # Get an Existing Site
|
1857
|
-
# site_existing = Site.new(nsc,184)
|
1858
|
-
#
|
1859
|
-
# # Create a New Site, add some hosts, and save it to the NSC
|
1860
|
-
# site = Site.new(nsc)
|
1861
|
-
# site.setSiteConfig("New Site", "New Site Created in the API")
|
1862
|
-
#
|
1863
|
-
# # Add the hosts
|
1864
|
-
# site.site_config.addHost(HostName.new("localhost"))
|
1865
|
-
# site.site_config.addHost(IPRange.new("192.168.7.1","192.168.7.255"))
|
1866
|
-
# site.site_config.addHost(IPRange.new("10.1.20.30"))
|
1867
|
-
#
|
1868
|
-
# status = site.saveSite()
|
1869
|
-
#
|
1870
|
-
class Site
|
1871
|
-
# true if an error condition exists; false otherwise
|
1872
|
-
attr_reader :error
|
1873
|
-
# Error message string
|
1874
|
-
attr_reader :error_msg
|
1875
|
-
# The last XML request sent by this object
|
1876
|
-
attr_reader :request_xml
|
1877
|
-
# The last XML response received by this object
|
1878
|
-
attr_reader :response_xml
|
1879
|
-
# The NSC Connection associated with this object
|
1880
|
-
attr_reader :connection
|
1881
|
-
# The Site ID
|
1882
|
-
# site_id = -1 means create a new site. The NSC will assign a new site_id on SiteSave.
|
1883
|
-
attr_reader :site_id
|
1884
|
-
# A summary overview of this site
|
1885
|
-
# SiteSummary Object
|
1886
|
-
attr_reader :site_summary
|
1887
|
-
# The configuration of this site
|
1888
|
-
# SiteConfig Object
|
1889
|
-
attr_reader :site_config
|
1890
|
-
# The device listing for this site
|
1891
|
-
# SiteDeviceListing Object
|
1892
|
-
attr_reader :site_device_listing
|
1893
|
-
# The scan history of this site
|
1894
|
-
# SiteScanHistory Object
|
1895
|
-
attr_reader :site_scan_history
|
1896
|
-
|
1897
|
-
def initialize(connection, site_id = -1)
|
1898
|
-
@error = false
|
1899
|
-
@connection = connection
|
1900
|
-
@site_id = site_id
|
1901
|
-
|
1902
|
-
# If site_id > 0 then get SiteConfig
|
1903
|
-
if (@site_id.to_i > 0)
|
1904
|
-
# Create new SiteConfig object
|
1905
|
-
@site_config = SiteConfig.new()
|
1906
|
-
# Populate SiteConfig Obect with Data from the NSC
|
1907
|
-
@site_config.getSiteConfig(@connection,@site_id)
|
1908
|
-
@site_summary = SiteSummary.new(@site_id, @site_config.site_name, @site_config.description, @site_config.riskfactor)
|
1909
|
-
@site_scan_history = SiteScanHistory.new(@connection,@site_id)
|
1910
|
-
@site_device_listing = SiteDeviceListing.new(@connection,@site_id)
|
1911
|
-
|
1912
|
-
else
|
1913
|
-
# Just in case user enters a number > -1 or = 0
|
1914
|
-
@site_id = -1
|
1915
|
-
|
1916
|
-
@site_config = SiteConfig.new()
|
1917
|
-
setSiteConfig("New Site " + rand(999999999999).to_s,"")
|
1918
|
-
@site_summary = nil
|
1919
|
-
|
1920
|
-
end
|
1921
|
-
|
1922
|
-
end
|
1923
|
-
|
1924
|
-
# Creates a new site summary
|
1925
|
-
def setSiteSummary(site_name, description, riskfactor = 1)
|
1926
|
-
@site_summary = SiteSummary.new(-1,site_name,description,riskfactor)
|
1927
|
-
|
1928
|
-
end
|
1929
|
-
|
1930
|
-
# Creates a new site configuration
|
1931
|
-
def setSiteConfig(site_name, description, riskfactor = 1)
|
1932
|
-
setSiteSummary(site_name,description,riskfactor)
|
1933
|
-
@site_config = SiteConfig.new()
|
1934
|
-
@site_config._set_site_id(-1)
|
1935
|
-
@site_config._set_site_name(site_name)
|
1936
|
-
@site_config._set_description(description)
|
1937
|
-
@site_config._set_riskfactor(riskfactor)
|
1938
|
-
@site_config._set_scanConfig(ScanConfig.new(-1,"tmp","full-audit"))
|
1939
|
-
@site_config._set_connection(@connection)
|
1940
|
-
|
1941
|
-
end
|
1942
|
-
|
1943
|
-
# Initiates a scan of this site. If successful returns scan_id and engine_id in an associative array. Returns false if scan is unsuccessful.
|
1944
|
-
def scanSite()
|
1945
|
-
r = @connection.execute('<SiteScanRequest session-id="' + "#{@connection.session_id}" + '" site-id="' + "#{@site_id}" + '"/>')
|
1946
|
-
if(r.success)
|
1947
|
-
res = {}
|
1948
|
-
r.res.elements.each('//Scan/') do |s|
|
1949
|
-
res[:scan_id] = s.attributes['scan-id']
|
1950
|
-
res[:engine_id] = s.attributes['engine-id']
|
1951
|
-
end
|
1952
|
-
return res
|
1953
|
-
else
|
1954
|
-
return false
|
1955
|
-
end
|
1956
|
-
end
|
1957
|
-
|
1958
|
-
# Saves this site in the NSC
|
1959
|
-
def saveSite()
|
1960
|
-
r = @connection.execute('<SiteSaveRequest session-id="' + @connection.session_id + '">' + getSiteXML() + ' </SiteSaveRequest>')
|
1961
|
-
if (r.success)
|
1962
|
-
@site_id = r.attributes['site-id']
|
1963
|
-
@site_config._set_site_id(@site_id)
|
1964
|
-
@site_config.scanConfig._set_configID(@site_id)
|
1965
|
-
@site_config.scanConfig._set_name(@site_id)
|
1966
|
-
return true
|
1967
|
-
else
|
1968
|
-
return false
|
1969
|
-
end
|
1970
|
-
end
|
1971
|
-
|
1972
|
-
def deleteSite()
|
1973
|
-
r = @connection.execute('<SiteDeleteRequest session-id="' + @connection.session_id.to_s + '" site-id="' + @site_id + '"/>')
|
1974
|
-
r.success
|
1975
|
-
end
|
1976
|
-
|
1977
|
-
|
1978
|
-
def printSite()
|
1979
|
-
puts "Site ID: " + @site_summary.id
|
1980
|
-
puts "Site Name: " + @site_summary.site_name
|
1981
|
-
puts "Site Description: " + @site_summary.description
|
1982
|
-
puts "Site Risk Factor: " + @site_summary.riskfactor
|
1983
|
-
end
|
1984
|
-
|
1985
|
-
def getSiteXML()
|
1986
|
-
|
1987
|
-
xml = '<Site id="' + "#{@site_config.site_id}" + '" name="' + "#{@site_config.site_name}" + '" description="' + "#{@site_config.description}" + '" riskfactor="' + "#{@site_config.riskfactor}" + '">'
|
1988
|
-
|
1989
|
-
xml << ' <Hosts>'
|
1990
|
-
@site_config.hosts.each do |h|
|
1991
|
-
xml << h.to_xml if h.respond_to? :to_xml
|
1992
|
-
end
|
1993
|
-
xml << '</Hosts>'
|
1994
|
-
|
1995
|
-
xml << '<Credentials>'
|
1996
|
-
@site_config.credentials.each do |c|
|
1997
|
-
xml << c.to_xml if c.respond_to? :to_xml
|
1998
|
-
end
|
1999
|
-
xml << ' </Credentials>'
|
2000
|
-
|
2001
|
-
xml << ' <Alerting>'
|
2002
|
-
@site_config.alerts.each do |a|
|
2003
|
-
xml << a.to_xml if a.respond_to? :to_xml
|
2004
|
-
end
|
2005
|
-
xml << ' </Alerting>'
|
2006
|
-
|
2007
|
-
xml << ' <ScanConfig configID="' + "#{@site_config.scanConfig.configID}" + '" name="' + "#{@site_config.scanConfig.name}" + '" templateID="' + "#{@site_config.scanConfig.templateID}" + '" configVersion="' + "#{@site_config.scanConfig.configVersion}" + '">'
|
2008
|
-
|
2009
|
-
xml << ' <Schedules>'
|
2010
|
-
@site_config.scanConfig.schedules.each do |s|
|
2011
|
-
xml << ' <Schedule enabled="' + s.enabled + '" type="' + s.type + '" interval="' + s.interval + '" start="' + s.start + '"/>'
|
2012
|
-
end
|
2013
|
-
xml << ' </Schedules>'
|
2014
|
-
|
2015
|
-
xml << ' <ScanTriggers>'
|
2016
|
-
@site_config.scanConfig.scanTriggers.each do |s|
|
2017
|
-
|
2018
|
-
if (s.class.to_s == "Nexpose::AutoUpdate")
|
2019
|
-
xml << ' <autoUpdate enabled="' + s.enabled + '" incremental="' + s.incremental + '"/>'
|
2020
|
-
end
|
2021
|
-
end
|
2022
|
-
|
2023
|
-
xml << ' </ScanTriggers>'
|
2024
|
-
|
2025
|
-
xml << ' </ScanConfig>'
|
2026
|
-
|
2027
|
-
xml << ' </Site>'
|
2028
|
-
|
2029
|
-
return xml
|
2030
|
-
end
|
2031
|
-
end
|
2032
|
-
|
2033
|
-
# === Description
|
2034
|
-
# Object that represents administrative credentials to be used during a scan. When retrived from an existing site configuration the credentials will be returned as a security blob and can only be passed back as is during a Site Save operation. This object can only be used to create a new set of credentials.
|
2035
|
-
#
|
2036
|
-
class AdminCredentials
|
2037
|
-
# Security blob for an existing set of credentials
|
2038
|
-
attr_reader :securityblob
|
2039
|
-
# Designates if this object contains user defined credentials or a security blob
|
2040
|
-
attr_reader :isblob
|
2041
|
-
# The service for these credentials. Can be All.
|
2042
|
-
attr_reader :service
|
2043
|
-
# The host for these credentials. Can be Any.
|
2044
|
-
attr_reader :host
|
2045
|
-
# The port on which to use these credentials.
|
2046
|
-
attr_reader :port
|
2047
|
-
# The user id or username
|
2048
|
-
attr_reader :userid
|
2049
|
-
# The password
|
2050
|
-
attr_reader :password
|
2051
|
-
# The realm for these credentials
|
2052
|
-
attr_reader :realm
|
2053
|
-
|
2054
|
-
|
2055
|
-
def initialize(isblob = false)
|
2056
|
-
@isblob = isblob
|
2057
|
-
end
|
2058
|
-
|
2059
|
-
# Sets the credentials information for this object.
|
2060
|
-
def setCredentials(service, host, port, userid, password, realm)
|
2061
|
-
@isblob = false
|
2062
|
-
@securityblob = nil
|
2063
|
-
@service = service
|
2064
|
-
@host = host
|
2065
|
-
@port = port
|
2066
|
-
@userid = userid
|
2067
|
-
@password = password
|
2068
|
-
@realm = realm
|
2069
|
-
end
|
2070
|
-
|
2071
|
-
# TODO: add description
|
2072
|
-
def setService(service)
|
2073
|
-
@service = service
|
2074
|
-
end
|
2075
|
-
|
2076
|
-
def setHost(host)
|
2077
|
-
@host = host
|
2078
|
-
end
|
2079
|
-
|
2080
|
-
# TODO: add description
|
2081
|
-
def setBlob(securityblob)
|
2082
|
-
@isblob = true
|
2083
|
-
@securityblob = securityblob
|
2084
|
-
end
|
2085
|
-
|
2086
|
-
include Sanitize
|
2087
|
-
def to_xml
|
2088
|
-
xml = ''
|
2089
|
-
xml << '<adminCredentials'
|
2090
|
-
xml << %Q{ service="#{replace_entities(service)}"} if (service)
|
2091
|
-
xml << %Q{ userid="#{replace_entities(userid)}"} if (userid)
|
2092
|
-
xml << %Q{ password="#{replace_entities(password)}"} if (password)
|
2093
|
-
xml << %Q{ realm="#{replace_entities(realm)}"} if (realm)
|
2094
|
-
xml << %Q{ host="#{replace_entities(host)}"} if (host)
|
2095
|
-
xml << %Q{ port="#{replace_entities(port)}"} if (port)
|
2096
|
-
xml << '>'
|
2097
|
-
xml << replace_entities(securityblob) if (isblob)
|
2098
|
-
xml << '</adminCredentials>'
|
2099
|
-
|
2100
|
-
xml
|
2101
|
-
end
|
2102
|
-
end
|
2103
|
-
|
2104
|
-
|
2105
|
-
# === Description
|
2106
|
-
# Object that represents an SMTP (Email) Alert.
|
2107
|
-
#
|
2108
|
-
class SmtpAlert
|
2109
|
-
# A unique name for this alert
|
2110
|
-
attr_reader :name
|
2111
|
-
# If this alert is enabled or not
|
2112
|
-
attr_reader :enabled
|
2113
|
-
# The email address of the sender
|
2114
|
-
attr_reader :sender
|
2115
|
-
# Limit the text for mobile devices
|
2116
|
-
attr_reader :limitText
|
2117
|
-
# Array containing Strings of email addresses
|
2118
|
-
# Array of strings with the email addresses of the intended recipients
|
2119
|
-
attr_reader :recipients
|
2120
|
-
# The vulnerability filter to trigger the alert
|
2121
|
-
attr_reader :vulnFilter
|
2122
|
-
# The alert type
|
2123
|
-
attr_reader :type
|
2124
|
-
|
2125
|
-
def initialize(name, sender, limitText, enabled = 1)
|
2126
|
-
@type = :smtp
|
2127
|
-
@name = name
|
2128
|
-
@sender = sender
|
2129
|
-
@enabled = enabled
|
2130
|
-
@limitText = limitText
|
2131
|
-
@recipients = Array.new()
|
2132
|
-
# Sets default vuln filter - All Events
|
2133
|
-
setVulnFilter(VulnFilter.new("50790400",1))
|
2134
|
-
end
|
2135
|
-
|
2136
|
-
# Adds a new Recipient to the recipients array
|
2137
|
-
def addRecipient(recipient)
|
2138
|
-
@recipients.push(recipient)
|
2139
|
-
end
|
2140
|
-
|
2141
|
-
# Sets the Vulnerability Filter for this alert.
|
2142
|
-
def setVulnFilter(vulnFilter)
|
2143
|
-
@vulnFilter = vulnFilter
|
2144
|
-
end
|
2145
|
-
|
2146
|
-
include Sanitize
|
2147
|
-
def to_xml
|
2148
|
-
xml = "<smtpAlert"
|
2149
|
-
xml << %Q{ name="#{replace_entities(name)}"}
|
2150
|
-
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
2151
|
-
xml << %Q{ sender="#{replace_entities(sender)}"}
|
2152
|
-
xml << %Q{ limitText="#{replace_entities(limitText)}">}
|
2153
|
-
recipients.each do |recpt|
|
2154
|
-
xml << "<recipient>#{replace_entities(recpt)}</recipient>"
|
2155
|
-
end
|
2156
|
-
xml << vulnFilter.to_xml
|
2157
|
-
xml << "</smtpAlert>"
|
2158
|
-
xml
|
2159
|
-
end
|
2160
|
-
end
|
2161
|
-
|
2162
|
-
# === Description
|
2163
|
-
# Object that represents an SNMP Alert.
|
2164
|
-
#
|
2165
|
-
class SnmpAlert
|
2166
|
-
|
2167
|
-
# A unique name for this alert
|
2168
|
-
attr_reader :name
|
2169
|
-
# If this alert is enabled or not
|
2170
|
-
attr_reader :enabled
|
2171
|
-
# The community string
|
2172
|
-
attr_reader :community
|
2173
|
-
# The SNMP server to sent this alert
|
2174
|
-
attr_reader :server
|
2175
|
-
# The vulnerability filter to trigger the alert
|
2176
|
-
attr_reader :vulnFilter
|
2177
|
-
# The alert type
|
2178
|
-
attr_reader :type
|
2179
|
-
|
2180
|
-
def initialize(name, community, server, enabled = 1)
|
2181
|
-
@type = :snmp
|
2182
|
-
@name = name
|
2183
|
-
@community = community
|
2184
|
-
@server = server
|
2185
|
-
@enabled = enabled
|
2186
|
-
# Sets default vuln filter - All Events
|
2187
|
-
setVulnFilter(VulnFilter.new("50790400",1))
|
2188
|
-
end
|
2189
|
-
|
2190
|
-
# Sets the Vulnerability Filter for this alert.
|
2191
|
-
def setVulnFilter(vulnFilter)
|
2192
|
-
@vulnFilter = vulnFilter
|
2193
|
-
end
|
2194
|
-
|
2195
|
-
include Sanitize
|
2196
|
-
def to_xml
|
2197
|
-
xml = "<snmpAlert"
|
2198
|
-
xml << %Q{ name="#{replace_entities(name)}"}
|
2199
|
-
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
2200
|
-
xml << %Q{ community="#{replace_entities(community)}"}
|
2201
|
-
xml << %Q{ server="#{replace_entities(server)}">}
|
2202
|
-
xml << vulnFilter.to_xml
|
2203
|
-
xml << "</snmpAlert>"
|
2204
|
-
xml
|
2205
|
-
end
|
2206
|
-
|
2207
|
-
end
|
2208
|
-
|
2209
|
-
# === Description
|
2210
|
-
# Object that represents a Syslog Alert.
|
2211
|
-
#
|
2212
|
-
class SyslogAlert
|
2213
|
-
|
2214
|
-
# A unique name for this alert
|
2215
|
-
attr_reader :name
|
2216
|
-
# If this alert is enabled or not
|
2217
|
-
attr_reader :enabled
|
2218
|
-
# The Syslog server to sent this alert
|
2219
|
-
attr_reader :server
|
2220
|
-
# The vulnerability filter to trigger the alert
|
2221
|
-
attr_reader :vulnFilter
|
2222
|
-
# The alert type
|
2223
|
-
attr_reader :type
|
2224
|
-
|
2225
|
-
def initialize(name, server, enabled = 1)
|
2226
|
-
@type = :syslog
|
2227
|
-
@name = name
|
2228
|
-
@server = server
|
2229
|
-
@enabled = enabled
|
2230
|
-
# Sets default vuln filter - All Events
|
2231
|
-
setVulnFilter(VulnFilter.new("50790400",1))
|
2232
|
-
|
2233
|
-
end
|
2234
|
-
|
2235
|
-
# Sets the Vulnerability Filter for this alert.
|
2236
|
-
def setVulnFilter(vulnFilter)
|
2237
|
-
@vulnFilter = vulnFilter
|
2238
|
-
end
|
2239
|
-
|
2240
|
-
include Sanitize
|
2241
|
-
def to_xml
|
2242
|
-
xml = "<syslogAlert"
|
2243
|
-
xml << %Q{ name="#{replace_entities(name)}"}
|
2244
|
-
xml << %Q{ enabled="#{replace_entities(enabled)}"}
|
2245
|
-
xml << %Q{ server="#{replace_entities(server)}">}
|
2246
|
-
xml << vulnFilter.to_xml
|
2247
|
-
xml << "</syslogAlert>"
|
2248
|
-
xml
|
2249
|
-
end
|
2250
|
-
|
2251
|
-
end
|
2252
|
-
|
2253
|
-
# TODO: review
|
2254
|
-
# <scanFilter scanStop='0' scanFailed='0' scanStart='1'/>
|
2255
|
-
# === Description
|
2256
|
-
#
|
2257
|
-
class ScanFilter
|
2258
|
-
|
2259
|
-
attr_reader :scanStop
|
2260
|
-
attr_reader :scanFailed
|
2261
|
-
attr_reader :scanStart
|
2262
|
-
|
2263
|
-
def initialize(scanstop, scanFailed, scanStart)
|
2264
|
-
|
2265
|
-
@scanStop = scanStop
|
2266
|
-
@scanFailed = scanFailed
|
2267
|
-
@scanStart = scanStart
|
2268
|
-
|
2269
|
-
end
|
2270
|
-
|
2271
|
-
end
|
2272
|
-
|
2273
|
-
# TODO: review
|
2274
|
-
# === Description
|
2275
|
-
#
|
2276
|
-
class VulnFilter
|
2277
|
-
|
2278
|
-
attr_reader :typeMask
|
2279
|
-
attr_reader :maxAlerts
|
2280
|
-
attr_reader :severityThreshold
|
2281
|
-
|
2282
|
-
def initialize(typeMask, severityThreshold, maxAlerts = -1)
|
2283
|
-
@typeMask = typeMask
|
2284
|
-
@maxAlerts = maxAlerts
|
2285
|
-
@severityThreshold = severityThreshold
|
2286
|
-
end
|
2287
|
-
|
2288
|
-
include Sanitize
|
2289
|
-
def to_xml
|
2290
|
-
xml = "<vulnFilter "
|
2291
|
-
xml << %Q{ typeMask="#{replace_entities(typeMask)}"}
|
2292
|
-
xml << %Q{ maxAlerts="#{replace_entities(maxAlerts)}"}
|
2293
|
-
xml << %Q{ severityThreshold="#{replace_entities(severityThreshold)}"}
|
2294
|
-
xml << "/>"
|
2295
|
-
|
2296
|
-
xml
|
2297
|
-
end
|
2298
|
-
|
2299
|
-
end
|
2300
|
-
|
2301
|
-
# TODO add engineID
|
2302
|
-
# === Description
|
2303
|
-
# Object that represents the scanning configuration for a Site.
|
2304
|
-
#
|
2305
|
-
class ScanConfig
|
2306
|
-
# A unique ID for this scan configuration
|
2307
|
-
attr_reader :configID
|
2308
|
-
# The name of the scan template
|
2309
|
-
attr_reader :name
|
2310
|
-
# The ID of the scan template used full-audit, exhaustive-audit, web-audit, dos-audit, internet-audit, network-audit
|
2311
|
-
attr_reader :templateID
|
2312
|
-
# The configuration version (default is 2)
|
2313
|
-
attr_reader :configVersion
|
2314
|
-
# Array of (Schedule)*
|
2315
|
-
attr_reader :schedules
|
2316
|
-
# Array of (ScanTrigger)*
|
2317
|
-
attr_reader :scanTriggers
|
2318
|
-
|
2319
|
-
def initialize(configID, name, templateID, configVersion = 2)
|
2320
|
-
|
2321
|
-
@configID = configID
|
2322
|
-
@name = name
|
2323
|
-
@templateID = templateID
|
2324
|
-
@configVersion = configVersion
|
2325
|
-
@schedules = Array.new()
|
2326
|
-
@scanTriggers = Array.new()
|
2327
|
-
|
2328
|
-
end
|
2329
|
-
|
2330
|
-
# Adds a new Schedule for this ScanConfig
|
2331
|
-
def addSchedule(schedule)
|
2332
|
-
@schedules.push(schedule)
|
2333
|
-
end
|
2334
|
-
|
2335
|
-
# Adds a new ScanTrigger to the scanTriggers array
|
2336
|
-
def addScanTrigger(scanTrigger)
|
2337
|
-
@scanTriggers.push(scanTrigger)
|
2338
|
-
end
|
2339
|
-
|
2340
|
-
def _set_configID(configID)
|
2341
|
-
@configID = configID
|
2342
|
-
end
|
2343
|
-
|
2344
|
-
def _set_name(name)
|
2345
|
-
@name = name
|
2346
|
-
end
|
2347
|
-
|
2348
|
-
end
|
2349
|
-
|
2350
|
-
# === Description
|
2351
|
-
# Object that holds a scan schedule
|
2352
|
-
#
|
2353
|
-
class Schedule
|
2354
|
-
# Type of Schedule (daily|hourly|monthly|weekly)
|
2355
|
-
attr_reader :type
|
2356
|
-
# The schedule interval
|
2357
|
-
attr_reader :interval
|
2358
|
-
# The date and time to start the first scan
|
2359
|
-
attr_reader :start
|
2360
|
-
# Enable or disable this schedule
|
2361
|
-
attr_reader :enabled
|
2362
|
-
# The date and time to disable to schedule. If null then the schedule will run forever.
|
2363
|
-
attr_reader :notValidAfter
|
2364
|
-
# Scan on the same date each time
|
2365
|
-
attr_reader :byDate
|
2366
|
-
|
2367
|
-
def initialize(type, interval, start, enabled = 1)
|
2368
|
-
|
2369
|
-
@type = type
|
2370
|
-
@interval = interval
|
2371
|
-
@start = start
|
2372
|
-
@enabled = enabled
|
2373
|
-
|
2374
|
-
end
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
end
|
2379
|
-
|
2380
|
-
# === Description
|
2381
|
-
# Object that holds an event that triggers the start of a scan.
|
2382
|
-
#
|
2383
|
-
class ScanTrigger
|
2384
|
-
# Type of Trigger (AutoUpdate)
|
2385
|
-
attr_reader :type
|
2386
|
-
# Enable or disable this scan trigger
|
2387
|
-
attr_reader :enabled
|
2388
|
-
# Sets the trigger to start an incremental scan or a full scan
|
2389
|
-
attr_reader :incremental
|
2390
|
-
|
2391
|
-
def initialize(type, incremental, enabled = 1)
|
2392
|
-
|
2393
|
-
@type = type
|
2394
|
-
@incremental = incremental
|
2395
|
-
@enabled = enabled
|
2396
|
-
|
2397
|
-
end
|
2398
|
-
|
2399
|
-
end
|
2400
|
-
|
2401
|
-
# === Description
|
2402
|
-
# Object that represents a single device in an NSC.
|
2403
|
-
#
|
2404
|
-
class Device
|
2405
|
-
|
2406
|
-
# A unique device ID (assigned by the NSC)
|
2407
|
-
attr_reader :id
|
2408
|
-
# The site ID of this devices site
|
2409
|
-
attr_reader :site_id
|
2410
|
-
# IP Address or Hostname of this device
|
2411
|
-
attr_reader :address
|
2412
|
-
# User assigned risk multiplier
|
2413
|
-
attr_reader :riskfactor
|
2414
|
-
# NeXpose risk score
|
2415
|
-
attr_reader :riskscore
|
2416
|
-
|
2417
|
-
def initialize(id, site_id, address, riskfactor=1, riskscore=0)
|
2418
|
-
@id = id
|
2419
|
-
@site_id = site_id
|
2420
|
-
@address = address
|
2421
|
-
@riskfactor = riskfactor
|
2422
|
-
@riskscore = riskscore
|
2423
|
-
|
2424
|
-
end
|
2425
|
-
|
2426
|
-
end
|
2427
|
-
|
2428
|
-
|
2429
|
-
# === Description
|
2430
|
-
# Object that represents a summary of a scan.
|
2431
|
-
#
|
2432
|
-
class ScanSummary
|
2433
|
-
# The Scan ID of the Scan
|
2434
|
-
attr_reader :scan_id
|
2435
|
-
# The Engine ID used to perform the scan
|
2436
|
-
attr_reader :engine_id
|
2437
|
-
# TODO: add description
|
2438
|
-
attr_reader :name
|
2439
|
-
# The scan start time
|
2440
|
-
attr_reader :startTime
|
2441
|
-
# The scan finish time
|
2442
|
-
attr_reader :endTime
|
2443
|
-
# The scan status (running|finished|stopped|error| dispatched|paused|aborted|uknown)
|
2444
|
-
attr_reader :status
|
2445
|
-
# The number of pending tasks
|
2446
|
-
attr_reader :tasks_pending
|
2447
|
-
# The number of active tasks
|
2448
|
-
attr_reader :tasks_active
|
2449
|
-
# The number of completed tasks
|
2450
|
-
attr_reader :tasks_completed
|
2451
|
-
# The number of "live" nodes
|
2452
|
-
attr_reader :nodes_live
|
2453
|
-
# The number of "dead" nodes
|
2454
|
-
attr_reader :nodes_dead
|
2455
|
-
# The number of filtered nodes
|
2456
|
-
attr_reader :nodes_filtered
|
2457
|
-
# The number of unresolved nodes
|
2458
|
-
attr_reader :nodes_unresolved
|
2459
|
-
# The number of "other" nodes
|
2460
|
-
attr_reader :nodes_other
|
2461
|
-
# Confirmed vulnerabilities found (indexed by severity)
|
2462
|
-
# Associative array, indexed by severity
|
2463
|
-
attr_reader :vuln_exploit
|
2464
|
-
# Unconfirmed vulnerabilities found (indexed by severity)
|
2465
|
-
# Associative array, indexed by severity
|
2466
|
-
attr_reader :vuln_version
|
2467
|
-
# Not vulnerable checks run (confirmed)
|
2468
|
-
attr_reader :not_vuln_exploit
|
2469
|
-
# Not vulnerable checks run (unconfirmed)
|
2470
|
-
attr_reader :not_vuln_version
|
2471
|
-
# Vulnerability check errors
|
2472
|
-
attr_reader :vuln_error
|
2473
|
-
# Vulnerability checks disabled
|
2474
|
-
attr_reader :vuln_disabled
|
2475
|
-
# Vulnerability checks other
|
2476
|
-
attr_reader :vuln_other
|
2477
|
-
|
2478
|
-
# Constructor
|
2479
|
-
# ScanSummary(can_id, $engine_id, $name, tartTime, $endTime, tatus)
|
2480
|
-
def initialize(scan_id, engine_id, name, startTime, endTime, status)
|
2481
|
-
|
2482
|
-
@scan_id = scan_id
|
2483
|
-
@engine_id = engine_id
|
2484
|
-
@name = name
|
2485
|
-
@startTime = startTime
|
2486
|
-
@endTime = endTime
|
2487
|
-
@status = status
|
2488
|
-
|
2489
|
-
end
|
2490
|
-
|
2491
|
-
end
|
2492
|
-
|
2493
|
-
# TODO
|
2494
|
-
# === Description
|
2495
|
-
# Object that represents the overview statistics for a particular scan.
|
2496
|
-
#
|
2497
|
-
# === Examples
|
2498
|
-
#
|
2499
|
-
# # Create a new Nexpose Connection on the default port and Login
|
2500
|
-
# nsc = Connection.new("10.1.40.10","nxadmin","password")
|
2501
|
-
# nsc.login()
|
2502
|
-
#
|
2503
|
-
# # Get a Site (Site ID = 12) from the NSC
|
2504
|
-
# site = new Site(nsc,12)
|
2505
|
-
#
|
2506
|
-
# # Start a Scan of this site and pause for 1 minute
|
2507
|
-
# scan1 = site.scanSite()
|
2508
|
-
# sleep(60)
|
2509
|
-
#
|
2510
|
-
# # Get the Scan Statistics for this scan
|
2511
|
-
# scanStatistics = new ScanStatistics(nsc,scan1["scan_id"])
|
2512
|
-
#
|
2513
|
-
# # Print out number of confirmed vulnerabilities with a 10 severity
|
2514
|
-
# puts scanStatistics.scansummary.vuln_exploit[10]
|
2515
|
-
#
|
2516
|
-
# # Print out the number of pending tasks left in the scan
|
2517
|
-
# puts scanStatistics.scan_summary.tasks_pending
|
2518
|
-
#
|
2519
|
-
class ScanStatistics
|
2520
|
-
# true if an error condition exists; false otherwise
|
2521
|
-
attr_reader :error
|
2522
|
-
# Error message string
|
2523
|
-
attr_reader :error_msg
|
2524
|
-
# The last XML request sent by this object
|
2525
|
-
attr_reader :request_xml
|
2526
|
-
# The last XML response received by this object
|
2527
|
-
attr_reader :reseponse_xml
|
2528
|
-
# The Scan ID
|
2529
|
-
attr_reader :scan_id
|
2530
|
-
# The ScanSummary of the scan
|
2531
|
-
attr_reader :scan_summary
|
2532
|
-
# The NSC Connection associated with this object
|
2533
|
-
attr_reader :connection
|
2534
|
-
|
2535
|
-
# Vulnerability checks other
|
2536
|
-
attr_reader :vuln_other
|
2537
|
-
def initialize(connection, scan_id)
|
2538
|
-
@error = false
|
2539
|
-
@connection = connection
|
2540
|
-
@scan_id = scan_id
|
2541
|
-
end
|
2542
|
-
end
|
2543
|
-
|
2544
|
-
# ==== Description
|
2545
|
-
# Object that represents a listing of all of the scan engines available on to an NSC.
|
2546
|
-
#
|
2547
|
-
class EngineListing
|
2548
|
-
# true if an error condition exists; false otherwise
|
2549
|
-
attr_reader :error
|
2550
|
-
# Error message string
|
2551
|
-
attr_reader :error_msg
|
2552
|
-
# The last XML request sent by this object
|
2553
|
-
attr_reader :request_xml
|
2554
|
-
# The last XML response received by this object
|
2555
|
-
attr_reader :response_xml
|
2556
|
-
# The NSC Connection associated with this object
|
2557
|
-
attr_reader :connection
|
2558
|
-
# Array containing (EngineSummary*)
|
2559
|
-
attr_reader :engines
|
2560
|
-
# The number of scan engines
|
2561
|
-
attr_reader :engine_count
|
2562
|
-
|
2563
|
-
# Constructor
|
2564
|
-
# EngineListing (connection)
|
2565
|
-
def initialize(connection)
|
2566
|
-
@connection = connection
|
2567
|
-
@engines = []
|
2568
|
-
@engine_count = 0
|
2569
|
-
@error = false
|
2570
|
-
r = @connection.execute('<EngineListingRequest session-id="' + @connection.session_id + '"/>', '1.2')
|
2571
|
-
|
2572
|
-
if (r.success)
|
2573
|
-
r.res.elements.each('EngineListingResponse/EngineSummary') do |v|
|
2574
|
-
@engines.push(EngineSummary.new(v.attributes['id'], v.attributes['name'], v.attributes['address'],
|
2575
|
-
v.attributes['port'], v.attributes['status']))
|
2576
|
-
end
|
2577
|
-
else
|
2578
|
-
@error = true
|
2579
|
-
@error_msg = 'EngineListingRequest Parse Error'
|
2580
|
-
end
|
2581
|
-
@engine_count = @engines.length
|
2582
|
-
end
|
2583
|
-
end
|
2584
|
-
|
2585
|
-
# ==== Description
|
2586
|
-
# Object that represents the summary of a scan engine.
|
2587
|
-
#
|
2588
|
-
# ==== Examples
|
2589
|
-
#
|
2590
|
-
# # Create a new Nexpose Connection on the default port and Login
|
2591
|
-
# nsc = Connection.new("10.1.40.10","nxadmin","password")
|
2592
|
-
# nsc.login()
|
2593
|
-
#
|
2594
|
-
# # Get the engine listing for the connection
|
2595
|
-
# enginelisting = EngineListing.new(nsc)
|
2596
|
-
#
|
2597
|
-
# # Print out the status of the first scan engine
|
2598
|
-
# puts enginelisting.engines[0].status
|
2599
|
-
#
|
2600
|
-
class EngineSummary
|
2601
|
-
# A unique ID that identifies this scan engine
|
2602
|
-
attr_reader :id
|
2603
|
-
# The name of this scan engine
|
2604
|
-
attr_reader :name
|
2605
|
-
# The hostname or IP address of the engine
|
2606
|
-
attr_reader :address
|
2607
|
-
# The port there the engine is listening
|
2608
|
-
attr_reader :port
|
2609
|
-
# The engine status (active|pending-auth| incompatible|not-responding|unknown)
|
2610
|
-
attr_reader :status
|
2611
|
-
|
2612
|
-
# Constructor
|
2613
|
-
# EngineSummary(id, name, address, port, status)
|
2614
|
-
def initialize(id, name, address, port, status)
|
2615
|
-
@id = id
|
2616
|
-
@name = name
|
2617
|
-
@address = address
|
2618
|
-
@port = port
|
2619
|
-
@status = status
|
2620
|
-
end
|
2621
|
-
|
2622
|
-
end
|
2623
|
-
|
2624
|
-
|
2625
|
-
# TODO
|
2626
|
-
class EngineActivity
|
2627
|
-
# true if an error condition exists; false otherwise
|
2628
|
-
attr_reader :error
|
2629
|
-
# Error message string
|
2630
|
-
attr_reader :error_msg
|
2631
|
-
# The last XML request sent by this object
|
2632
|
-
attr_reader :request_xml
|
2633
|
-
# The last XML response received by this object
|
2634
|
-
attr_reader :response_xml
|
2635
|
-
# The NSC Connection associated with this object
|
2636
|
-
attr_reader :connection
|
2637
|
-
# The Engine ID
|
2638
|
-
attr_reader :engine_id
|
2639
|
-
# Array containing (ScanSummary*)
|
2640
|
-
attr_reader :scan_summaries
|
2641
|
-
|
2642
|
-
|
2643
|
-
end
|
2644
|
-
|
2645
|
-
# === Description
|
2646
|
-
# Object that represents a listing of all of the vulnerabilities in the vulnerability database
|
2647
|
-
#
|
2648
|
-
class VulnerabilityListing
|
2649
|
-
|
2650
|
-
# true if an error condition exists; false otherwise
|
2651
|
-
attr_reader :error
|
2652
|
-
# Error message string
|
2653
|
-
attr_reader :error_msg
|
2654
|
-
# The last XML request sent by this object
|
2655
|
-
attr_reader :request_xml
|
2656
|
-
# The last XML response received by this object
|
2657
|
-
attr_reader :response_xml
|
2658
|
-
# The NSC Connection associated with this object
|
2659
|
-
attr_reader :connection
|
2660
|
-
# Array containing (VulnerabilitySummary*)
|
2661
|
-
attr_reader :vulnerability_summaries
|
2662
|
-
# The number of vulnerability definitions
|
2663
|
-
attr_reader :vulnerability_count
|
2664
|
-
|
2665
|
-
# Constructor
|
2666
|
-
# VulnerabilityListing(connection)
|
2667
|
-
def initialize(connection)
|
2668
|
-
@error = false
|
2669
|
-
@vulnerability_summaries = []
|
2670
|
-
@connection = connection
|
2671
|
-
|
2672
|
-
r = @connection.execute('<VulnerabilityListingRequest session-id="' + @connection.session_id + '"/>')
|
2673
|
-
|
2674
|
-
if (r.success)
|
2675
|
-
r.res.elements.each('VulnerabilityListingResponse/VulnerabilitySummary') do |v|
|
2676
|
-
@vulnerability_summaries.push(VulnerabilitySummary.new(v.attributes['id'],v.attributes["title"],v.attributes["severity"]))
|
2677
|
-
end
|
2678
|
-
else
|
2679
|
-
@error = true
|
2680
|
-
@error_msg = 'VulnerabilitySummaryRequest Parse Error'
|
2681
|
-
end
|
2682
|
-
@vulnerability_count = @vulnerability_summaries.length
|
2683
|
-
end
|
2684
|
-
end
|
2685
|
-
|
2686
|
-
# === Description
|
2687
|
-
# Object that represents the summary of an entry in the vulnerability database
|
2688
|
-
#
|
2689
|
-
class VulnerabilitySummary
|
2690
|
-
|
2691
|
-
# The unique ID string for this vulnerability
|
2692
|
-
attr_reader :id
|
2693
|
-
# The title of this vulnerability
|
2694
|
-
attr_reader :title
|
2695
|
-
# The severity of this vulnerability (1 – 10)
|
2696
|
-
attr_reader :severity
|
2697
|
-
|
2698
|
-
# Constructor
|
2699
|
-
# VulnerabilitySummary(id, title, severity)
|
2700
|
-
def initialize(id, title, severity)
|
2701
|
-
@id = id
|
2702
|
-
@title = title
|
2703
|
-
@severity = severity
|
2704
|
-
|
2705
|
-
end
|
2706
|
-
|
2707
|
-
end
|
2708
|
-
|
2709
|
-
# === Description
|
2710
|
-
#
|
2711
|
-
class Reference
|
2712
|
-
|
2713
|
-
attr_reader :source
|
2714
|
-
attr_reader :reference
|
2715
|
-
|
2716
|
-
def initialize(source, reference)
|
2717
|
-
@source = source
|
2718
|
-
@reference = reference
|
2719
|
-
end
|
2720
|
-
end
|
2721
|
-
|
2722
|
-
# === Description
|
2723
|
-
# Object that represents the details for an entry in the vulnerability database
|
2724
|
-
#
|
2725
|
-
class VulnerabilityDetail
|
2726
|
-
# true if an error condition exists; false otherwise
|
2727
|
-
attr_reader :error
|
2728
|
-
# Error message string
|
2729
|
-
attr_reader :error_msg
|
2730
|
-
# The last XML request sent by this object
|
2731
|
-
attr_reader :request_xml
|
2732
|
-
# The last XML response received by this object
|
2733
|
-
attr_reader :response_xml
|
2734
|
-
# The NSC Connection associated with this object
|
2735
|
-
attr_reader :connection
|
2736
|
-
# The unique ID string for this vulnerability
|
2737
|
-
attr_reader :id
|
2738
|
-
# The title of this vulnerability
|
2739
|
-
attr_reader :title
|
2740
|
-
# The severity of this vulnerability (1 – 10)
|
2741
|
-
attr_reader :severity
|
2742
|
-
# The pciSeverity of this vulnerability
|
2743
|
-
attr_reader :pciSeverity
|
2744
|
-
# The CVSS score of this vulnerability
|
2745
|
-
attr_reader :cvssScore
|
2746
|
-
# The CVSS vector of this vulnerability
|
2747
|
-
attr_reader :cvssVector
|
2748
|
-
# The date this vulnerability was published
|
2749
|
-
attr_reader :published
|
2750
|
-
# The date this vulnerability was added to NeXpose
|
2751
|
-
attr_reader :added
|
2752
|
-
# The last date this vulnerability was modified
|
2753
|
-
attr_reader :modified
|
2754
|
-
# The HTML Description of this vulnerability
|
2755
|
-
attr_reader :description
|
2756
|
-
# External References for this vulnerability
|
2757
|
-
# Array containing (Reference)
|
2758
|
-
attr_reader :references
|
2759
|
-
# The HTML Solution for this vulnerability
|
2760
|
-
attr_reader :solution
|
2761
|
-
|
2762
|
-
# Constructor
|
2763
|
-
# VulnerabilityListing(connection,id)
|
2764
|
-
def initialize(connection, id)
|
2765
|
-
|
2766
|
-
@error = false
|
2767
|
-
@connection = connection
|
2768
|
-
@id = id
|
2769
|
-
@references = []
|
2770
|
-
|
2771
|
-
r = @connection.execute('<VulnerabilityDetailsRequest session-id="' + @connection.session_id + '" vuln-id="' + @id + '"/>')
|
2772
|
-
|
2773
|
-
if (r.success)
|
2774
|
-
r.res.elements.each('VulnerabilityDetailsResponse/Vulnerability') do |v|
|
2775
|
-
@id = v.attributes['id']
|
2776
|
-
@title = v.attributes["title"]
|
2777
|
-
@severity = v.attributes["severity"]
|
2778
|
-
@pciSeverity = v.attributes['pciSeverity']
|
2779
|
-
@cvssScore = v.attributes['cvssScore']
|
2780
|
-
@cvssVector = v.attributes['cvssVector']
|
2781
|
-
@published = v.attributes['published']
|
2782
|
-
@added = v.attributes['added']
|
2783
|
-
@modified = v.attributes['modified']
|
2784
|
-
|
2785
|
-
v.elements.each('description') do |d|
|
2786
|
-
@description = d.to_s.gsub(/\<\/?description\>/i, '')
|
2787
|
-
end
|
2788
|
-
|
2789
|
-
v.elements.each('solution') do |s|
|
2790
|
-
@solution = s.to_s.gsub(/\<\/?solution\>/i, '')
|
2791
|
-
end
|
2792
|
-
|
2793
|
-
v.elements.each('references/reference') do |r|
|
2794
|
-
@references.push(Reference.new(r.attributes['source'],r.text))
|
2795
|
-
end
|
2796
|
-
end
|
2797
|
-
else
|
2798
|
-
@error = true
|
2799
|
-
@error_msg = 'VulnerabilitySummaryRequest Parse Error'
|
2800
|
-
end
|
2801
|
-
|
2802
|
-
end
|
2803
|
-
end
|
2804
|
-
|
2805
|
-
# === Description
|
2806
|
-
# Object that represents the summary of a Report Configuration.
|
2807
|
-
#
|
2808
|
-
class ReportConfigSummary
|
2809
|
-
# The Report Configuration ID
|
2810
|
-
attr_reader :id
|
2811
|
-
# A unique name for the Report
|
2812
|
-
attr_reader :name
|
2813
|
-
# The report format
|
2814
|
-
attr_reader :format
|
2815
|
-
# The date of the last report generation
|
2816
|
-
attr_reader :last_generated_on
|
2817
|
-
# Relative URI of the last generated report
|
2818
|
-
attr_reader :last_generated_uri
|
2819
|
-
|
2820
|
-
# Constructor
|
2821
|
-
# ReportConfigSummary(id, name, format, last_generated_on, last_generated_uri)
|
2822
|
-
def initialize(id, name, format, last_generated_on, last_generated_uri)
|
2823
|
-
|
2824
|
-
@id = id
|
2825
|
-
@name = name
|
2826
|
-
@format = format
|
2827
|
-
@last_generated_on = last_generated_on
|
2828
|
-
@last_generated_uri = last_generated_uri
|
2829
|
-
|
2830
|
-
end
|
2831
|
-
|
2832
|
-
end
|
2833
|
-
|
2834
|
-
# === Description
|
2835
|
-
# Object that represents the schedule on which to automatically generate new reports.
|
2836
|
-
class ReportHistory
|
2837
|
-
|
2838
|
-
# true if an error condition exists; false otherwise
|
2839
|
-
attr_reader :error
|
2840
|
-
# Error message string
|
2841
|
-
attr_reader :error_msg
|
2842
|
-
# The last XML request sent by this object
|
2843
|
-
attr_reader :request_xml
|
2844
|
-
# The last XML response received by this object
|
2845
|
-
attr_reader :response_xml
|
2846
|
-
# The NSC Connection associated with this object
|
2847
|
-
attr_reader :connection
|
2848
|
-
# The report definition (report config) ID
|
2849
|
-
# Report definition ID
|
2850
|
-
attr_reader :config_id
|
2851
|
-
# Array (ReportSummary*)
|
2852
|
-
attr_reader :report_summaries
|
2853
|
-
|
2854
|
-
|
2855
|
-
def initialize(connection, config_id)
|
2856
|
-
|
2857
|
-
@error = false
|
2858
|
-
@connection = connection
|
2859
|
-
@config_id = config_id
|
2860
|
-
@report_summaries = []
|
2861
|
-
|
2862
|
-
reportHistory_request = APIRequest.new('<ReportHistoryRequest session-id="' + "#{connection.session_id}" + '" reportcfg-id="' + "#{@config_id}" + '"/>',@connection.geturl())
|
2863
|
-
reportHistory_request.execute()
|
2864
|
-
@response_xml = reportHistory_request.response_xml
|
2865
|
-
@request_xml = reportHistory_request.request_xml
|
2866
|
-
|
2867
|
-
end
|
2868
|
-
|
2869
|
-
def xml_parse(response)
|
2870
|
-
response = REXML::Document.new(response.to_s)
|
2871
|
-
status = response.root.attributes['success']
|
2872
|
-
if (status == '1')
|
2873
|
-
response.elements.each('ReportHistoryResponse/ReportSummary') do |r|
|
2874
|
-
@report_summaries.push(ReportSummary.new(r.attributes["id"], r.attributes["cfg-id"], r.attributes["status"], r.attributes["generated-on"],r.attributes['report-uri']))
|
2875
|
-
end
|
2876
|
-
else
|
2877
|
-
@error = true
|
2878
|
-
@error_msg = 'Error ReportHistoryReponse'
|
2879
|
-
end
|
2880
|
-
end
|
2881
|
-
|
2882
|
-
end
|
2883
|
-
|
2884
|
-
# === Description
|
2885
|
-
# Object that represents the summary of a single report.
|
2886
|
-
class ReportSummary
|
2887
|
-
|
2888
|
-
# The Report ID
|
2889
|
-
attr_reader :id
|
2890
|
-
# The Report Configuration ID
|
2891
|
-
attr_reader :cfg_id
|
2892
|
-
# The status of this report
|
2893
|
-
# available | generating | failed
|
2894
|
-
attr_reader :status
|
2895
|
-
# The date on which this report was generated
|
2896
|
-
attr_reader :generated_on
|
2897
|
-
# The relative URI of the report
|
2898
|
-
attr_reader :report_uri
|
2899
|
-
|
2900
|
-
def initialize(id, cfg_id, status, generated_on, report_uri)
|
2901
|
-
|
2902
|
-
@id = id
|
2903
|
-
@cfg_id = cfg_id
|
2904
|
-
@status = status
|
2905
|
-
@generated_on = generated_on
|
2906
|
-
@report_uri = report_uri
|
2907
|
-
|
2908
|
-
end
|
2909
|
-
|
2910
|
-
end
|
2911
|
-
|
2912
|
-
# === Description
|
2913
|
-
#
|
2914
|
-
class ReportAdHoc
|
2915
|
-
include XMLUtils
|
2916
|
-
|
2917
|
-
attr_reader :error
|
2918
|
-
attr_reader :error_msg
|
2919
|
-
attr_reader :connection
|
2920
|
-
# Report Template ID strong e.g. full-audit
|
2921
|
-
attr_reader :template_id
|
2922
|
-
# pdf|html|xml|text|csv|raw-xml
|
2923
|
-
attr_reader :format
|
2924
|
-
# Array of (ReportFilter)*
|
2925
|
-
attr_reader :filters
|
2926
|
-
attr_reader :request_xml
|
2927
|
-
attr_reader :response_xml
|
2928
|
-
attr_reader :report_decoded
|
2929
|
-
|
2930
|
-
|
2931
|
-
def initialize(connection, template_id = 'full-audit', format = 'raw-xml')
|
2932
|
-
|
2933
|
-
@error = false
|
2934
|
-
@connection = connection
|
2935
|
-
@filters = Array.new()
|
2936
|
-
@template_id = template_id
|
2937
|
-
@format = format
|
2938
|
-
|
2939
|
-
end
|
2940
|
-
|
2941
|
-
def addFilter(filter_type, id)
|
2942
|
-
|
2943
|
-
# filter_type can be site|group|device|scan
|
2944
|
-
# id is the ID number. For scan, you can use 'last' for the most recently run scan
|
2945
|
-
filter = ReportFilter.new(filter_type, id)
|
2946
|
-
filters.push(filter)
|
2947
|
-
|
2948
|
-
end
|
2949
|
-
|
2950
|
-
def generate()
|
2951
|
-
request_xml = '<ReportAdhocGenerateRequest session-id="' + @connection.session_id + '">'
|
2952
|
-
request_xml += '<AdhocReportConfig template-id="' + @template_id + '" format="' + @format + '">'
|
2953
|
-
request_xml += '<Filters>'
|
2954
|
-
@filters.each do |f|
|
2955
|
-
request_xml += '<filter type="' + f.type + '" id="'+ f.id.to_s + '"/>'
|
2956
|
-
end
|
2957
|
-
request_xml += '</Filters>'
|
2958
|
-
request_xml += '</AdhocReportConfig>'
|
2959
|
-
request_xml += '</ReportAdhocGenerateRequest>'
|
2960
|
-
|
2961
|
-
ad_hoc_request = APIRequest.new(request_xml, @connection.url)
|
2962
|
-
ad_hoc_request.execute()
|
2963
|
-
|
2964
|
-
content_type_response = ad_hoc_request.raw_response.header['Content-Type']
|
2965
|
-
if content_type_response =~ /multipart\/mixed;\s*boundary=([^\s]+)/
|
2966
|
-
# NeXpose sends an incorrect boundary format which breaks parsing
|
2967
|
-
# Eg: boundary=XXX; charset=XXX
|
2968
|
-
# Fix by removing everything from the last semi-colon onward
|
2969
|
-
last_semi_colon_index = content_type_response.index(/;/, content_type_response.index(/boundary/))
|
2970
|
-
content_type_response = content_type_response[0, last_semi_colon_index]
|
2971
|
-
|
2972
|
-
data = "Content-Type: " + content_type_response + "\r\n\r\n" + ad_hoc_request.raw_response_data
|
2973
|
-
doc = Rex::MIME::Message.new data
|
2974
|
-
doc.parts.each do |part|
|
2975
|
-
if /.*base64.*/ =~ part.header.to_s
|
2976
|
-
return parse_xml(part.content.unpack("m*")[0])
|
2977
|
-
end
|
2978
|
-
end
|
2979
|
-
end
|
2980
|
-
end
|
2981
|
-
|
2982
|
-
end
|
2983
|
-
|
2984
|
-
# === Description
|
2985
|
-
# Object that represents the configuration of a report definition.
|
2986
|
-
#
|
2987
|
-
class ReportConfig
|
2988
|
-
|
2989
|
-
# true if an error condition exists; false otherwise
|
2990
|
-
attr_reader :error
|
2991
|
-
# Error message string
|
2992
|
-
attr_reader :error_msg
|
2993
|
-
# The last XML request sent by this object
|
2994
|
-
attr_reader :request_xml
|
2995
|
-
# The last XML response received by this object
|
2996
|
-
attr_reader :response_xml
|
2997
|
-
# The NSC Connection associated with this object
|
2998
|
-
attr_reader :connection
|
2999
|
-
# The ID for this report definition
|
3000
|
-
attr_reader :config_id
|
3001
|
-
# A unique name for this report definition
|
3002
|
-
attr_reader :name
|
3003
|
-
# The template ID used for this report definition
|
3004
|
-
attr_reader :template_id
|
3005
|
-
# html, db, txt, xml, raw-xml, csv, pdf
|
3006
|
-
attr_reader :format
|
3007
|
-
# XXX new
|
3008
|
-
attr_reader :timezone
|
3009
|
-
# XXX new
|
3010
|
-
attr_reader :owner
|
3011
|
-
# Array of (ReportFilter)* - The Sites, Asset Groups, or Devices to run the report against
|
3012
|
-
attr_reader :filters
|
3013
|
-
# Automatically generate a new report at the conclusion of a scan
|
3014
|
-
# 1 or 0
|
3015
|
-
attr_reader :generate_after_scan
|
3016
|
-
# Schedule to generate reports
|
3017
|
-
# ReportSchedule Object
|
3018
|
-
attr_reader :schedule
|
3019
|
-
# Store the reports on the server
|
3020
|
-
# 1 or 0
|
3021
|
-
attr_reader :storeOnServer
|
3022
|
-
# Location to store the report on the server
|
3023
|
-
attr_reader :store_location
|
3024
|
-
# Form to send the report via email
|
3025
|
-
# "file", "zip", "url", or NULL (don’t send email)
|
3026
|
-
attr_reader :email_As
|
3027
|
-
# Send the Email to all Authorized Users
|
3028
|
-
# boolean - Send the Email to all Authorized Users
|
3029
|
-
attr_reader :email_to_all
|
3030
|
-
# Array containing the email addresses of the recipients
|
3031
|
-
attr_reader :email_recipients
|
3032
|
-
# IP Address or Hostname of SMTP Relay Server
|
3033
|
-
attr_reader :smtp_relay_server
|
3034
|
-
# Sets the FROM field of the Email
|
3035
|
-
attr_reader :sender
|
3036
|
-
# TODO
|
3037
|
-
attr_reader :db_export
|
3038
|
-
# TODO
|
3039
|
-
attr_reader :csv_export
|
3040
|
-
# TODO
|
3041
|
-
attr_reader :xml_export
|
3042
|
-
|
3043
|
-
|
3044
|
-
def initialize(connection, config_id = -1)
|
3045
|
-
|
3046
|
-
@error = false
|
3047
|
-
@connection = connection
|
3048
|
-
@config_id = config_id
|
3049
|
-
@xml_tag_stack = Array.new()
|
3050
|
-
@filters = Array.new()
|
3051
|
-
@email_recipients = Array.new()
|
3052
|
-
@name = "New Report " + rand(999999999).to_s
|
3053
|
-
|
3054
|
-
r = @connection.execute('<ReportConfigRequest session-id="' + @connection.session_id.to_s + '" reportcfg-id="' + @config_id.to_s + '"/>')
|
3055
|
-
if (r.success)
|
3056
|
-
r.res.elements.each('ReportConfigResponse/ReportConfig') do |r|
|
3057
|
-
@name = r.attributes['name']
|
3058
|
-
@format = r.attributes['format']
|
3059
|
-
@timezone = r.attributes['timezone']
|
3060
|
-
@id = r.attributes['id']
|
3061
|
-
@template_id = r.attributes['template-id']
|
3062
|
-
@owner = r.attributes['owner']
|
3063
|
-
end
|
3064
|
-
else
|
3065
|
-
@error = true
|
3066
|
-
@error_msg = 'Error ReportHistoryReponse'
|
3067
|
-
end
|
3068
|
-
end
|
3069
|
-
|
3070
|
-
# === Description
|
3071
|
-
# Generate a new report on this report definition. Returns the new report ID.
|
3072
|
-
def generateReport(debug = false)
|
3073
|
-
return generateReport(@connection, @config_id, debug)
|
3074
|
-
end
|
3075
|
-
|
3076
|
-
# === Description
|
3077
|
-
# Save the report definition to the NSC.
|
3078
|
-
# Returns the config-id.
|
3079
|
-
def saveReport()
|
3080
|
-
r = @connection.execute('<ReportSaveRequest session-id="' + @connection.session_id.to_s + '">' + getXML().to_s + ' </ReportSaveRequest>')
|
3081
|
-
if(r.success)
|
3082
|
-
@config_id = r.attributes['reportcfg-id']
|
3083
|
-
return true
|
3084
|
-
end
|
3085
|
-
return false
|
3086
|
-
end
|
3087
|
-
|
3088
|
-
# === Description
|
3089
|
-
# Adds a new filter to the report config
|
3090
|
-
def addFilter(filter_type, id)
|
3091
|
-
filter = ReportFilter.new(filter_type,id)
|
3092
|
-
@filters.push(filter)
|
3093
|
-
end
|
3094
|
-
|
3095
|
-
# === Description
|
3096
|
-
# Adds a new email recipient
|
3097
|
-
def addEmailRecipient(recipient)
|
3098
|
-
@email_recipients.push(recipient)
|
3099
|
-
end
|
3100
|
-
|
3101
|
-
# === Description
|
3102
|
-
# Sets the schedule for this report config
|
3103
|
-
def setSchedule(schedule)
|
3104
|
-
@schedule = schedule
|
3105
|
-
end
|
3106
|
-
|
3107
|
-
def getXML()
|
3108
|
-
|
3109
|
-
xml = '<ReportConfig id="' + @config_id.to_s + '" name="' + @name.to_s + '" template-id="' + @template_id.to_s + '" format="' + @format.to_s + '">'
|
3110
|
-
|
3111
|
-
xml += ' <Filters>'
|
3112
|
-
|
3113
|
-
@filters.each do |f|
|
3114
|
-
xml += ' <' + f.type.to_s + ' id="' + f.id.to_s + '"/>'
|
3115
|
-
end
|
3116
|
-
|
3117
|
-
xml += ' </Filters>'
|
3118
|
-
|
3119
|
-
xml += ' <Generate after-scan="' + @generate_after_scan.to_s + '">'
|
3120
|
-
|
3121
|
-
if (@schedule)
|
3122
|
-
xml += ' <Schedule type="' + @schedule.type.to_s + '" interval="' + @schedule.interval.to_s + '" start="' + @schedule.start.to_s + '"/>'
|
3123
|
-
end
|
3124
|
-
|
3125
|
-
xml += ' </Generate>'
|
3126
|
-
|
3127
|
-
xml += ' <Delivery>'
|
3128
|
-
|
3129
|
-
xml += ' <Storage storeOnServer="' + @storeOnServer.to_s + '">'
|
3130
|
-
|
3131
|
-
if (@store_location and @store_location.length > 0)
|
3132
|
-
xml += ' <location>' + @store_location.to_s + '</location>'
|
3133
|
-
end
|
3134
|
-
|
3135
|
-
xml += ' </Storage>'
|
3136
|
-
|
3137
|
-
|
3138
|
-
xml += ' </Delivery>'
|
3139
|
-
|
3140
|
-
xml += ' </ReportConfig>'
|
3141
|
-
|
3142
|
-
return xml
|
3143
|
-
end
|
3144
|
-
|
3145
|
-
def set_name(name)
|
3146
|
-
@name = name
|
3147
|
-
end
|
3148
|
-
|
3149
|
-
def set_template_id(template_id)
|
3150
|
-
@template_id = template_id
|
3151
|
-
end
|
3152
|
-
|
3153
|
-
def set_format(format)
|
3154
|
-
@format = format
|
3155
|
-
end
|
3156
|
-
|
3157
|
-
def set_email_As(email_As)
|
3158
|
-
@email_As = email_As
|
3159
|
-
end
|
3160
|
-
|
3161
|
-
def set_storeOnServer(storeOnServer)
|
3162
|
-
@storeOnServer = storeOnServer
|
3163
|
-
end
|
3164
|
-
|
3165
|
-
def set_smtp_relay_server(smtp_relay_server)
|
3166
|
-
@smtp_relay_server = smtp_relay_server
|
3167
|
-
end
|
3168
|
-
|
3169
|
-
def set_sender(sender)
|
3170
|
-
@sender = sender
|
3171
|
-
end
|
3172
|
-
|
3173
|
-
def set_generate_after_scan(generate_after_scan)
|
3174
|
-
@generate_after_scan = generate_after_scan
|
3175
|
-
end
|
3176
|
-
end
|
3177
|
-
|
3178
|
-
# === Description
|
3179
|
-
# Object that represents a report filter which determines which sites, asset
|
3180
|
-
# groups, and/or devices that a report is run against. gtypes are
|
3181
|
-
# "SiteFilter", "AssetGroupFilter", "DeviceFilter", or "ScanFilter". gid is
|
3182
|
-
# the site-id, assetgroup-id, or devce-id. ScanFilter, if used, specifies
|
3183
|
-
# a specifies a specific scan to use as the data source for the report. The gid
|
3184
|
-
# can be a specific scan-id or "first" for the first run scan, or “last” for
|
3185
|
-
# the last run scan.
|
3186
|
-
#
|
3187
|
-
class ReportFilter
|
3188
|
-
|
3189
|
-
attr_reader :type
|
3190
|
-
attr_reader :id
|
3191
|
-
|
3192
|
-
def initialize(type, id)
|
3193
|
-
|
3194
|
-
@type = type
|
3195
|
-
@id = id
|
3196
|
-
|
3197
|
-
end
|
3198
|
-
|
3199
|
-
end
|
3200
|
-
|
3201
|
-
# === Description
|
3202
|
-
# Object that represents the schedule on which to automatically generate new reports.
|
3203
|
-
#
|
3204
|
-
class ReportSchedule
|
3205
|
-
|
3206
|
-
# The type of schedule
|
3207
|
-
# (daily, hourly, monthly, weekly)
|
3208
|
-
attr_reader :type
|
3209
|
-
# The frequency with which to run the scan
|
3210
|
-
attr_reader :interval
|
3211
|
-
# The earliest date to generate the report
|
3212
|
-
attr_reader :start
|
3213
|
-
|
3214
|
-
def initialize(type, interval, start)
|
3215
|
-
|
3216
|
-
@type = type
|
3217
|
-
@interval = interval
|
3218
|
-
@start = start
|
3219
|
-
|
3220
|
-
end
|
3221
|
-
|
3222
|
-
|
3223
|
-
end
|
3224
|
-
|
3225
|
-
class ReportTemplateListing
|
3226
|
-
|
3227
|
-
attr_reader :error_msg
|
3228
|
-
attr_reader :error
|
3229
|
-
attr_reader :request_xml
|
3230
|
-
attr_reader :response_xml
|
3231
|
-
attr_reader :connection
|
3232
|
-
attr_reader :xml_tag_stack
|
3233
|
-
attr_reader :report_template_summaries#; //Array (ReportTemplateSummary*)
|
3234
|
-
|
3235
|
-
|
3236
|
-
def ReportTemplateListing(connection)
|
3237
|
-
|
3238
|
-
@error = nil
|
3239
|
-
@connection = connection
|
3240
|
-
@report_template_summaries = Array.new()
|
3241
|
-
|
3242
|
-
r = @connection.execute('<ReportTemplateListingRequest session-id="' + connection.session_id.to_s + '"/>')
|
3243
|
-
if (r.success)
|
3244
|
-
r.res.elements.each('ReportTemplateListingResponse/ReportTemplateSummary') do |r|
|
3245
|
-
@report_template_summaries.push(ReportTemplateSumary.new(r.attributes['id'],r.attributes['name']))
|
3246
|
-
end
|
3247
|
-
else
|
3248
|
-
@error = true
|
3249
|
-
@error_msg = 'ReportTemplateListingRequest Parse Error'
|
3250
|
-
end
|
3251
|
-
|
3252
|
-
end
|
3253
|
-
|
3254
|
-
end
|
3255
|
-
|
3256
|
-
|
3257
|
-
class ReportTemplateSummary
|
3258
|
-
|
3259
|
-
attr_reader :id
|
3260
|
-
attr_reader :name
|
3261
|
-
attr_reader :description
|
3262
|
-
|
3263
|
-
def ReportTemplateSummary(id, name, description)
|
3264
|
-
|
3265
|
-
@id = id
|
3266
|
-
@name = name
|
3267
|
-
@description = description
|
3268
|
-
|
3269
|
-
end
|
3270
|
-
|
3271
|
-
end
|
3272
|
-
|
3273
|
-
|
3274
|
-
class ReportSection
|
3275
|
-
|
3276
|
-
attr_reader :name
|
3277
|
-
attr_reader :properties
|
3278
|
-
|
3279
|
-
def ReportSection(name)
|
3280
|
-
|
3281
|
-
@properties = Array.new()
|
3282
|
-
@name = name
|
3283
|
-
end
|
3284
|
-
|
3285
|
-
|
3286
|
-
def addProperty(name, value)
|
3287
|
-
|
3288
|
-
@properties[name.to_s] = value
|
3289
|
-
end
|
3290
|
-
|
3291
|
-
end
|
3292
|
-
|
3293
|
-
|
3294
72
|
# TODO add
|
3295
73
|
def self.site_device_scan(connection, site_id, device_array, host_array, debug = false)
|
3296
74
|
|
@@ -3348,5 +126,4 @@ end
|
|
3348
126
|
end
|
3349
127
|
end
|
3350
128
|
|
3351
|
-
|
3352
129
|
end
|