nexpose 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.markdown +1 -1
  2. data/lib/nexpose.rb +129 -0
  3. data/nexpose.gemspec +1 -1
  4. metadata +6 -7
  5. data/nexpose.rb +0 -2897
data/README.markdown CHANGED
@@ -1,6 +1,6 @@
1
1
  # Nexpose
2
2
 
3
- This is the official gem package for the Ruby NeXpose API included in the Metasploit Framework. This version is based on SVN revision 12430.
3
+ This is the official gem package for the Ruby Nexpose API included in the Metasploit Framework. This version is based on SVN revision 12430.
4
4
  The upstream for this gem can be found at https://metasploit.com/svn/framework3/trunk/lib/rapid7
5
5
 
6
6
  # Credits
data/lib/nexpose.rb CHANGED
@@ -350,6 +350,109 @@ module NexposeAPI
350
350
  r.success
351
351
  end
352
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
+
353
456
  #-------------------------------------------------------------------------
354
457
  # Returns all asset group information
355
458
  #-------------------------------------------------------------------------
@@ -446,6 +549,32 @@ module NexposeAPI
446
549
  end
447
550
  end
448
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
+
449
578
  def site_delete(param)
450
579
  r = execute(make_xml('SiteDeleteRequest', { 'site-id' => param }))
451
580
  r.success
data/nexpose.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  APP_NAME = "nexpose"
4
- VERSION = "0.0.7"
4
+ VERSION = "0.0.8"
5
5
  REVISION = "12878"
6
6
 
7
7
  Gem::Specification.new do |s|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexpose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,12 +10,12 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-05 00:00:00.000000000 -05:00
13
+ date: 2011-11-07 00:00:00.000000000 -06:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: librex
18
- requirement: &25538520 !ruby/object:Gem::Requirement
18
+ requirement: &2920356 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ! '>='
@@ -23,10 +23,10 @@ dependencies:
23
23
  version: 0.0.32
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *25538520
26
+ version_requirements: *2920356
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rex
29
- requirement: &25538244 !ruby/object:Gem::Requirement
29
+ requirement: &19472268 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ! '>='
@@ -34,7 +34,7 @@ dependencies:
34
34
  version: 1.0.2
35
35
  type: :runtime
36
36
  prerelease: false
37
- version_requirements: *25538244
37
+ version_requirements: *19472268
38
38
  description: This gem provides a Ruby API to the NeXpose vulnerability management
39
39
  product by Rapid7. This version is based on Metasploit SVN revision 12878
40
40
  email:
@@ -46,7 +46,6 @@ extra_rdoc_files:
46
46
  - README.markdown
47
47
  files:
48
48
  - nexpose.gemspec
49
- - nexpose.rb
50
49
  - Rakefile
51
50
  - README
52
51
  - README.markdown
data/nexpose.rb DELETED
@@ -1,2897 +0,0 @@
1
- #
2
- # The NeXpose API
3
- #
4
- =begin
5
-
6
- Copyright (C) 2009-2011, Rapid7 LLC
7
- All rights reserved.
8
-
9
- Redistribution and use in source and binary forms, with or without modification,
10
- are permitted provided that the following conditions are met:
11
-
12
- * Redistributions of source code must retain the above copyright notice,
13
- this list of conditions and the following disclaimer.
14
-
15
- * Redistributions in binary form must reproduce the above copyright notice,
16
- this list of conditions and the following disclaimer in the documentation
17
- and/or other materials provided with the distribution.
18
-
19
- * Neither the name of Rapid7 LLC nor the names of its contributors
20
- may be used to endorse or promote products derived from this software
21
- without specific prior written permission.
22
-
23
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
27
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
-
34
- =end
35
-
36
- #
37
- # WARNING! This code makes an SSL connection to the NeXpose server, but does NOT
38
- # verify the certificate at this time. This can be a security issue if
39
- # an attacker is able to man-in-the-middle the connection between the
40
- # Metasploit console and the NeXpose server. In the common case of
41
- # running NeXpose and Metasploit on the same host, this is a low risk.
42
- #
43
-
44
- #
45
- # WARNING! This code is still rough and going through substantive changes. While
46
- # you can build tools using this library today, keep in mind that method
47
- # names and parameters may change in the future.
48
- #
49
-
50
- require 'date'
51
- require 'rexml/document'
52
- require 'net/https'
53
- require 'net/http'
54
- require 'uri'
55
- require 'rex/mime'
56
-
57
- module Nexpose
58
-
59
- module Sanitize
60
- def replace_entities(str)
61
- ret = str.dup
62
- ret.gsub!(/&/, "&amp;")
63
- ret.gsub!(/'/, "&apos;")
64
- ret.gsub!(/"/, "&quot;")
65
- ret.gsub!(/</, "&lt;")
66
- ret.gsub!(/>/, "&gt;")
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
- # Returns all asset group information
355
- #-------------------------------------------------------------------------
356
- def asset_groups_listing()
357
- r = execute(make_xml('AssetGroupListingRequest'))
358
-
359
- if r.success
360
- res = []
361
- r.res.elements.each('//AssetGroupSummary') do |group|
362
- res << {
363
- :asset_group_id => group.attributes['id'].to_i,
364
- :name => group.attributes['name'].to_s,
365
- :description => group.attributes['description'].to_s,
366
- :risk_score => group.attributes['riskscore'].to_f,
367
- }
368
- end
369
- res
370
- else
371
- false
372
- end
373
- end
374
-
375
- #-------------------------------------------------------------------------
376
- # Returns an asset group configuration information for a specific group ID
377
- #-------------------------------------------------------------------------
378
- def asset_group_config(group_id)
379
- r = execute(make_xml('AssetGroupConfigRequest', {'group-id' => group_id}))
380
-
381
- if r.success
382
- res = []
383
- r.res.elements.each('//Devices/device') do |device_info|
384
- res << {
385
- :device_id => device_info.attributes['id'].to_i,
386
- :site_id => device_info.attributes['site-id'].to_i,
387
- :address => device_info.attributes['address'].to_s,
388
- :riskfactor => device_info.attributes['riskfactor'].to_f,
389
- }
390
- end
391
- res
392
- else
393
- false
394
- end
395
- end
396
-
397
- #-----------------------------------------------------------------------
398
- # Starts device specific site scanning.
399
- #
400
- # devices - An Array of device IDs
401
- # hosts - An Array of Hashes [o]=>{:range=>"to,from"} [1]=>{:host=>host}
402
- #-----------------------------------------------------------------------
403
- def site_device_scan_start(site_id, devices, hosts)
404
-
405
- if hosts == nil and devices == nil
406
- raise ArgumentError.new("Both the device and host list is nil")
407
- end
408
-
409
- xml = make_xml('SiteDevicesScanRequest', {'site-id' => site_id})
410
-
411
- if devices != nil
412
- inner_xml = REXML::Element.new 'Devices'
413
- for device_id in devices
414
- inner_xml.add_element 'device', {'id' => "#{device_id}"}
415
- end
416
- xml.add_element inner_xml
417
- end
418
-
419
- if hosts != nil
420
- inner_xml = REXML::Element.new 'Hosts'
421
- hosts.each_index do |x|
422
- if hosts[x].key? :range
423
- to = hosts[x][:range].split(',')[0]
424
- from = hosts[x][:range].split(',')[1]
425
- inner_xml.add_element 'range', {'to' => "#{to}", 'from' => "#{from}"}
426
- end
427
- if hosts[x].key? :host
428
- host_element = REXML::Element.new 'host'
429
- host_element.text = "#{hosts[x][:host]}"
430
- inner_xml.add_element host_element
431
- end
432
- end
433
- xml.add_element inner_xml
434
- end
435
-
436
- r = execute xml
437
- if r.success
438
- r.res.elements.each('//Scan') do |scan_info|
439
- return {
440
- :scan_id => scan_info.attributes['scan-id'].to_i,
441
- :engine_id => scan_info.attributes['engine-id'].to_i
442
- }
443
- end
444
- else
445
- false
446
- end
447
- end
448
-
449
- def site_delete(param)
450
- r = execute(make_xml('SiteDeleteRequest', { 'site-id' => param }))
451
- r.success
452
- end
453
-
454
- def site_listing
455
- r = execute(make_xml('SiteListingRequest', { }))
456
-
457
- if(r.success)
458
- res = []
459
- r.res.elements.each("//SiteSummary") do |site|
460
- res << {
461
- :site_id => site.attributes['id'].to_i,
462
- :name => site.attributes['name'].to_s,
463
- :risk_factor => site.attributes['risk_factor'].to_f,
464
- :risk_score => site.attributes['risk_score'].to_f,
465
- }
466
- end
467
- return res
468
- else
469
- return false
470
- end
471
- end
472
-
473
- #-----------------------------------------------------------------------
474
- # TODO: Needs to be expanded to included details
475
- #-----------------------------------------------------------------------
476
- def site_scan_history(site_id)
477
- r = execute(make_xml('SiteScanHistoryRequest', {'site-id' => site_id.to_s}))
478
-
479
- if (r.success)
480
- res = []
481
- r.res.elements.each("//ScanSummary") do |site_scan_history|
482
- res << {
483
- :site_id => site_scan_history.attributes['site-id'].to_i,
484
- :scan_id => site_scan_history.attributes['scan-id'].to_i,
485
- :engine_id => site_scan_history.attributes['engine-id'].to_i,
486
- :start_time => site_scan_history.attributes['startTime'].to_s,
487
- :end_time => site_scan_history.attributes['endTime'].to_s
488
- }
489
- end
490
- res
491
- else
492
- false
493
- end
494
- end
495
-
496
- ###################
497
- # SILO MANAGEMENT #
498
- ###################
499
-
500
- #########################
501
- # MULTI-TENANT USER OPS #
502
- #########################
503
-
504
- #-------------------------------------------------------------------------
505
- # Creates a multi-tenant user
506
- #
507
- # user_config - A map of the user data.
508
- #
509
- # REQUIRED PARAMS
510
- # user-id, authsrcid, user-name, full-name, enabled, superuser
511
- #
512
- # OPTIONAL PARAMS
513
- # email, password
514
- #
515
- # silo_configs - An array of maps of silo specific data
516
- #
517
- # REQUIRED PARAMS
518
- # silo-id, role-name, all-groups, all-sites, default-silo
519
- #
520
- # allowed_groups/allowed_sites - An array of ids
521
- #-------------------------------------------------------------------------
522
- def create_multi_tenant_user(user_config, silo_configs)
523
- xml = make_xml('MultiTenantUserCreateRequest')
524
- mtu_config_xml = make_xml('MultiTenantUserConfig', user_config, '', false)
525
-
526
- # Add the silo access
527
- silo_xml = make_xml('SiloAccesses', {}, '', false)
528
- silo_config_xml = make_xml('SiloAccess', {}, '', false)
529
- silo_configs.keys.each do |k|
530
- if k.eql? 'allowed_sites'
531
- allowed_sites_xml = make_xml('AllowedSites', {}, '', false)
532
- silo_configs['allowed_sites'].each do |allowed_site|
533
- allowed_sites_xml.add_element make_xml('AllowedSite', {'id' => allowed_site}, '', false)
534
- end
535
- silo_config_xml.add_element allowed_sites_xml
536
- elsif k.eql? 'allowed_groups'
537
- allowed_groups_xml = make_xml('AllowedGroups', {}, '', false)
538
- silo_configs['allowed_groups'].each do |allowed_group|
539
- allowed_groups_xml.add_element make_xml('AllowedGroup', {'id' => allowed_group}, '', false)
540
- end
541
- silo_config_xml.add_element allowed_groups_xml
542
- else
543
- silo_config_xml.attributes[k] = silo_configs[k]
544
- end
545
- end
546
- silo_xml.add_element silo_config_xml
547
- mtu_config_xml.add_element silo_xml
548
- xml.add_element mtu_config_xml
549
- r = execute xml, '1.2'
550
- r.success
551
- end
552
-
553
-
554
- #-------------------------------------------------------------------------
555
- # Lists all the multi-tenant users and their attributes.
556
- #-------------------------------------------------------------------------
557
- def list_mtu
558
- xml = make_xml('MultiTenantUserListingRequest')
559
- r = execute xml, '1.2'
560
-
561
- if r.success
562
- res = []
563
- r.res.elements.each("//MultiTenantUserSummary") do |mtu|
564
- res << {
565
- :id => mtu.attributes['id'],
566
- :full_name => mtu.attributes['full-name'],
567
- :user_name => mtu.attributes['user-name'],
568
- :email => mtu.attributes['email'],
569
- :super_user => mtu.attributes['superuser'],
570
- :enabled => mtu.attributes['enabled'],
571
- :auth_module => mtu.attributes['auth-module'],
572
- :silo_count => mtu.attributes['silo-count'],
573
- :locked => mtu.attributes['locked']
574
- }
575
- end
576
- res
577
- else
578
- false
579
- end
580
- end
581
-
582
- #-------------------------------------------------------------------------
583
- # Delete a multi-tenant user
584
- #-------------------------------------------------------------------------
585
- def delete_mtu user_name, user_id
586
- using_user_name = (user_name and not user_name.empty?)
587
- xml = make_xml('MultiTenantUserDeleteRequest', (using_user_name ? {'user-name' => user_name} : {'user-id' => user_id}))
588
- r = execute xml, '1.2'
589
- r.success
590
- end
591
-
592
- ####################
593
- # SILO PROFILE OPS #
594
- ####################
595
-
596
- #-------------------------------------------------------------------------
597
- # Creates a silo profile
598
- #
599
- # silo_config - A map of the silo data.
600
- #
601
- # REQUIRED PARAMS
602
- # id, name, all‐licensed-modules, all‐global-engines, all-global-report-templates, all‐global-scan‐templates
603
- #
604
- # OPTIONAL PARAMS
605
- # description
606
- #
607
- # permissions - A map of an array of maps of silo specific data
608
- #
609
- # REQUIRED PARAMS
610
- # silo-id, role-name, all-groups, all-sites, default-silo
611
- #
612
- # allowed_groups/allowed_sites - An array of ids
613
- #-------------------------------------------------------------------------
614
- def create_silo_profile silo_profile_config, permissions
615
- xml = make_xml 'SiloProfileCreateRequest'
616
- spc_xml = make_xml('SiloProfileConfig', silo_profile_config, '', false)
617
-
618
- # Add the permissions
619
- if permissions['global_report_templates']
620
- grt_xml = make_xml('GlobalReportTemplates', {}, '', false)
621
- permissions['global_report_templates'].each do |name|
622
- grt_xml.add_element make_xml('GlobalReportTemplate', {'name' => name}, '', false)
623
- end
624
- spc_xml.add_element grt_xml
625
- end
626
-
627
- if permissions['global_scan_engines']
628
- gse_xml = make_xml('GlobalScanEngines', {}, '', false)
629
- permissions['global_scan_engines'].each do |name|
630
- gse_xml.add_element make_xml('GlobalScanEngine', {'name' => name}, '', false)
631
- end
632
- spc_xml.add_element gse_xml
633
- end
634
-
635
- if permissions['global_scan_templates']
636
- gst_xml = make_xml('GlobalScanTemplates', {}, '', false)
637
- permissions['global_scan_templates'].each do |name|
638
- gst_xml.add_element make_xml('GlobalScanTemplate', {'name' => name}, '', false)
639
- end
640
- spc_xml.add_element gst_xml
641
- end
642
-
643
- if permissions['licensed_modules']
644
- lm_xml = make_xml('LicensedModules', {}, '', false)
645
- permissions['licensed_modules'].each do |name|
646
- lm_xml.add_element make_xml('LicensedModule', {'name' => name}, '', false)
647
- end
648
- spc_xml.add_element lm_xml
649
- end
650
-
651
- if permissions['restricted_report_formats']
652
- rrf_xml = make_xml('RestrictedReportFormats', {}, '', false)
653
- permissions['restricted_report_formats'].each do |name|
654
- rrf_xml.add_element make_xml('RestrictedReportFormat', {'name' => name}, '', false)
655
- end
656
- spc_xml.add_element rrf_xml
657
- end
658
-
659
- if permissions['restricted_report_sections']
660
- rrs_xml = make_xml('RestrictedReportSections', {}, '', false)
661
- permissions['restricted_report_sections'].each do |name|
662
- rrs_xml.add_element make_xml('RestrictedReportSection', {'name' => name}, '', false)
663
- end
664
- spc_xml.add_element rrs_xml
665
- end
666
-
667
- xml.add_element spc_xml
668
- r = execute xml, '1.2'
669
- r.success
670
- end
671
-
672
- #-------------------------------------------------------------------------
673
- # Lists all the silo profiles and their attributes.
674
- #-------------------------------------------------------------------------
675
- def list_silo_profiles
676
- xml = make_xml('SiloProfileListingRequest')
677
- r = execute xml, '1.2'
678
-
679
- if r.success
680
- res = []
681
- r.res.elements.each("//SiloProfileSummary") do |silo_profile|
682
- res << {
683
- :id => silo_profile.attributes['id'],
684
- :name => silo_profile.attributes['name'],
685
- :description => silo_profile.attributes['description'],
686
- :global_report_template_count => silo_profile.attributes['global-report-template-count'],
687
- :global_scan_engine_count => silo_profile.attributes['global-scan-engine-count'],
688
- :global_scan_template_count => silo_profile.attributes['global-scan-template-count'],
689
- :licensed_module_count => silo_profile.attributes['licensed-module-count'],
690
- :restricted_report_section_count => silo_profile.attributes['restricted-report-section-count'],
691
- :all_licensed_modules => silo_profile.attributes['all-licensed-modules'],
692
- :all_global_engines => silo_profile.attributes['all-global-engines'],
693
- :all_global_report_templates => silo_profile.attributes['all-global-report-templates'],
694
- :all_global_scan_templates => silo_profile.attributes['all-global-scan-templates']
695
- }
696
- end
697
- res
698
- else
699
- false
700
- end
701
- end
702
-
703
- #-------------------------------------------------------------------------
704
- # Delete a silo profile
705
- #-------------------------------------------------------------------------
706
- def delete_silo_profile name, id
707
- using_name = (name and not name.empty?)
708
- xml = make_xml('SiloProfileDeleteRequest', (using_name ? {'name' => name} : {'silo-profile-id' => id}))
709
- r = execute xml, '1.2'
710
- r.success
711
- end
712
-
713
- ####################
714
- # SILO OPS #
715
- ####################
716
-
717
- #-------------------------------------------------------------------------
718
- # Creates a silo
719
- #
720
- # silo_config - A map of the silo creation data.
721
- #
722
- # REQUIRED PARAMS
723
- # id, name, silo-profile-id, max-assets, max-hosted-assets, max-users
724
- #
725
- # OPTIONAL PARAMS
726
- # description
727
- #-------------------------------------------------------------------------
728
- def create_silo silo_config
729
- xml = make_xml 'SiloCreateRequest'
730
- silo_config_xml = make_xml 'SiloConfig', {}, '', false
731
-
732
- # Add the attributes
733
- silo_config.keys.each do |key|
734
- if not 'merchant'.eql? key and not 'organization'.eql? key
735
- silo_config_xml.attributes[key] = silo_config[key]
736
- end
737
- end
738
-
739
- # Add Organization info
740
- if silo_config['organization']
741
- org_xml = make_xml 'Organization', {}, '', false
742
- silo_config['organization'].keys.each do |key|
743
- if not 'address'.eql? key
744
- org_xml.attributes[key] = silo_config['organization'][key]
745
- end
746
- end
747
-
748
- address_xml = make_xml 'Address', silo_config['organization']['address'], '', false
749
- org_xml.add_element address_xml
750
- silo_config_xml.add_element org_xml
751
- end
752
-
753
- # Add Merchant info
754
- if silo_config['merchant']
755
- merchant_xml = make_xml 'Merchant', {}, '', false
756
-
757
- silo_config['merchant'].keys.each do |key|
758
- if not 'dba'.eql? key and not 'other_industries'.eql? key and not 'qsa'.eql? key and not 'address'.eql? key
759
- merchant_xml.attributes[key] = silo_config['merchant'][key]
760
- end
761
- end
762
-
763
- # Add the merchant address
764
- merchant_address_xml = make_xml 'Address', silo_config['merchant']['address'], '', false
765
- merchant_xml.add_element merchant_address_xml
766
-
767
- #Now add the complex data types
768
- if silo_config['merchant']['dba']
769
- dba_xml = make_xml 'DBAs', {}, '', false
770
- silo_config['merchant']['dba'].each do |name|
771
- dba_xml.add_element make_xml('DBA', {'name' => name}, '', false)
772
- end
773
- merchant_xml.add_element dba_xml
774
- end
775
-
776
- if silo_config['merchant']['other_industries']
777
- ois_xml = make_xml 'OtherIndustries', {}, '', false
778
- silo_config['merchant']['other_industries'].each do |name|
779
- ois_xml.add_element make_xml('Industry', {'name' => name}, '', false)
780
- end
781
- merchant_xml.add_element ois_xml
782
- end
783
-
784
- if silo_config['merchant']['qsa']
785
- qsa_xml = make_xml 'QSA', {}, '', false
786
- silo_config['merchant']['qsa'].keys.each do |key|
787
- if not 'address'.eql? key
788
- qsa_xml.attributes[key] = silo_config['merchant']['qsa'][key]
789
- end
790
- end
791
-
792
- # Add the address for this QSA
793
- address_xml = make_xml 'Address', silo_config['merchant']['qsa']['address'], '', false
794
-
795
- qsa_xml.add_element address_xml
796
- merchant_xml.add_element qsa_xml
797
- end
798
- silo_config_xml.add_element merchant_xml
799
- end
800
-
801
- xml.add_element silo_config_xml
802
- r = execute xml, '1.2'
803
- r.success
804
- end
805
-
806
- #-------------------------------------------------------------------------
807
- # Lists all the silos and their attributes.
808
- #-------------------------------------------------------------------------
809
- def list_silos
810
- xml = make_xml('SiloListingRequest')
811
- r = execute xml, '1.2'
812
-
813
- if r.success
814
- res = []
815
- r.res.elements.each("//SiloSummary") do |silo_profile|
816
- res << {
817
- :id => silo_profile.attributes['id'],
818
- :name => silo_profile.attributes['name'],
819
- :description => silo_profile.attributes['description']
820
- }
821
- end
822
- res
823
- else
824
- false
825
- end
826
- end
827
-
828
- #-------------------------------------------------------------------------
829
- # Delete a silo
830
- #-------------------------------------------------------------------------
831
- def delete_silo name, id
832
- using_name = (name and not name.empty?)
833
- xml = make_xml('SiloDeleteRequest', (using_name ? {'silo-name' => name} : {'silo-id' => id}))
834
- r = execute xml, '1.2'
835
- r.success
836
- end
837
-
838
- def site_device_listing(site_id)
839
- r = execute(make_xml('SiteDeviceListingRequest', { 'site-id' => site_id.to_s }))
840
-
841
- if(r.success)
842
- res = []
843
- r.res.elements.each("//device") do |device|
844
- res << {
845
- :device_id => device.attributes['id'].to_i,
846
- :address => device.attributes['address'].to_s,
847
- :risk_factor => device.attributes['risk_factor'].to_f,
848
- :risk_score => device.attributes['risk_score'].to_f,
849
- }
850
- end
851
- return res
852
- else
853
- return false
854
- end
855
- end
856
-
857
- def report_template_listing
858
- r = execute(make_xml('ReportTemplateListingRequest', { }))
859
-
860
- if(r.success)
861
- res = []
862
- r.res.elements.each("//ReportTemplateSummary") do |template|
863
- desc = ''
864
- template.elements.each("//description") do |ent|
865
- desc = ent.text
866
- end
867
-
868
- res << {
869
- :template_id => template.attributes['id'].to_s,
870
- :name => template.attributes['name'].to_s,
871
- :description => desc.to_s
872
- }
873
- end
874
- return res
875
- else
876
- return false
877
- end
878
- end
879
-
880
-
881
- def console_command(cmd_string)
882
- xml = make_xml('ConsoleCommandRequest', { })
883
- cmd = REXML::Element.new('Command')
884
- cmd.text = cmd_string
885
- xml << cmd
886
-
887
- r = execute(xml)
888
-
889
- if(r.success)
890
- res = ""
891
- r.res.elements.each("//Output") do |out|
892
- res << out.text.to_s
893
- end
894
-
895
- return res
896
- else
897
- return false
898
- end
899
- end
900
-
901
- def system_information
902
- r = execute(make_xml('SystemInformationRequest', { }))
903
-
904
- if(r.success)
905
- res = {}
906
- r.res.elements.each("//Statistic") do |stat|
907
- res[ stat.attributes['name'].to_s ] = stat.text.to_s
908
- end
909
-
910
- return res
911
- else
912
- return false
913
- end
914
- end
915
-
916
- end
917
-
918
- # === Description
919
- # Object that represents a connection to a NeXpose Security Console.
920
- #
921
- # === Examples
922
- # # Create a new Nexpose Connection on the default port
923
- # nsc = Connection.new("10.1.40.10","nxadmin","password")
924
- #
925
- # # Login to NSC and Establish a Session ID
926
- # nsc.login()
927
- #
928
- # # Check Session ID
929
- # if (nsc.session_id)
930
- # puts "Login Successful"
931
- # else
932
- # puts "Login Failure"
933
- # end
934
- #
935
- # # //Logout
936
- # logout_success = nsc.logout()
937
- # if (! logout_success)
938
- # puts "Logout Failure" + "<p>" + nsc.error_msg.to_s
939
- # end
940
- #
941
- class Connection
942
- include XMLUtils
943
- include NexposeAPI
944
-
945
- # true if an error condition exists; false otherwise
946
- attr_reader :error
947
- # Error message string
948
- attr_reader :error_msg
949
- # The last XML request sent by this object
950
- attr_reader :request_xml
951
- # The last XML response received by this object
952
- attr_reader :response_xml
953
- # Session ID of this connection
954
- attr_reader :session_id
955
- # The hostname or IP Address of the NSC
956
- attr_reader :host
957
- # The port of the NSC (default is 3780)
958
- attr_reader :port
959
- # The username used to login to the NSC
960
- attr_reader :username
961
- # The password used to login to the NSC
962
- attr_reader :password
963
- # The URL for communication
964
- attr_reader :url
965
-
966
- # Constructor for Connection
967
- def initialize(ip, user, pass, port = 3780, silo_id = nil)
968
- @host = ip
969
- @port = port
970
- @username = user
971
- @password = pass
972
- @silo_id = silo_id
973
- @session_id = nil
974
- @error = false
975
- @url = "https://#{@host}:#{@port}/api/API_VERSION/xml"
976
- end
977
-
978
- # Establish a new connection and Session ID
979
- def login
980
- begin
981
- login_hash = { 'sync-id' => 0, 'password' => @password, 'user-id' => @username }
982
- unless @silo_id.nil?
983
- login_hash['silo-id'] = @silo_id
984
- end
985
- r = execute(make_xml('LoginRequest', login_hash))
986
- rescue APIError
987
- raise AuthenticationFailed.new(r)
988
- end
989
- if(r.success)
990
- @session_id = r.sid
991
- return true
992
- end
993
- end
994
-
995
- # Logout of the current connection
996
- def logout
997
- r = execute(make_xml('LogoutRequest', {'sync-id' => 0}))
998
- if(r.success)
999
- return true
1000
- end
1001
- raise APIError.new(r, 'Logout failed')
1002
- end
1003
-
1004
- # Execute an API request
1005
- def execute(xml, version = '1.1')
1006
- @api_version = version
1007
- APIRequest.execute(@url,xml.to_s, @api_version)
1008
- end
1009
-
1010
- # Download a specific URL
1011
- def download(url)
1012
- uri = URI.parse(url)
1013
- http = Net::HTTP.new(@host, @port)
1014
- http.use_ssl = true
1015
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE # XXX: security issue
1016
- headers = {'Cookie' => "nexposeCCSessionID=#{@session_id}"}
1017
- resp, data = http.get(uri.path, headers)
1018
- data
1019
- end
1020
- end
1021
-
1022
- # === Description
1023
- # Object that represents a listing of all of the sites available on an NSC.
1024
- #
1025
- # === Example
1026
- # # Create a new Nexpose Connection on the default port and Login
1027
- # nsc = Connection.new("10.1.40.10","nxadmin","password")
1028
- # nsc->login();
1029
- #
1030
- # # Get Site Listing
1031
- # sitelisting = SiteListing.new(nsc)
1032
- #
1033
- # # Enumerate through all of the SiteSummaries
1034
- # sitelisting.sites.each do |sitesummary|
1035
- # # Do some operation on each site
1036
- # end
1037
- #
1038
- class SiteListing
1039
- # true if an error condition exists; false otherwise
1040
- attr_reader :error
1041
- # Error message string
1042
- attr_reader :error_msg
1043
- # The last XML request sent by this object
1044
- attr_reader :request_xml
1045
- # The last XML response received by this object
1046
- attr_reader :response_xml
1047
- # The NSC Connection associated with this object
1048
- attr_reader :connection
1049
- # Array containing SiteSummary objects for each site in the connection
1050
- attr_reader :sites
1051
- # The number of sites
1052
- attr_reader :site_count
1053
-
1054
- # Constructor
1055
- # SiteListing (connection)
1056
- def initialize(connection)
1057
- @sites = []
1058
-
1059
- @connection = connection
1060
-
1061
- r = @connection.execute('<SiteListingRequest session-id="' + @connection.session_id.to_s + '"/>')
1062
-
1063
- if (r.success)
1064
- parse(r.res)
1065
- else
1066
- raise APIError.new(r, "Failed to get site listing")
1067
- end
1068
- end
1069
-
1070
- def parse(r)
1071
- r.elements.each('SiteListingResponse/SiteSummary') do |s|
1072
- site_summary = SiteSummary.new(
1073
- s.attributes['id'].to_s,
1074
- s.attributes['name'].to_s,
1075
- s.attributes['description'].to_s,
1076
- s.attributes['riskfactor'].to_s
1077
- )
1078
- @sites.push(site_summary)
1079
- end
1080
- @site_count = @sites.length
1081
- end
1082
- end
1083
-
1084
- # === Description
1085
- # Object that represents the summary of a NeXpose Site.
1086
- #
1087
- class SiteSummary
1088
- # The Site ID
1089
- attr_reader :id
1090
- # The Site Name
1091
- attr_reader :site_name
1092
- # A Description of the Site
1093
- attr_reader :description
1094
- # User assigned risk multiplier
1095
- attr_reader :riskfactor
1096
-
1097
- # Constructor
1098
- # SiteSummary(id, site_name, description, riskfactor = 1)
1099
- def initialize(id, site_name, description, riskfactor = 1)
1100
- @id = id
1101
- @site_name = site_name
1102
- @description = description
1103
- @riskfactor = riskfactor
1104
- end
1105
-
1106
- def _set_id(id)
1107
- @id = id
1108
- end
1109
- end
1110
-
1111
- # === Description
1112
- # 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.
1113
- #
1114
- class IPRange
1115
- # Start of Range *Required
1116
- attr_reader :from;
1117
- # End of Range *Optional (If Null then IPRange is a single IP Address)
1118
- attr_reader :to;
1119
-
1120
- def initialize(from, to = nil)
1121
- @from = from
1122
- @to = to
1123
- end
1124
-
1125
- include Sanitize
1126
- def to_xml
1127
- if (to and not to.empty?)
1128
- return %Q{<range from="#{from}" to="#{to}"/>}
1129
- else
1130
- return %Q{<range from="#{from}"/>}
1131
- end
1132
- end
1133
- end
1134
-
1135
- # === Description
1136
- # Object that represents a hostname to be added to a site.
1137
- class HostName
1138
-
1139
- # The hostname
1140
- attr_reader :hostname
1141
-
1142
- def initialize(hostname)
1143
- @hostname = hostname
1144
- end
1145
-
1146
- include Sanitize
1147
- def to_xml
1148
- "<hostname>#{replace_entities(hostname)}</hostname>"
1149
- end
1150
- end
1151
-
1152
- # === Description
1153
- # Object that represents the configuration of a Site. This object is automatically created when a new Site object is instantiated.
1154
- #
1155
- class SiteConfig
1156
- # true if an error condition exists; false otherwise
1157
- attr_reader :error
1158
- # Error message string
1159
- attr_reader :error_msg
1160
- # The last XML request sent by this object
1161
- attr_reader :request_xml
1162
- # The last XML response received by this object
1163
- attr_reader :response_xml
1164
- # The NSC Connection associated with this object
1165
- attr_reader :connection
1166
- # The Site ID
1167
- attr_reader :site_id
1168
- # The Site Name
1169
- attr_reader :site_name
1170
- # A Description of the Site
1171
- attr_reader :description
1172
- # User assigned risk multiplier
1173
- attr_reader :riskfactor
1174
- # Array containing ((IPRange|HostName)*)
1175
- attr_reader :hosts
1176
- # Array containing (AdminCredentials*)
1177
- attr_reader :credentials
1178
- # Array containing ((SmtpAlera|SnmpAlert|SyslogAlert)*)
1179
- attr_reader :alerts
1180
- # ScanConfig object which holds Schedule and ScanTrigger Objects
1181
- attr_reader :scanConfig
1182
-
1183
- def initialize()
1184
- @xml_tag_stack = Array.new()
1185
- @hosts = Array.new()
1186
- @credentials = Array.new()
1187
- @alerts = Array.new()
1188
- @error = false
1189
- end
1190
-
1191
- # Adds a new host to the hosts array
1192
- def addHost(host)
1193
- @hosts.push(host)
1194
- end
1195
-
1196
- # Adds a new alert to the alerts array
1197
- def addAlert(alert)
1198
- @alerts.push(alert)
1199
- end
1200
-
1201
- # Adds a new set of credentials to the credentials array
1202
- def addCredentials(credential)
1203
- @credentials.push(credential)
1204
- end
1205
-
1206
- # TODO
1207
- def getSiteConfig(connection,site_id)
1208
- @connection = connection
1209
- @site_id = site_id
1210
-
1211
- r = APIRequest.execute(@connection.url,'<SiteConfigRequest session-id="' + @connection.session_id + '" site-id="' + @site_id + '"/>')
1212
- parse(r.res)
1213
- end
1214
-
1215
- def _set_site_id(site_id)
1216
- @site_id = site_id
1217
- end
1218
-
1219
- def _set_site_name(site_name)
1220
- @site_name = site_name
1221
- end
1222
-
1223
- def _set_description(description)
1224
- @description = description
1225
- end
1226
-
1227
- def _set_riskfactor(riskfactor)
1228
- @riskfactor = riskfactor
1229
- end
1230
-
1231
- def _set_scanConfig(scanConfig)
1232
- @scanConfig = scanConfig
1233
- end
1234
-
1235
- def _set_connection(connection)
1236
- @connection = connection
1237
- end
1238
- =begin
1239
- <SiteConfigResponse success='1'>
1240
- <Site name='Site1' id='243' description='' riskfactor='1.0'>
1241
- <Hosts>
1242
- <range from='127.0.0.1'/>
1243
- </Hosts>
1244
- <Credentials>
1245
- </Credentials>
1246
- <Alerting>
1247
- </Alerting>
1248
- <ScanConfig configID='243' name='Full audit' configVersion='3' engineID='2' templateID='full-audit'>
1249
- <Schedules>
1250
- </Schedules>
1251
- <ScanTriggers>
1252
- </ScanTriggers>
1253
- </ScanConfig>
1254
- </Site>
1255
-
1256
- =end
1257
-
1258
- def parse(response)
1259
- response.elements.each('SiteConfigResponse/Site') do |s|
1260
- @site_id = s.attributes['id']
1261
- @site_name = s.attributes['name']
1262
- @description = s.attributes['description']
1263
- @riskfactor = s.attributes['riskfactor']
1264
- s.elements.each('Hosts/range') do |r|
1265
- @hosts.push(IPRange.new(r.attributes['from'],r.attributes['to']))
1266
- end
1267
- s.elements.each('ScanConfig') do |c|
1268
- @scanConfig = ScanConfig.new(c.attributes['configID'],
1269
- c.attributes['name'],
1270
- c.attributes['configVersion'],
1271
- c.attributes['templateID'])
1272
- s.elements.each('Schedule') do |schedule|
1273
- schedule = new Schedule(schedule.attributes["type"], schedule.attributes["interval"], schedule.attributes["start"], schedule.attributes["enabled"])
1274
- @scanConfig.addSchedule(schedule)
1275
- end
1276
- end
1277
-
1278
- s.elements.each('Alerting/Alert') do |a|
1279
-
1280
- a.elements.each('smtpAlert') do |smtp|
1281
- smtp_alert = SmtpAlert.new(a.attributes["name"], smtp.attributes["sender"], smtp.attributes["limitText"], a.attributes["enabled"])
1282
-
1283
- smtp.elements.each('recipient') do |recipient|
1284
- smtp_alert.addRecipient(recipient.text)
1285
- end
1286
- @alerts.push(smtp_alert)
1287
- end
1288
-
1289
- a.elements.each('snmpAlert') do |snmp|
1290
- snmp_alert = SnmpAlert.new(a.attributes["name"], snmp.attributes["community"], snmp.attributes["server"], a.attributes["enabled"])
1291
- @alerts.push(snmp_alert)
1292
- end
1293
- a.elements.each('syslogAlert') do |syslog|
1294
- syslog_alert = SyslogAlert.new(a.attributes["name"], syslog.attributes["server"], a.attributes["enabled"])
1295
- @alerts.push(syslog_alert)
1296
- end
1297
-
1298
- a.elements.each('vulnFilter') do |vulnFilter|
1299
-
1300
- #vulnfilter = new VulnFilter.new(a.attributes["typemask"], a.attributes["severityThreshold"], $attrs["MAXALERTS"])
1301
- # Pop off the top alert on the stack
1302
- #$alert = @alerts.pop()
1303
- # Add the new recipient string to the Alert Object
1304
- #$alert.setVulnFilter($vulnfilter)
1305
- # Push the alert back on to the alert stack
1306
- #array_push($this->alerts, $alert)
1307
- end
1308
-
1309
- a.elements.each('scanFilter') do |scanFilter|
1310
- #<scanFilter scanStop='0' scanFailed='0' scanStart='1'/>
1311
- #scanfilter = ScanFilter.new(scanFilter.attributes['scanStop'],scanFilter.attributes['scanFailed'],scanFilter.attributes['scanStart'])
1312
- #alert = @alerts.pop()
1313
- #alert.setScanFilter(scanfilter)
1314
- #@alerts.push(alert)
1315
- end
1316
- end
1317
- end
1318
- end
1319
- end
1320
-
1321
- # === Description
1322
- # Object that represents the scan history of a site.
1323
- #
1324
- class SiteScanHistory
1325
- # true if an error condition exists; false otherwise
1326
- attr_reader :error
1327
- # Error message string
1328
- attr_reader :error_msg
1329
- # The last XML request sent by this object
1330
- attr_reader :request_xml
1331
- # The last XML response received by this object
1332
- attr_reader :response_xml
1333
- # The NSC Connection associated with this object
1334
- attr_reader :connection
1335
- # The Site ID
1336
- attr_reader :site_id
1337
- # //Array containing (ScanSummary*)
1338
- attr_reader :scan_summaries
1339
-
1340
- def initialize(connection, id)
1341
- @site_id = id
1342
- @error = false
1343
- @connection = connection
1344
- @scan_summaries = Array.new()
1345
-
1346
- r = @connection.execute('<SiteScanHistoryRequest' + ' session-id="' + @connection.session_id + '" site-id="' + @site_id + '"/>')
1347
- status = r.success
1348
- end
1349
- end
1350
-
1351
- # === Description
1352
- # 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.
1353
- #
1354
- class SiteDeviceListing
1355
-
1356
- # true if an error condition exists; false otherwise
1357
- attr_reader :error
1358
- # Error message string
1359
- attr_reader :error_msg
1360
- # The last XML request sent by this object
1361
- attr_reader :request_xml
1362
- # The last XML response received by this object
1363
- attr_reader :response_xml
1364
- # The NSC Connection associated with this object
1365
- attr_reader :connection
1366
- # The Site ID. 0 if all sites are specified.
1367
- attr_reader :site_id
1368
- # //Array of (Device)*
1369
- attr_reader :devices
1370
-
1371
- def initialize(connection, site_id = 0)
1372
-
1373
- @site_id = site_id
1374
- @error = false
1375
- @connection = connection
1376
- @devices = Array.new()
1377
-
1378
- r = nil
1379
- if (@site_id)
1380
- r = @connection.execute('<SiteDeviceListingRequest session-id="' + connection.session_id + '" site-id="' + @site_id + '"/>')
1381
- else
1382
- r = @connection.execute('<SiteDeviceListingRequest session-id="' + connection.session_id + '"/>')
1383
- end
1384
-
1385
- if(r.success)
1386
- response.elements.each('SiteDeviceListingResponse/SiteDevices/device') do |d|
1387
- @devices.push(Device.new(d.attributes['id'],@site_id,d.attributes["address"],d.attributes["riskfactor"],d.attributes['riskscore']))
1388
- end
1389
- end
1390
- end
1391
- end
1392
-
1393
- # === Description
1394
- # Object that represents a site, including the site configuration, scan history, and device listing.
1395
- #
1396
- # === Example
1397
- # # Create a new Nexpose Connection on the default port and Login
1398
- # nsc = Connection.new("10.1.40.10","nxadmin","password")
1399
- # nsc.login()
1400
- #
1401
- # # Get an Existing Site
1402
- # site_existing = Site.new(nsc,184)
1403
- #
1404
- # # Create a New Site, add some hosts, and save it to the NSC
1405
- # site = Site.new(nsc)
1406
- # site.setSiteConfig("New Site", "New Site Created in the API")
1407
- #
1408
- # # Add the hosts
1409
- # site.site_config.addHost(HostName.new("localhost"))
1410
- # site.site_config.addHost(IPRange.new("192.168.7.1","192.168.7.255"))
1411
- # site.site_config.addHost(IPRange.new("10.1.20.30"))
1412
- #
1413
- # status = site.saveSite()
1414
- #
1415
- class Site
1416
- # true if an error condition exists; false otherwise
1417
- attr_reader :error
1418
- # Error message string
1419
- attr_reader :error_msg
1420
- # The last XML request sent by this object
1421
- attr_reader :request_xml
1422
- # The last XML response received by this object
1423
- attr_reader :response_xml
1424
- # The NSC Connection associated with this object
1425
- attr_reader :connection
1426
- # The Site ID
1427
- # site_id = -1 means create a new site. The NSC will assign a new site_id on SiteSave.
1428
- attr_reader :site_id
1429
- # A summary overview of this site
1430
- # SiteSummary Object
1431
- attr_reader :site_summary
1432
- # The configuration of this site
1433
- # SiteConfig Object
1434
- attr_reader :site_config
1435
- # The device listing for this site
1436
- # SiteDeviceListing Object
1437
- attr_reader :site_device_listing
1438
- # The scan history of this site
1439
- # SiteScanHistory Object
1440
- attr_reader :site_scan_history
1441
-
1442
- def initialize(connection, site_id = -1)
1443
- @error = false
1444
- @connection = connection
1445
- @site_id = site_id
1446
-
1447
- # If site_id > 0 then get SiteConfig
1448
- if (@site_id.to_i > 0)
1449
- # Create new SiteConfig object
1450
- @site_config = SiteConfig.new()
1451
- # Populate SiteConfig Obect with Data from the NSC
1452
- @site_config.getSiteConfig(@connection,@site_id)
1453
- @site_summary = SiteSummary.new(@site_id, @site_config.site_name, @site_config.description, @site_config.riskfactor)
1454
- @site_scan_history = SiteScanHistory.new(@connection,@site_id)
1455
- @site_device_listing = SiteDeviceListing.new(@connection,@site_id)
1456
-
1457
- else
1458
- # Just in case user enters a number > -1 or = 0
1459
- @site_id = -1
1460
-
1461
- @site_config = SiteConfig.new()
1462
- setSiteConfig("New Site " + rand(999999999999).to_s,"")
1463
- @site_summary = nil
1464
-
1465
- end
1466
-
1467
- end
1468
-
1469
- # Creates a new site summary
1470
- def setSiteSummary(site_name, description, riskfactor = 1)
1471
- @site_summary = SiteSummary.new(-1,site_name,description,riskfactor)
1472
-
1473
- end
1474
-
1475
- # Creates a new site configuration
1476
- def setSiteConfig(site_name, description, riskfactor = 1)
1477
- setSiteSummary(site_name,description,riskfactor)
1478
- @site_config = SiteConfig.new()
1479
- @site_config._set_site_id(-1)
1480
- @site_config._set_site_name(site_name)
1481
- @site_config._set_description(description)
1482
- @site_config._set_riskfactor(riskfactor)
1483
- @site_config._set_scanConfig(ScanConfig.new(-1,"tmp","full-audit"))
1484
- @site_config._set_connection(@connection)
1485
-
1486
- end
1487
-
1488
- # Initiates a scan of this site. If successful returns scan_id and engine_id in an associative array. Returns false if scan is unsuccessful.
1489
- def scanSite()
1490
- r = @connection.execute('<SiteScanRequest session-id="' + "#{@connection.session_id}" + '" site-id="' + "#{@site_id}" + '"/>')
1491
- if(r.success)
1492
- res = {}
1493
- r.res.elements.each('//Scan/') do |s|
1494
- res[:scan_id] = s.attributes['scan-id']
1495
- res[:engine_id] = s.attributes['engine-id']
1496
- end
1497
- return res
1498
- else
1499
- return false
1500
- end
1501
- end
1502
-
1503
- # Saves this site in the NSC
1504
- def saveSite()
1505
- r = @connection.execute('<SiteSaveRequest session-id="' + @connection.session_id + '">' + getSiteXML() + ' </SiteSaveRequest>')
1506
- if (r.success)
1507
- @site_id = r.attributes['site-id']
1508
- @site_config._set_site_id(@site_id)
1509
- @site_config.scanConfig._set_configID(@site_id)
1510
- @site_config.scanConfig._set_name(@site_id)
1511
- return true
1512
- else
1513
- return false
1514
- end
1515
- end
1516
-
1517
- def deleteSite()
1518
- r = @connection.execute('<SiteDeleteRequest session-id="' + @connection.session_id.to_s + '" site-id="' + @site_id + '"/>')
1519
- r.success
1520
- end
1521
-
1522
-
1523
- def printSite()
1524
- puts "Site ID: " + @site_summary.id
1525
- puts "Site Name: " + @site_summary.site_name
1526
- puts "Site Description: " + @site_summary.description
1527
- puts "Site Risk Factor: " + @site_summary.riskfactor
1528
- end
1529
-
1530
- def getSiteXML()
1531
-
1532
- xml = '<Site id="' + "#{@site_config.site_id}" + '" name="' + "#{@site_config.site_name}" + '" description="' + "#{@site_config.description}" + '" riskfactor="' + "#{@site_config.riskfactor}" + '">'
1533
-
1534
- xml << ' <Hosts>'
1535
- @site_config.hosts.each do |h|
1536
- xml << h.to_xml if h.respond_to? :to_xml
1537
- end
1538
- xml << '</Hosts>'
1539
-
1540
- xml << '<Credentials>'
1541
- @site_config.credentials.each do |c|
1542
- xml << c.to_xml if c.respond_to? :to_xml
1543
- end
1544
- xml << ' </Credentials>'
1545
-
1546
- xml << ' <Alerting>'
1547
- @site_config.alerts.each do |a|
1548
- xml << a.to_xml if a.respond_to? :to_xml
1549
- end
1550
- xml << ' </Alerting>'
1551
-
1552
- xml << ' <ScanConfig configID="' + "#{@site_config.scanConfig.configID}" + '" name="' + "#{@site_config.scanConfig.name}" + '" templateID="' + "#{@site_config.scanConfig.templateID}" + '" configVersion="' + "#{@site_config.scanConfig.configVersion}" + '">'
1553
-
1554
- xml << ' <Schedules>'
1555
- @site_config.scanConfig.schedules.each do |s|
1556
- xml << ' <Schedule enabled="' + s.enabled + '" type="' + s.type + '" interval="' + s.interval + '" start="' + s.start + '"/>'
1557
- end
1558
- xml << ' </Schedules>'
1559
-
1560
- xml << ' <ScanTriggers>'
1561
- @site_config.scanConfig.scanTriggers.each do |s|
1562
-
1563
- if (s.class.to_s == "Nexpose::AutoUpdate")
1564
- xml << ' <autoUpdate enabled="' + s.enabled + '" incremental="' + s.incremental + '"/>'
1565
- end
1566
- end
1567
-
1568
- xml << ' </ScanTriggers>'
1569
-
1570
- xml << ' </ScanConfig>'
1571
-
1572
- xml << ' </Site>'
1573
-
1574
- return xml
1575
- end
1576
- end
1577
-
1578
- # === Description
1579
- # 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.
1580
- #
1581
- class AdminCredentials
1582
- # Security blob for an existing set of credentials
1583
- attr_reader :securityblob
1584
- # Designates if this object contains user defined credentials or a security blob
1585
- attr_reader :isblob
1586
- # The service for these credentials. Can be All.
1587
- attr_reader :service
1588
- # The host for these credentials. Can be Any.
1589
- attr_reader :host
1590
- # The port on which to use these credentials.
1591
- attr_reader :port
1592
- # The user id or username
1593
- attr_reader :userid
1594
- # The password
1595
- attr_reader :password
1596
- # The realm for these credentials
1597
- attr_reader :realm
1598
-
1599
-
1600
- def initialize(isblob = false)
1601
- @isblob = isblob
1602
- end
1603
-
1604
- # Sets the credentials information for this object.
1605
- def setCredentials(service, host, port, userid, password, realm)
1606
- @isblob = false
1607
- @securityblob = nil
1608
- @service = service
1609
- @host = host
1610
- @port = port
1611
- @userid = userid
1612
- @password = password
1613
- @realm = realm
1614
- end
1615
-
1616
- # TODO: add description
1617
- def setService(service)
1618
- @service = service
1619
- end
1620
-
1621
- def setHost(host)
1622
- @host = host
1623
- end
1624
-
1625
- # TODO: add description
1626
- def setBlob(securityblob)
1627
- @isblob = true
1628
- @securityblob = securityblob
1629
- end
1630
-
1631
- include Sanitize
1632
- def to_xml
1633
- xml = ''
1634
- xml << '<adminCredentials'
1635
- xml << %Q{ service="#{replace_entities(service)}"} if (service)
1636
- xml << %Q{ userid="#{replace_entities(userid)}"} if (userid)
1637
- xml << %Q{ password="#{replace_entities(password)}"} if (password)
1638
- xml << %Q{ realm="#{replace_entities(realm)}"} if (realm)
1639
- xml << %Q{ host="#{replace_entities(host)}"} if (host)
1640
- xml << %Q{ port="#{replace_entities(port)}"} if (port)
1641
- xml << '>'
1642
- xml << replace_entities(securityblob) if (isblob)
1643
- xml << '</adminCredentials>'
1644
-
1645
- xml
1646
- end
1647
- end
1648
-
1649
-
1650
- # === Description
1651
- # Object that represents an SMTP (Email) Alert.
1652
- #
1653
- class SmtpAlert
1654
- # A unique name for this alert
1655
- attr_reader :name
1656
- # If this alert is enabled or not
1657
- attr_reader :enabled
1658
- # The email address of the sender
1659
- attr_reader :sender
1660
- # Limit the text for mobile devices
1661
- attr_reader :limitText
1662
- # Array containing Strings of email addresses
1663
- # Array of strings with the email addresses of the intended recipients
1664
- attr_reader :recipients
1665
- # The vulnerability filter to trigger the alert
1666
- attr_reader :vulnFilter
1667
- # The alert type
1668
- attr_reader :type
1669
-
1670
- def initialize(name, sender, limitText, enabled = 1)
1671
- @type = :smtp
1672
- @name = name
1673
- @sender = sender
1674
- @enabled = enabled
1675
- @limitText = limitText
1676
- @recipients = Array.new()
1677
- # Sets default vuln filter - All Events
1678
- setVulnFilter(VulnFilter.new("50790400",1))
1679
- end
1680
-
1681
- # Adds a new Recipient to the recipients array
1682
- def addRecipient(recipient)
1683
- @recipients.push(recipient)
1684
- end
1685
-
1686
- # Sets the Vulnerability Filter for this alert.
1687
- def setVulnFilter(vulnFilter)
1688
- @vulnFilter = vulnFilter
1689
- end
1690
-
1691
- include Sanitize
1692
- def to_xml
1693
- xml = "<smtpAlert"
1694
- xml << %Q{ name="#{replace_entities(name)}"}
1695
- xml << %Q{ enabled="#{replace_entities(enabled)}"}
1696
- xml << %Q{ sender="#{replace_entities(sender)}"}
1697
- xml << %Q{ limitText="#{replace_entities(limitText)}">}
1698
- recipients.each do |recpt|
1699
- xml << "<recipient>#{replace_entities(recpt)}</recipient>"
1700
- end
1701
- xml << vulnFilter.to_xml
1702
- xml << "</smtpAlert>"
1703
- xml
1704
- end
1705
- end
1706
-
1707
- # === Description
1708
- # Object that represents an SNMP Alert.
1709
- #
1710
- class SnmpAlert
1711
-
1712
- # A unique name for this alert
1713
- attr_reader :name
1714
- # If this alert is enabled or not
1715
- attr_reader :enabled
1716
- # The community string
1717
- attr_reader :community
1718
- # The SNMP server to sent this alert
1719
- attr_reader :server
1720
- # The vulnerability filter to trigger the alert
1721
- attr_reader :vulnFilter
1722
- # The alert type
1723
- attr_reader :type
1724
-
1725
- def initialize(name, community, server, enabled = 1)
1726
- @type = :snmp
1727
- @name = name
1728
- @community = community
1729
- @server = server
1730
- @enabled = enabled
1731
- # Sets default vuln filter - All Events
1732
- setVulnFilter(VulnFilter.new("50790400",1))
1733
- end
1734
-
1735
- # Sets the Vulnerability Filter for this alert.
1736
- def setVulnFilter(vulnFilter)
1737
- @vulnFilter = vulnFilter
1738
- end
1739
-
1740
- include Sanitize
1741
- def to_xml
1742
- xml = "<snmpAlert"
1743
- xml << %Q{ name="#{replace_entities(name)}"}
1744
- xml << %Q{ enabled="#{replace_entities(enabled)}"}
1745
- xml << %Q{ community="#{replace_entities(community)}"}
1746
- xml << %Q{ server="#{replace_entities(server)}">}
1747
- xml << vulnFilter.to_xml
1748
- xml << "</snmpAlert>"
1749
- xml
1750
- end
1751
-
1752
- end
1753
-
1754
- # === Description
1755
- # Object that represents a Syslog Alert.
1756
- #
1757
- class SyslogAlert
1758
-
1759
- # A unique name for this alert
1760
- attr_reader :name
1761
- # If this alert is enabled or not
1762
- attr_reader :enabled
1763
- # The Syslog server to sent this alert
1764
- attr_reader :server
1765
- # The vulnerability filter to trigger the alert
1766
- attr_reader :vulnFilter
1767
- # The alert type
1768
- attr_reader :type
1769
-
1770
- def initialize(name, server, enabled = 1)
1771
- @type = :syslog
1772
- @name = name
1773
- @server = server
1774
- @enabled = enabled
1775
- # Sets default vuln filter - All Events
1776
- setVulnFilter(VulnFilter.new("50790400",1))
1777
-
1778
- end
1779
-
1780
- # Sets the Vulnerability Filter for this alert.
1781
- def setVulnFilter(vulnFilter)
1782
- @vulnFilter = vulnFilter
1783
- end
1784
-
1785
- include Sanitize
1786
- def to_xml
1787
- xml = "<syslogAlert"
1788
- xml << %Q{ name="#{replace_entities(name)}"}
1789
- xml << %Q{ enabled="#{replace_entities(enabled)}"}
1790
- xml << %Q{ server="#{replace_entities(server)}">}
1791
- xml << vulnFilter.to_xml
1792
- xml << "</syslogAlert>"
1793
- xml
1794
- end
1795
-
1796
- end
1797
-
1798
- # TODO: review
1799
- # <scanFilter scanStop='0' scanFailed='0' scanStart='1'/>
1800
- # === Description
1801
- #
1802
- class ScanFilter
1803
-
1804
- attr_reader :scanStop
1805
- attr_reader :scanFailed
1806
- attr_reader :scanStart
1807
-
1808
- def initialize(scanstop, scanFailed, scanStart)
1809
-
1810
- @scanStop = scanStop
1811
- @scanFailed = scanFailed
1812
- @scanStart = scanStart
1813
-
1814
- end
1815
-
1816
- end
1817
-
1818
- # TODO: review
1819
- # === Description
1820
- #
1821
- class VulnFilter
1822
-
1823
- attr_reader :typeMask
1824
- attr_reader :maxAlerts
1825
- attr_reader :severityThreshold
1826
-
1827
- def initialize(typeMask, severityThreshold, maxAlerts = -1)
1828
- @typeMask = typeMask
1829
- @maxAlerts = maxAlerts
1830
- @severityThreshold = severityThreshold
1831
- end
1832
-
1833
- include Sanitize
1834
- def to_xml
1835
- xml = "<vulnFilter "
1836
- xml << %Q{ typeMask="#{replace_entities(typeMask)}"}
1837
- xml << %Q{ maxAlerts="#{replace_entities(maxAlerts)}"}
1838
- xml << %Q{ severityThreshold="#{replace_entities(severityThreshold)}"}
1839
- xml << "/>"
1840
-
1841
- xml
1842
- end
1843
-
1844
- end
1845
-
1846
- # TODO add engineID
1847
- # === Description
1848
- # Object that represents the scanning configuration for a Site.
1849
- #
1850
- class ScanConfig
1851
- # A unique ID for this scan configuration
1852
- attr_reader :configID
1853
- # The name of the scan template
1854
- attr_reader :name
1855
- # The ID of the scan template used full-audit, exhaustive-audit, web-audit, dos-audit, internet-audit, network-audit
1856
- attr_reader :templateID
1857
- # The configuration version (default is 2)
1858
- attr_reader :configVersion
1859
- # Array of (Schedule)*
1860
- attr_reader :schedules
1861
- # Array of (ScanTrigger)*
1862
- attr_reader :scanTriggers
1863
-
1864
- def initialize(configID, name, templateID, configVersion = 2)
1865
-
1866
- @configID = configID
1867
- @name = name
1868
- @templateID = templateID
1869
- @configVersion = configVersion
1870
- @schedules = Array.new()
1871
- @scanTriggers = Array.new()
1872
-
1873
- end
1874
-
1875
- # Adds a new Schedule for this ScanConfig
1876
- def addSchedule(schedule)
1877
- @schedules.push(schedule)
1878
- end
1879
-
1880
- # Adds a new ScanTrigger to the scanTriggers array
1881
- def addScanTrigger(scanTrigger)
1882
- @scanTriggers.push(scanTrigger)
1883
- end
1884
-
1885
- def _set_configID(configID)
1886
- @configID = configID
1887
- end
1888
-
1889
- def _set_name(name)
1890
- @name = name
1891
- end
1892
-
1893
- end
1894
-
1895
- # === Description
1896
- # Object that holds a scan schedule
1897
- #
1898
- class Schedule
1899
- # Type of Schedule (daily|hourly|monthly|weekly)
1900
- attr_reader :type
1901
- # The schedule interval
1902
- attr_reader :interval
1903
- # The date and time to start the first scan
1904
- attr_reader :start
1905
- # Enable or disable this schedule
1906
- attr_reader :enabled
1907
- # The date and time to disable to schedule. If null then the schedule will run forever.
1908
- attr_reader :notValidAfter
1909
- # Scan on the same date each time
1910
- attr_reader :byDate
1911
-
1912
- def initialize(type, interval, start, enabled = 1)
1913
-
1914
- @type = type
1915
- @interval = interval
1916
- @start = start
1917
- @enabled = enabled
1918
-
1919
- end
1920
-
1921
-
1922
-
1923
- end
1924
-
1925
- # === Description
1926
- # Object that holds an event that triggers the start of a scan.
1927
- #
1928
- class ScanTrigger
1929
- # Type of Trigger (AutoUpdate)
1930
- attr_reader :type
1931
- # Enable or disable this scan trigger
1932
- attr_reader :enabled
1933
- # Sets the trigger to start an incremental scan or a full scan
1934
- attr_reader :incremental
1935
-
1936
- def initialize(type, incremental, enabled = 1)
1937
-
1938
- @type = type
1939
- @incremental = incremental
1940
- @enabled = enabled
1941
-
1942
- end
1943
-
1944
- end
1945
-
1946
- # === Description
1947
- # Object that represents a single device in an NSC.
1948
- #
1949
- class Device
1950
-
1951
- # A unique device ID (assigned by the NSC)
1952
- attr_reader :id
1953
- # The site ID of this devices site
1954
- attr_reader :site_id
1955
- # IP Address or Hostname of this device
1956
- attr_reader :address
1957
- # User assigned risk multiplier
1958
- attr_reader :riskfactor
1959
- # NeXpose risk score
1960
- attr_reader :riskscore
1961
-
1962
- def initialize(id, site_id, address, riskfactor=1, riskscore=0)
1963
- @id = id
1964
- @site_id = site_id
1965
- @address = address
1966
- @riskfactor = riskfactor
1967
- @riskscore = riskscore
1968
-
1969
- end
1970
-
1971
- end
1972
-
1973
-
1974
- # === Description
1975
- # Object that represents a summary of a scan.
1976
- #
1977
- class ScanSummary
1978
- # The Scan ID of the Scan
1979
- attr_reader :scan_id
1980
- # The Engine ID used to perform the scan
1981
- attr_reader :engine_id
1982
- # TODO: add description
1983
- attr_reader :name
1984
- # The scan start time
1985
- attr_reader :startTime
1986
- # The scan finish time
1987
- attr_reader :endTime
1988
- # The scan status (running|finished|stopped|error| dispatched|paused|aborted|uknown)
1989
- attr_reader :status
1990
- # The number of pending tasks
1991
- attr_reader :tasks_pending
1992
- # The number of active tasks
1993
- attr_reader :tasks_active
1994
- # The number of completed tasks
1995
- attr_reader :tasks_completed
1996
- # The number of "live" nodes
1997
- attr_reader :nodes_live
1998
- # The number of "dead" nodes
1999
- attr_reader :nodes_dead
2000
- # The number of filtered nodes
2001
- attr_reader :nodes_filtered
2002
- # The number of unresolved nodes
2003
- attr_reader :nodes_unresolved
2004
- # The number of "other" nodes
2005
- attr_reader :nodes_other
2006
- # Confirmed vulnerabilities found (indexed by severity)
2007
- # Associative array, indexed by severity
2008
- attr_reader :vuln_exploit
2009
- # Unconfirmed vulnerabilities found (indexed by severity)
2010
- # Associative array, indexed by severity
2011
- attr_reader :vuln_version
2012
- # Not vulnerable checks run (confirmed)
2013
- attr_reader :not_vuln_exploit
2014
- # Not vulnerable checks run (unconfirmed)
2015
- attr_reader :not_vuln_version
2016
- # Vulnerability check errors
2017
- attr_reader :vuln_error
2018
- # Vulnerability checks disabled
2019
- attr_reader :vuln_disabled
2020
- # Vulnerability checks other
2021
- attr_reader :vuln_other
2022
-
2023
- # Constructor
2024
- # ScanSummary(can_id, $engine_id, $name, tartTime, $endTime, tatus)
2025
- def initialize(scan_id, engine_id, name, startTime, endTime, status)
2026
-
2027
- @scan_id = scan_id
2028
- @engine_id = engine_id
2029
- @name = name
2030
- @startTime = startTime
2031
- @endTime = endTime
2032
- @status = status
2033
-
2034
- end
2035
-
2036
- end
2037
-
2038
- # TODO
2039
- # === Description
2040
- # Object that represents the overview statistics for a particular scan.
2041
- #
2042
- # === Examples
2043
- #
2044
- # # Create a new Nexpose Connection on the default port and Login
2045
- # nsc = Connection.new("10.1.40.10","nxadmin","password")
2046
- # nsc.login()
2047
- #
2048
- # # Get a Site (Site ID = 12) from the NSC
2049
- # site = new Site(nsc,12)
2050
- #
2051
- # # Start a Scan of this site and pause for 1 minute
2052
- # scan1 = site.scanSite()
2053
- # sleep(60)
2054
- #
2055
- # # Get the Scan Statistics for this scan
2056
- # scanStatistics = new ScanStatistics(nsc,scan1["scan_id"])
2057
- #
2058
- # # Print out number of confirmed vulnerabilities with a 10 severity
2059
- # puts scanStatistics.scansummary.vuln_exploit[10]
2060
- #
2061
- # # Print out the number of pending tasks left in the scan
2062
- # puts scanStatistics.scan_summary.tasks_pending
2063
- #
2064
- class ScanStatistics
2065
- # true if an error condition exists; false otherwise
2066
- attr_reader :error
2067
- # Error message string
2068
- attr_reader :error_msg
2069
- # The last XML request sent by this object
2070
- attr_reader :request_xml
2071
- # The last XML response received by this object
2072
- attr_reader :reseponse_xml
2073
- # The Scan ID
2074
- attr_reader :scan_id
2075
- # The ScanSummary of the scan
2076
- attr_reader :scan_summary
2077
- # The NSC Connection associated with this object
2078
- attr_reader :connection
2079
-
2080
- # Vulnerability checks other
2081
- attr_reader :vuln_other
2082
- def initialize(connection, scan_id)
2083
- @error = false
2084
- @connection = connection
2085
- @scan_id = scan_id
2086
- end
2087
- end
2088
-
2089
- # ==== Description
2090
- # Object that represents a listing of all of the scan engines available on to an NSC.
2091
- #
2092
- class EngineListing
2093
- # true if an error condition exists; false otherwise
2094
- attr_reader :error
2095
- # Error message string
2096
- attr_reader :error_msg
2097
- # The last XML request sent by this object
2098
- attr_reader :request_xml
2099
- # The last XML response received by this object
2100
- attr_reader :response_xml
2101
- # The NSC Connection associated with this object
2102
- attr_reader :connection
2103
- # Array containing (EngineSummary*)
2104
- attr_reader :engines
2105
- # The number of scan engines
2106
- attr_reader :engine_count
2107
-
2108
- # Constructor
2109
- # EngineListing (connection)
2110
- def initialize(connection)
2111
- @connection = connection
2112
- @engines = []
2113
- @engine_count = 0
2114
- @error = false
2115
- r = @connection.execute('<EngineListingRequest session-id="' + @connection.session_id + '"/>', '1.2')
2116
-
2117
- if (r.success)
2118
- r.res.elements.each('EngineListingResponse/EngineSummary') do |v|
2119
- @engines.push(EngineSummary.new(v.attributes['id'], v.attributes['name'], v.attributes['address'],
2120
- v.attributes['port'], v.attributes['status']))
2121
- end
2122
- else
2123
- @error = true
2124
- @error_msg = 'EngineListingRequest Parse Error'
2125
- end
2126
- @engine_count = @engines.length
2127
- end
2128
- end
2129
-
2130
- # ==== Description
2131
- # Object that represents the summary of a scan engine.
2132
- #
2133
- # ==== Examples
2134
- #
2135
- # # Create a new Nexpose Connection on the default port and Login
2136
- # nsc = Connection.new("10.1.40.10","nxadmin","password")
2137
- # nsc.login()
2138
- #
2139
- # # Get the engine listing for the connection
2140
- # enginelisting = EngineListing.new(nsc)
2141
- #
2142
- # # Print out the status of the first scan engine
2143
- # puts enginelisting.engines[0].status
2144
- #
2145
- class EngineSummary
2146
- # A unique ID that identifies this scan engine
2147
- attr_reader :id
2148
- # The name of this scan engine
2149
- attr_reader :name
2150
- # The hostname or IP address of the engine
2151
- attr_reader :address
2152
- # The port there the engine is listening
2153
- attr_reader :port
2154
- # The engine status (active|pending-auth| incompatible|not-responding|unknown)
2155
- attr_reader :status
2156
-
2157
- # Constructor
2158
- # EngineSummary(id, name, address, port, status)
2159
- def initialize(id, name, address, port, status)
2160
- @id = id
2161
- @name = name
2162
- @address = address
2163
- @port = port
2164
- @status = status
2165
- end
2166
-
2167
- end
2168
-
2169
-
2170
- # TODO
2171
- class EngineActivity
2172
- # true if an error condition exists; false otherwise
2173
- attr_reader :error
2174
- # Error message string
2175
- attr_reader :error_msg
2176
- # The last XML request sent by this object
2177
- attr_reader :request_xml
2178
- # The last XML response received by this object
2179
- attr_reader :response_xml
2180
- # The NSC Connection associated with this object
2181
- attr_reader :connection
2182
- # The Engine ID
2183
- attr_reader :engine_id
2184
- # Array containing (ScanSummary*)
2185
- attr_reader :scan_summaries
2186
-
2187
-
2188
- end
2189
-
2190
- # === Description
2191
- # Object that represents a listing of all of the vulnerabilities in the vulnerability database
2192
- #
2193
- class VulnerabilityListing
2194
-
2195
- # true if an error condition exists; false otherwise
2196
- attr_reader :error
2197
- # Error message string
2198
- attr_reader :error_msg
2199
- # The last XML request sent by this object
2200
- attr_reader :request_xml
2201
- # The last XML response received by this object
2202
- attr_reader :response_xml
2203
- # The NSC Connection associated with this object
2204
- attr_reader :connection
2205
- # Array containing (VulnerabilitySummary*)
2206
- attr_reader :vulnerability_summaries
2207
- # The number of vulnerability definitions
2208
- attr_reader :vulnerability_count
2209
-
2210
- # Constructor
2211
- # VulnerabilityListing(connection)
2212
- def initialize(connection)
2213
- @error = false
2214
- @vulnerability_summaries = []
2215
- @connection = connection
2216
-
2217
- r = @connection.execute('<VulnerabilityListingRequest session-id="' + @connection.session_id + '"/>')
2218
-
2219
- if (r.success)
2220
- r.res.elements.each('VulnerabilityListingResponse/VulnerabilitySummary') do |v|
2221
- @vulnerability_summaries.push(VulnerabilitySummary.new(v.attributes['id'],v.attributes["title"],v.attributes["severity"]))
2222
- end
2223
- else
2224
- @error = true
2225
- @error_msg = 'VulnerabilitySummaryRequest Parse Error'
2226
- end
2227
- @vulnerability_count = @vulnerability_summaries.length
2228
- end
2229
- end
2230
-
2231
- # === Description
2232
- # Object that represents the summary of an entry in the vulnerability database
2233
- #
2234
- class VulnerabilitySummary
2235
-
2236
- # The unique ID string for this vulnerability
2237
- attr_reader :id
2238
- # The title of this vulnerability
2239
- attr_reader :title
2240
- # The severity of this vulnerability (1 – 10)
2241
- attr_reader :severity
2242
-
2243
- # Constructor
2244
- # VulnerabilitySummary(id, title, severity)
2245
- def initialize(id, title, severity)
2246
- @id = id
2247
- @title = title
2248
- @severity = severity
2249
-
2250
- end
2251
-
2252
- end
2253
-
2254
- # === Description
2255
- #
2256
- class Reference
2257
-
2258
- attr_reader :source
2259
- attr_reader :reference
2260
-
2261
- def initialize(source, reference)
2262
- @source = source
2263
- @reference = reference
2264
- end
2265
- end
2266
-
2267
- # === Description
2268
- # Object that represents the details for an entry in the vulnerability database
2269
- #
2270
- class VulnerabilityDetail
2271
- # true if an error condition exists; false otherwise
2272
- attr_reader :error
2273
- # Error message string
2274
- attr_reader :error_msg
2275
- # The last XML request sent by this object
2276
- attr_reader :request_xml
2277
- # The last XML response received by this object
2278
- attr_reader :response_xml
2279
- # The NSC Connection associated with this object
2280
- attr_reader :connection
2281
- # The unique ID string for this vulnerability
2282
- attr_reader :id
2283
- # The title of this vulnerability
2284
- attr_reader :title
2285
- # The severity of this vulnerability (1 – 10)
2286
- attr_reader :severity
2287
- # The pciSeverity of this vulnerability
2288
- attr_reader :pciSeverity
2289
- # The CVSS score of this vulnerability
2290
- attr_reader :cvssScore
2291
- # The CVSS vector of this vulnerability
2292
- attr_reader :cvssVector
2293
- # The date this vulnerability was published
2294
- attr_reader :published
2295
- # The date this vulnerability was added to NeXpose
2296
- attr_reader :added
2297
- # The last date this vulnerability was modified
2298
- attr_reader :modified
2299
- # The HTML Description of this vulnerability
2300
- attr_reader :description
2301
- # External References for this vulnerability
2302
- # Array containing (Reference)
2303
- attr_reader :references
2304
- # The HTML Solution for this vulnerability
2305
- attr_reader :solution
2306
-
2307
- # Constructor
2308
- # VulnerabilityListing(connection,id)
2309
- def initialize(connection, id)
2310
-
2311
- @error = false
2312
- @connection = connection
2313
- @id = id
2314
- @references = []
2315
-
2316
- r = @connection.execute('<VulnerabilityDetailsRequest session-id="' + @connection.session_id + '" vuln-id="' + @id + '"/>')
2317
-
2318
- if (r.success)
2319
- r.res.elements.each('VulnerabilityDetailsResponse/Vulnerability') do |v|
2320
- @id = v.attributes['id']
2321
- @title = v.attributes["title"]
2322
- @severity = v.attributes["severity"]
2323
- @pciSeverity = v.attributes['pciSeverity']
2324
- @cvssScore = v.attributes['cvssScore']
2325
- @cvssVector = v.attributes['cvssVector']
2326
- @published = v.attributes['published']
2327
- @added = v.attributes['added']
2328
- @modified = v.attributes['modified']
2329
-
2330
- v.elements.each('description') do |d|
2331
- @description = d.to_s.gsub(/\<\/?description\>/i, '')
2332
- end
2333
-
2334
- v.elements.each('solution') do |s|
2335
- @solution = s.to_s.gsub(/\<\/?solution\>/i, '')
2336
- end
2337
-
2338
- v.elements.each('references/reference') do |r|
2339
- @references.push(Reference.new(r.attributes['source'],r.text))
2340
- end
2341
- end
2342
- else
2343
- @error = true
2344
- @error_msg = 'VulnerabilitySummaryRequest Parse Error'
2345
- end
2346
-
2347
- end
2348
- end
2349
-
2350
- # === Description
2351
- # Object that represents the summary of a Report Configuration.
2352
- #
2353
- class ReportConfigSummary
2354
- # The Report Configuration ID
2355
- attr_reader :id
2356
- # A unique name for the Report
2357
- attr_reader :name
2358
- # The report format
2359
- attr_reader :format
2360
- # The date of the last report generation
2361
- attr_reader :last_generated_on
2362
- # Relative URI of the last generated report
2363
- attr_reader :last_generated_uri
2364
-
2365
- # Constructor
2366
- # ReportConfigSummary(id, name, format, last_generated_on, last_generated_uri)
2367
- def initialize(id, name, format, last_generated_on, last_generated_uri)
2368
-
2369
- @id = id
2370
- @name = name
2371
- @format = format
2372
- @last_generated_on = last_generated_on
2373
- @last_generated_uri = last_generated_uri
2374
-
2375
- end
2376
-
2377
- end
2378
-
2379
- # === Description
2380
- # Object that represents the schedule on which to automatically generate new reports.
2381
- class ReportHistory
2382
-
2383
- # true if an error condition exists; false otherwise
2384
- attr_reader :error
2385
- # Error message string
2386
- attr_reader :error_msg
2387
- # The last XML request sent by this object
2388
- attr_reader :request_xml
2389
- # The last XML response received by this object
2390
- attr_reader :response_xml
2391
- # The NSC Connection associated with this object
2392
- attr_reader :connection
2393
- # The report definition (report config) ID
2394
- # Report definition ID
2395
- attr_reader :config_id
2396
- # Array (ReportSummary*)
2397
- attr_reader :report_summaries
2398
-
2399
-
2400
- def initialize(connection, config_id)
2401
-
2402
- @error = false
2403
- @connection = connection
2404
- @config_id = config_id
2405
- @report_summaries = []
2406
-
2407
- reportHistory_request = APIRequest.new('<ReportHistoryRequest session-id="' + "#{connection.session_id}" + '" reportcfg-id="' + "#{@config_id}" + '"/>',@connection.geturl())
2408
- reportHistory_request.execute()
2409
- @response_xml = reportHistory_request.response_xml
2410
- @request_xml = reportHistory_request.request_xml
2411
-
2412
- end
2413
-
2414
- def xml_parse(response)
2415
- response = REXML::Document.new(response.to_s)
2416
- status = response.root.attributes['success']
2417
- if (status == '1')
2418
- response.elements.each('ReportHistoryResponse/ReportSummary') do |r|
2419
- @report_summaries.push(ReportSummary.new(r.attributes["id"], r.attributes["cfg-id"], r.attributes["status"], r.attributes["generated-on"],r.attributes['report-uri']))
2420
- end
2421
- else
2422
- @error = true
2423
- @error_msg = 'Error ReportHistoryReponse'
2424
- end
2425
- end
2426
-
2427
- end
2428
-
2429
- # === Description
2430
- # Object that represents the summary of a single report.
2431
- class ReportSummary
2432
-
2433
- # The Report ID
2434
- attr_reader :id
2435
- # The Report Configuration ID
2436
- attr_reader :cfg_id
2437
- # The status of this report
2438
- # available | generating | failed
2439
- attr_reader :status
2440
- # The date on which this report was generated
2441
- attr_reader :generated_on
2442
- # The relative URI of the report
2443
- attr_reader :report_uri
2444
-
2445
- def initialize(id, cfg_id, status, generated_on, report_uri)
2446
-
2447
- @id = id
2448
- @cfg_id = cfg_id
2449
- @status = status
2450
- @generated_on = generated_on
2451
- @report_uri = report_uri
2452
-
2453
- end
2454
-
2455
- end
2456
-
2457
- # === Description
2458
- #
2459
- class ReportAdHoc
2460
- include XMLUtils
2461
-
2462
- attr_reader :error
2463
- attr_reader :error_msg
2464
- attr_reader :connection
2465
- # Report Template ID strong e.g. full-audit
2466
- attr_reader :template_id
2467
- # pdf|html|xml|text|csv|raw-xml
2468
- attr_reader :format
2469
- # Array of (ReportFilter)*
2470
- attr_reader :filters
2471
- attr_reader :request_xml
2472
- attr_reader :response_xml
2473
- attr_reader :report_decoded
2474
-
2475
-
2476
- def initialize(connection, template_id = 'full-audit', format = 'raw-xml')
2477
-
2478
- @error = false
2479
- @connection = connection
2480
- @filters = Array.new()
2481
- @template_id = template_id
2482
- @format = format
2483
-
2484
- end
2485
-
2486
- def addFilter(filter_type, id)
2487
-
2488
- # filter_type can be site|group|device|scan
2489
- # id is the ID number. For scan, you can use 'last' for the most recently run scan
2490
- filter = ReportFilter.new(filter_type, id)
2491
- filters.push(filter)
2492
-
2493
- end
2494
-
2495
- def generate()
2496
- request_xml = '<ReportAdhocGenerateRequest session-id="' + @connection.session_id + '">'
2497
- request_xml += '<AdhocReportConfig template-id="' + @template_id + '" format="' + @format + '">'
2498
- request_xml += '<Filters>'
2499
- @filters.each do |f|
2500
- request_xml += '<filter type="' + f.type + '" id="'+ f.id.to_s + '"/>'
2501
- end
2502
- request_xml += '</Filters>'
2503
- request_xml += '</AdhocReportConfig>'
2504
- request_xml += '</ReportAdhocGenerateRequest>'
2505
-
2506
- ad_hoc_request = APIRequest.new(request_xml, @connection.url)
2507
- ad_hoc_request.execute()
2508
-
2509
- content_type_response = ad_hoc_request.raw_response.header['Content-Type']
2510
- if content_type_response =~ /multipart\/mixed;\s*boundary=([^\s]+)/
2511
- # NeXpose sends an incorrect boundary format which breaks parsing
2512
- # Eg: boundary=XXX; charset=XXX
2513
- # Fix by removing everything from the last semi-colon onward
2514
- last_semi_colon_index = content_type_response.index(/;/, content_type_response.index(/boundary/))
2515
- content_type_response = content_type_response[0, last_semi_colon_index]
2516
-
2517
- data = "Content-Type: " + content_type_response + "\r\n\r\n" + ad_hoc_request.raw_response_data
2518
- doc = Rex::MIME::Message.new data
2519
- doc.parts.each do |part|
2520
- if /.*base64.*/ =~ part.header.to_s
2521
- return parse_xml(part.content.unpack("m*")[0])
2522
- end
2523
- end
2524
- end
2525
- end
2526
-
2527
- end
2528
-
2529
- # === Description
2530
- # Object that represents the configuration of a report definition.
2531
- #
2532
- class ReportConfig
2533
-
2534
- # true if an error condition exists; false otherwise
2535
- attr_reader :error
2536
- # Error message string
2537
- attr_reader :error_msg
2538
- # The last XML request sent by this object
2539
- attr_reader :request_xml
2540
- # The last XML response received by this object
2541
- attr_reader :response_xml
2542
- # The NSC Connection associated with this object
2543
- attr_reader :connection
2544
- # The ID for this report definition
2545
- attr_reader :config_id
2546
- # A unique name for this report definition
2547
- attr_reader :name
2548
- # The template ID used for this report definition
2549
- attr_reader :template_id
2550
- # html, db, txt, xml, raw-xml, csv, pdf
2551
- attr_reader :format
2552
- # XXX new
2553
- attr_reader :timezone
2554
- # XXX new
2555
- attr_reader :owner
2556
- # Array of (ReportFilter)* - The Sites, Asset Groups, or Devices to run the report against
2557
- attr_reader :filters
2558
- # Automatically generate a new report at the conclusion of a scan
2559
- # 1 or 0
2560
- attr_reader :generate_after_scan
2561
- # Schedule to generate reports
2562
- # ReportSchedule Object
2563
- attr_reader :schedule
2564
- # Store the reports on the server
2565
- # 1 or 0
2566
- attr_reader :storeOnServer
2567
- # Location to store the report on the server
2568
- attr_reader :store_location
2569
- # Form to send the report via email
2570
- # "file", "zip", "url", or NULL (don’t send email)
2571
- attr_reader :email_As
2572
- # Send the Email to all Authorized Users
2573
- # boolean - Send the Email to all Authorized Users
2574
- attr_reader :email_to_all
2575
- # Array containing the email addresses of the recipients
2576
- attr_reader :email_recipients
2577
- # IP Address or Hostname of SMTP Relay Server
2578
- attr_reader :smtp_relay_server
2579
- # Sets the FROM field of the Email
2580
- attr_reader :sender
2581
- # TODO
2582
- attr_reader :db_export
2583
- # TODO
2584
- attr_reader :csv_export
2585
- # TODO
2586
- attr_reader :xml_export
2587
-
2588
-
2589
- def initialize(connection, config_id = -1)
2590
-
2591
- @error = false
2592
- @connection = connection
2593
- @config_id = config_id
2594
- @xml_tag_stack = Array.new()
2595
- @filters = Array.new()
2596
- @email_recipients = Array.new()
2597
- @name = "New Report " + rand(999999999).to_s
2598
-
2599
- r = @connection.execute('<ReportConfigRequest session-id="' + @connection.session_id.to_s + '" reportcfg-id="' + @config_id.to_s + '"/>')
2600
- if (r.success)
2601
- r.res.elements.each('ReportConfigResponse/ReportConfig') do |r|
2602
- @name = r.attributes['name']
2603
- @format = r.attributes['format']
2604
- @timezone = r.attributes['timezone']
2605
- @id = r.attributes['id']
2606
- @template_id = r.attributes['template-id']
2607
- @owner = r.attributes['owner']
2608
- end
2609
- else
2610
- @error = true
2611
- @error_msg = 'Error ReportHistoryReponse'
2612
- end
2613
- end
2614
-
2615
- # === Description
2616
- # Generate a new report on this report definition. Returns the new report ID.
2617
- def generateReport(debug = false)
2618
- return generateReport(@connection, @config_id, debug)
2619
- end
2620
-
2621
- # === Description
2622
- # Save the report definition to the NSC.
2623
- # Returns the config-id.
2624
- def saveReport()
2625
- r = @connection.execute('<ReportSaveRequest session-id="' + @connection.session_id.to_s + '">' + getXML().to_s + ' </ReportSaveRequest>')
2626
- if(r.success)
2627
- @config_id = r.attributes['reportcfg-id']
2628
- return true
2629
- end
2630
- return false
2631
- end
2632
-
2633
- # === Description
2634
- # Adds a new filter to the report config
2635
- def addFilter(filter_type, id)
2636
- filter = ReportFilter.new(filter_type,id)
2637
- @filters.push(filter)
2638
- end
2639
-
2640
- # === Description
2641
- # Adds a new email recipient
2642
- def addEmailRecipient(recipient)
2643
- @email_recipients.push(recipient)
2644
- end
2645
-
2646
- # === Description
2647
- # Sets the schedule for this report config
2648
- def setSchedule(schedule)
2649
- @schedule = schedule
2650
- end
2651
-
2652
- def getXML()
2653
-
2654
- xml = '<ReportConfig id="' + @config_id.to_s + '" name="' + @name.to_s + '" template-id="' + @template_id.to_s + '" format="' + @format.to_s + '">'
2655
-
2656
- xml += ' <Filters>'
2657
-
2658
- @filters.each do |f|
2659
- xml += ' <' + f.type.to_s + ' id="' + f.id.to_s + '"/>'
2660
- end
2661
-
2662
- xml += ' </Filters>'
2663
-
2664
- xml += ' <Generate after-scan="' + @generate_after_scan.to_s + '">'
2665
-
2666
- if (@schedule)
2667
- xml += ' <Schedule type="' + @schedule.type.to_s + '" interval="' + @schedule.interval.to_s + '" start="' + @schedule.start.to_s + '"/>'
2668
- end
2669
-
2670
- xml += ' </Generate>'
2671
-
2672
- xml += ' <Delivery>'
2673
-
2674
- xml += ' <Storage storeOnServer="' + @storeOnServer.to_s + '">'
2675
-
2676
- if (@store_location and @store_location.length > 0)
2677
- xml += ' <location>' + @store_location.to_s + '</location>'
2678
- end
2679
-
2680
- xml += ' </Storage>'
2681
-
2682
-
2683
- xml += ' </Delivery>'
2684
-
2685
- xml += ' </ReportConfig>'
2686
-
2687
- return xml
2688
- end
2689
-
2690
- def set_name(name)
2691
- @name = name
2692
- end
2693
-
2694
- def set_template_id(template_id)
2695
- @template_id = template_id
2696
- end
2697
-
2698
- def set_format(format)
2699
- @format = format
2700
- end
2701
-
2702
- def set_email_As(email_As)
2703
- @email_As = email_As
2704
- end
2705
-
2706
- def set_storeOnServer(storeOnServer)
2707
- @storeOnServer = storeOnServer
2708
- end
2709
-
2710
- def set_smtp_relay_server(smtp_relay_server)
2711
- @smtp_relay_server = smtp_relay_server
2712
- end
2713
-
2714
- def set_sender(sender)
2715
- @sender = sender
2716
- end
2717
-
2718
- def set_generate_after_scan(generate_after_scan)
2719
- @generate_after_scan = generate_after_scan
2720
- end
2721
- end
2722
-
2723
- # === Description
2724
- # Object that represents a report filter which determines which sites, asset
2725
- # groups, and/or devices that a report is run against. gtypes are
2726
- # "SiteFilter", "AssetGroupFilter", "DeviceFilter", or "ScanFilter". gid is
2727
- # the site-id, assetgroup-id, or devce-id. ScanFilter, if used, specifies
2728
- # a specifies a specific scan to use as the data source for the report. The gid
2729
- # can be a specific scan-id or "first" for the first run scan, or “last” for
2730
- # the last run scan.
2731
- #
2732
- class ReportFilter
2733
-
2734
- attr_reader :type
2735
- attr_reader :id
2736
-
2737
- def initialize(type, id)
2738
-
2739
- @type = type
2740
- @id = id
2741
-
2742
- end
2743
-
2744
- end
2745
-
2746
- # === Description
2747
- # Object that represents the schedule on which to automatically generate new reports.
2748
- #
2749
- class ReportSchedule
2750
-
2751
- # The type of schedule
2752
- # (daily, hourly, monthly, weekly)
2753
- attr_reader :type
2754
- # The frequency with which to run the scan
2755
- attr_reader :interval
2756
- # The earliest date to generate the report
2757
- attr_reader :start
2758
-
2759
- def initialize(type, interval, start)
2760
-
2761
- @type = type
2762
- @interval = interval
2763
- @start = start
2764
-
2765
- end
2766
-
2767
-
2768
- end
2769
-
2770
- class ReportTemplateListing
2771
-
2772
- attr_reader :error_msg
2773
- attr_reader :error
2774
- attr_reader :request_xml
2775
- attr_reader :response_xml
2776
- attr_reader :connection
2777
- attr_reader :xml_tag_stack
2778
- attr_reader :report_template_summaries#; //Array (ReportTemplateSummary*)
2779
-
2780
-
2781
- def ReportTemplateListing(connection)
2782
-
2783
- @error = nil
2784
- @connection = connection
2785
- @report_template_summaries = Array.new()
2786
-
2787
- r = @connection.execute('<ReportTemplateListingRequest session-id="' + connection.session_id.to_s + '"/>')
2788
- if (r.success)
2789
- r.res.elements.each('ReportTemplateListingResponse/ReportTemplateSummary') do |r|
2790
- @report_template_summaries.push(ReportTemplateSumary.new(r.attributes['id'],r.attributes['name']))
2791
- end
2792
- else
2793
- @error = true
2794
- @error_msg = 'ReportTemplateListingRequest Parse Error'
2795
- end
2796
-
2797
- end
2798
-
2799
- end
2800
-
2801
-
2802
- class ReportTemplateSummary
2803
-
2804
- attr_reader :id
2805
- attr_reader :name
2806
- attr_reader :description
2807
-
2808
- def ReportTemplateSummary(id, name, description)
2809
-
2810
- @id = id
2811
- @name = name
2812
- @description = description
2813
-
2814
- end
2815
-
2816
- end
2817
-
2818
-
2819
- class ReportSection
2820
-
2821
- attr_reader :name
2822
- attr_reader :properties
2823
-
2824
- def ReportSection(name)
2825
-
2826
- @properties = Array.new()
2827
- @name = name
2828
- end
2829
-
2830
-
2831
- def addProperty(name, value)
2832
-
2833
- @properties[name.to_s] = value
2834
- end
2835
-
2836
- end
2837
-
2838
-
2839
- # TODO add
2840
- def self.site_device_scan(connection, site_id, device_array, host_array, debug = false)
2841
-
2842
- request_xml = '<SiteDevicesScanRequest session-id="' + connection.session_id.to_s + '" site-id="' + site_id.to_s + '">'
2843
- request_xml += '<Devices>'
2844
- device_array.each do |d|
2845
- request_xml += '<device id="' + d.to_s + '"/>'
2846
- end
2847
- request_xml += '</Devices>'
2848
- request_xml += '<Hosts>'
2849
- # The host array can only by single IP addresses for now. TODO: Expand to full API Spec.
2850
- host_array.each do |h|
2851
- request_xml += '<range from="' + h.to_s + '"/>'
2852
- end
2853
- request_xml += '</Hosts>'
2854
- request_xml += '</SiteDevicesScanRequest>'
2855
-
2856
- r = connection.execute(request_xml)
2857
- r.success ? {:engine_id => r.attributes['engine_id'], :scan_id => r.attributes['scan-id']} : nil
2858
- end
2859
-
2860
- # === Description
2861
- # TODO
2862
- def self.getAttribute(attribute, xml)
2863
- value = ''
2864
- #@value = substr(substr(strstr(strstr(@xml,@attribute),'"'),1),0,strpos(substr(strstr(strstr(@xml,@attribute),'"'),1),'"'))
2865
- yvalue
2866
- end
2867
-
2868
- # === Description
2869
- # Returns an ISO 8601 formatted date/time stamp. All dates in NeXpose must use this format.
2870
- def self.get_iso_8601_date(int_date)
2871
- #@date_mod = date('Ymd\THis000', @int_date)
2872
- date_mod = ''
2873
- return date_mod
2874
- end
2875
-
2876
- # ==== Description
2877
- # Echos the last XML API request and response for the specified object. (Useful for debugging)
2878
- def self.printXML(object)
2879
- puts "request" + object.request_xml.to_s
2880
- puts "response is " + object.response_xml.to_s
2881
- end
2882
-
2883
-
2884
- def self.testa(ip, port, user, passwd)
2885
- nsc = Connection.new(ip, user, passwd, port)
2886
-
2887
- nsc.login
2888
- site_listing = SiteListing.new(nsc)
2889
-
2890
- site_listing.sites.each do |site|
2891
- puts "name is #{site.site_name}"
2892
- puts "id is #{site.id}"
2893
- end
2894
- end
2895
-
2896
-
2897
- end