Class: Nexpose::Connection

Inherits:
Object
  • Object
show all
Includes:
XMLUtils
Defined in:
lib/nexpose/connection.rb,
lib/nexpose/pool.rb,
lib/nexpose/role.rb,
lib/nexpose/scan.rb,
lib/nexpose/silo.rb,
lib/nexpose/site.rb,
lib/nexpose/user.rb,
lib/nexpose/vuln.rb,
lib/nexpose/group.rb,
lib/nexpose/backup.rb,
lib/nexpose/device.rb,
lib/nexpose/engine.rb,
lib/nexpose/filter.rb,
lib/nexpose/manage.rb,
lib/nexpose/report.rb,
lib/nexpose/ticket.rb,
lib/nexpose/shared_cred.rb,
lib/nexpose/scan_template.rb,
lib/nexpose/vuln_exception.rb,
lib/nexpose/report_template.rb

Overview

Description

Object that represents a connection to a Nexpose Security Console.

Examples

# Create a new Nexpose::Connection on the default port
nsc = Connection.new('10.1.40.10', 'nxadmin', 'password')

# Create a new Nexpose::Connection from a URI or "URI" String
nsc = Connection.from_uri('https://10.1.40.10:3780', 'nxadmin', 'password')

# Login to NSC and Establish a Session ID
nsc.

# Check Session ID
if nsc.session_id
    puts 'Login Successful'
else
    puts 'Login Failure'
end

# Logout
logout_success = nsc.logout

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from XMLUtils

#make_xml, #parse_xml

Constructor Details

#initialize(ip, user, pass, port = 3780, silo_id = nil) ⇒ Connection

A constructor for Connection



54
55
56
57
58
59
60
61
62
# File 'lib/nexpose/connection.rb', line 54

def initialize(ip, user, pass, port = 3780, silo_id = nil)
  @host = ip
  @port = port
  @username = user
  @password = pass
  @silo_id = silo_id
  @session_id = nil
  @url = "https://#{@host}:#{@port}/api/API_VERSION/xml"
end

Instance Attribute Details

#hostObject (readonly)

The hostname or IP Address of the NSC



32
33
34
# File 'lib/nexpose/connection.rb', line 32

def host
  @host
end

#passwordObject (readonly)

The password used to login to the NSC



38
39
40
# File 'lib/nexpose/connection.rb', line 38

def password
  @password
end

#portObject (readonly)

The port of the NSC (default is 3780)



34
35
36
# File 'lib/nexpose/connection.rb', line 34

def port
  @port
end

#request_xmlObject (readonly)

The last XML request sent by this object, useful for debugging.



43
44
45
# File 'lib/nexpose/connection.rb', line 43

def request_xml
  @request_xml
end

#response_xmlObject (readonly)

The last XML response received by this object, useful for debugging.



45
46
47
# File 'lib/nexpose/connection.rb', line 45

def response_xml
  @response_xml
end

#session_idObject (readonly)

Session ID of this connection



30
31
32
# File 'lib/nexpose/connection.rb', line 30

def session_id
  @session_id
end

#urlObject (readonly)

The URL for communication



40
41
42
# File 'lib/nexpose/connection.rb', line 40

def url
  @url
end

#usernameObject (readonly)

The username used to login to the NSC



36
37
38
# File 'lib/nexpose/connection.rb', line 36

def username
  @username
end

Class Method Details

.from_uri(uri, user, pass, silo_id = nil) ⇒ Object

A constructor to load a Connection object from a URI



48
49
50
51
# File 'lib/nexpose/connection.rb', line 48

def self.from_uri(uri, user, pass, silo_id = nil)
  uri = URI.parse(uri)
  new(uri.host, user, pass, uri.port, silo_id)
end

Instance Method Details

#_append_asset!(xml, asset) ⇒ Object

Utility method for appending a HostName or IPRange object into an XML object, in preparation for ad hoc scanning.

Parameters:

  • xml (REXML::Document)

    Prepared API call to execute.

  • asset (HostName|IPRange)

    Asset to append to XML.



112
113
114
115
116
117
118
119
120
# File 'lib/nexpose/scan.rb', line 112

def _append_asset!(xml, asset)
  if asset.kind_of? Nexpose::IPRange
    xml.add_element('range', { 'from' => asset.from, 'to' => asset.to })
  else  # Assume HostName
    host = REXML::Element.new('host')
    host.text = asset.host
    xml.add_element(host)
  end
end

#_maintenance_restartObject



35
36
37
38
39
40
41
# File 'lib/nexpose/backup.rb', line 35

def _maintenance_restart
  parameters = { 'cancelAllTasks' => false,
                 'cmd' => 'restartServer',
                 'targetTask' => 'maintModeHandler' }
  xml = AJAX.form_post(self, '/admin/global/maintenance/maintCmd.txml', parameters)
  !!(xml =~ /succeded="true"/)
end

#_scan_ad_hoc(xml) ⇒ Scan

Utility method for executing prepared XML and extracting Scan launch information.

Parameters:

  • xml (REXML::Document)

    Prepared API call to execute.

Returns:

  • (Scan)

    Scan launch information.



128
129
130
131
# File 'lib/nexpose/scan.rb', line 128

def _scan_ad_hoc(xml)
  r = execute(xml)
  Scan.parse(r.res)
end

#backup(platform_independent = false, description = nil) ⇒ Boolean

Create a backup of this security console’s data. A restart will be initiated in order to put the product into maintenance mode while the backup is made. It will then restart automatically.

Parameters:

  • platform_independent (Boolean) (defaults to: false)

    Whether to make a platform independent backup.

  • description (String) (defaults to: nil)

    A note about this backup which will be visible through the web interface.

Returns:

  • (Boolean)

    Whether a backup is successfully initiated.



24
25
26
27
28
29
30
31
32
33
# File 'lib/nexpose/backup.rb', line 24

def backup(platform_independent = false, description = nil)
  parameters = { 'backup_desc' => description,
                 'cmd' => 'backup',
                 'platform_independent' => platform_independent,
                 'targetTask' => 'backupRestore' }
  xml = AJAX.form_post(self, '/admin/global/maintenance/maintCmd.txml', parameters)
  if !!(xml =~ /succeded="true"/)
    _maintenance_restart
  end
end

#console_command(cmd_string) ⇒ Object

Execute an arbitrary console command that is supplied as text via the supplied parameter. Console commands are documented in the administrator’s guide. If you use a command that is not listed in the administrator’s guide, the application will return the XMLResponse.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/nexpose/manage.rb', line 12

def console_command(cmd_string)
  xml = make_xml('ConsoleCommandRequest', {})
  cmd = REXML::Element.new('Command')
  cmd.text = cmd_string
  xml << cmd

  r = execute(xml)
  if r.success
    r.res.elements.each('//Output') do |out|
      return out.text.to_s
    end
  else
    false
  end
end

#create_multi_tenant_user(user_config, silo_configs) ⇒ Object


Creates a multi-tenant user

user_config - A map of the user data.

REQUIRED PARAMS user-id, authsrcid, user-name, full-name, enabled, superuser

OPTIONAL PARAMS email, password

silo_configs - An array of maps of silo specific data

REQUIRED PARAMS silo-id, role-name, all-groups, all-sites, default-silo

allowed_groups/allowed_sites - An array of ids




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/nexpose/silo.rb', line 32

def create_multi_tenant_user(user_config, silo_configs)
  xml = make_xml('MultiTenantUserCreateRequest')
  mtu_config_xml = make_xml('MultiTenantUserConfig', user_config, '', false)

  # Add the silo access
  silo_xml = make_xml('SiloAccesses', {}, '', false)
  silo_configs.each do |silo_config|
    silo_config_xml = make_xml('SiloAccess', {}, '', false)
    silo_config.keys.each do |k|
      if k == 'allowed_sites'
        allowed_sites_xml = make_xml('AllowedSites', {}, '', false)
        silo_config['allowed_sites'].each do |allowed_site|
          allowed_sites_xml.add_element(make_xml('AllowedSite', {'id' => allowed_site}, '', false))
        end
        silo_config_xml.add_element(allowed_sites_xml)
      elsif k == 'allowed_groups'
        allowed_groups_xml = make_xml('AllowedGroups', {}, '', false)
        silo_config['allowed_groups'].each do |allowed_group|
          allowed_groups_xml.add_element(make_xml('AllowedGroup', {'id' => allowed_group}, '', false))
        end
        silo_config_xml.add_element(allowed_groups_xml)
      else
        silo_config_xml.attributes[k] = silo_config[k]
      end
    end
    silo_xml.add_element(silo_config_xml)
  end
  mtu_config_xml.add_element(silo_xml)
  xml.add_element(mtu_config_xml)
  r = execute(xml, '1.2')
  r.success
end

#create_silo(silo_config) ⇒ Object


Creates a silo

silo_config - A map of the silo creation data.

REQUIRED PARAMS id, name, silo-profile-id, max-assets, max-hosted-assets, max-users

OPTIONAL PARAMS description




239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/nexpose/silo.rb', line 239

def create_silo silo_config
  xml = make_xml 'SiloCreateRequest'
  silo_config_xml = make_xml 'SiloConfig', {}, '', false

  # Add the attributes
  silo_config.keys.each do |key|
    if not 'merchant'.eql? key and not 'organization'.eql? key
      silo_config_xml.attributes[key] = silo_config[key]
    end
  end

  # Add Organization info
  if silo_config['organization']
    org_xml = make_xml 'Organization', {}, '', false
    silo_config['organization'].keys.each do |key|
      if not 'address'.eql? key
        org_xml.attributes[key] = silo_config['organization'][key]
      end
    end

    address_xml = make_xml 'Address', silo_config['organization']['address'], '', false
    org_xml.add_element address_xml
    silo_config_xml.add_element org_xml
  end

  # Add Merchant info
  if silo_config['merchant']
    merchant_xml = make_xml 'Merchant', {}, '', false

    silo_config['merchant'].keys.each do |key|
      if not 'dba'.eql? key and not 'other_industries'.eql? key and not 'qsa'.eql? key and not 'address'.eql? key
        merchant_xml.attributes[key] = silo_config['merchant'][key]
      end
    end

    # Add the merchant address
    merchant_address_xml = make_xml 'Address', silo_config['merchant']['address'], '', false
    merchant_xml.add_element merchant_address_xml

    #Now add the complex data types
    if silo_config['merchant']['dba']
      dba_xml = make_xml 'DBAs', {}, '', false
      silo_config['merchant']['dba'].each do |name|
        dba_xml.add_element make_xml('DBA', {'name' => name}, '', false)
      end
      merchant_xml.add_element dba_xml
    end

    if silo_config['merchant']['other_industries']
      ois_xml = make_xml 'OtherIndustries', {}, '', false
      silo_config['merchant']['other_industries'].each do |name|
        ois_xml.add_element make_xml('Industry', {'name' => name}, '', false)
      end
      merchant_xml.add_element ois_xml
    end

    if silo_config['merchant']['qsa']
      qsa_xml = make_xml 'QSA', {}, '', false
      silo_config['merchant']['qsa'].keys.each do |key|
        if not 'address'.eql? key
          qsa_xml.attributes[key] = silo_config['merchant']['qsa'][key]
        end
      end

      # Add the address for this QSA
      address_xml = make_xml 'Address', silo_config['merchant']['qsa']['address'], '', false

      qsa_xml.add_element address_xml
      merchant_xml.add_element qsa_xml
    end
    silo_config_xml.add_element merchant_xml
  end

  xml.add_element silo_config_xml
  r = execute xml, '1.2'
  r.success
end

#create_silo_profile(silo_profile_config, permissions) ⇒ Object


Creates a silo profile

silo_config - A map of the silo data.

REQUIRED PARAMS id, name, all‐licensed-modules, all‐global-engines, all-global-report-templates, all‐global-scan‐templates

OPTIONAL PARAMS description

permissions - A map of an array of maps of silo specific data

REQUIRED PARAMS silo-id, role-name, all-groups, all-sites, default-silo

allowed_groups/allowed_sites - An array of ids




125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/nexpose/silo.rb', line 125

def create_silo_profile silo_profile_config, permissions
  xml = make_xml 'SiloProfileCreateRequest'
  spc_xml = make_xml('SiloProfileConfig', silo_profile_config, '', false)

  # Add the permissions
  if permissions['global_report_templates']
    grt_xml = make_xml('GlobalReportTemplates', {}, '', false)
    permissions['global_report_templates'].each do |name|
      grt_xml.add_element make_xml('GlobalReportTemplate', {'name' => name}, '', false)
    end
    spc_xml.add_element grt_xml
  end

  if permissions['global_scan_engines']
    gse_xml = make_xml('GlobalScanEngines', {}, '', false)
    permissions['global_scan_engines'].each do |name|
      gse_xml.add_element make_xml('GlobalScanEngine', {'name' => name}, '', false)
    end
    spc_xml.add_element gse_xml
  end

  if permissions['global_scan_templates']
    gst_xml = make_xml('GlobalScanTemplates', {}, '', false)
    permissions['global_scan_templates'].each do |name|
      gst_xml.add_element make_xml('GlobalScanTemplate', {'name' => name}, '', false)
    end
    spc_xml.add_element gst_xml
  end

  if permissions['licensed_modules']
    lm_xml = make_xml('LicensedModules', {}, '', false)
    permissions['licensed_modules'].each do |name|
      lm_xml.add_element make_xml('LicensedModule', {'name' => name}, '', false)
    end
    spc_xml.add_element lm_xml
  end

  if permissions['restricted_report_formats']
    rrf_xml = make_xml('RestrictedReportFormats', {}, '', false)
    permissions['restricted_report_formats'].each do |name|
      rrf_xml.add_element make_xml('RestrictedReportFormat', {'name' => name}, '', false)
    end
    spc_xml.add_element rrf_xml
  end

  if permissions['restricted_report_sections']
    rrs_xml = make_xml('RestrictedReportSections', {}, '', false)
    permissions['restricted_report_sections'].each do |name|
      rrs_xml.add_element make_xml('RestrictedReportSection', {'name' => name}, '', false)
    end
    spc_xml.add_element rrs_xml
  end

  xml.add_element spc_xml
  r = execute xml, '1.2'
  r.success
end

#delete_asset_group(id) ⇒ Boolean

Delete an asset group and all associated data.

Parameters:

  • id (Fixnum)

    Asset group ID to delete.

Returns:

  • (Boolean)

    Whether group deletion succeeded.



12
13
14
15
# File 'lib/nexpose/group.rb', line 12

def delete_asset_group(id)
  r = execute(make_xml('AssetGroupDeleteRequest', {'group-id' => id}))
  r.success
end

#delete_device(device_id) ⇒ Object



83
84
85
86
# File 'lib/nexpose/device.rb', line 83

def delete_device(device_id)
  r = execute(make_xml('DeviceDeleteRequest', { 'device-id' => device_id }))
  r.success
end

#delete_engine(engine_id, scope = 'silo') ⇒ Boolean

Removes a scan engine from the list of available engines.

Parameters:

  • engine_id (Fixnum)

    Unique ID of an existing engine to remove.

  • scope (String) (defaults to: 'silo')

    Whether the engine is global or silo scoped.

Returns:

  • (Boolean)

    true if engine successfully deleted.



12
13
14
15
16
17
# File 'lib/nexpose/engine.rb', line 12

def delete_engine(engine_id, scope = 'silo')
  xml = make_xml('EngineDeleteRequest',
                 {'engine-id' => engine_id, 'scope' => scope})
  response = execute(xml, '1.2')
  response.success
end

#delete_mtu(user_name, user_id) ⇒ Object


Delete a multi-tenant user




96
97
98
99
100
101
# File 'lib/nexpose/silo.rb', line 96

def delete_mtu user_name, user_id
  using_user_name = (user_name and not user_name.empty?)
  xml = make_xml('MultiTenantUserDeleteRequest', (using_user_name ? {'user-name' => user_name} : {'user-id' => user_id}))
  r = execute xml, '1.2'
  r.success
end

#delete_report(report_id) ⇒ Object

Delete a previously generated report.

Parameters:

  • report_id (Fixnum)

    ID of individual report to delete.



65
66
67
68
# File 'lib/nexpose/report.rb', line 65

def delete_report(report_id)
  xml = make_xml('ReportDeleteRequest', { 'report-id' => report_id })
  execute(xml).success
end

#delete_report_config(report_config_id) ⇒ Object

Delete a previously generated report definition. Also deletes any reports generated from that configuration.

Parameters:

  • report_config_id (Fixnum)

    ID of the report configuration to remove.



75
76
77
78
# File 'lib/nexpose/report.rb', line 75

def delete_report_config(report_config_id)
  xml = make_xml('ReportDeleteRequest', { 'reportcfg-id' => report_config_id })
  execute(xml).success
end

#delete_report_template(template_id) ⇒ Object

Deletes an existing, custom report template. Cannot delete built-in templates.

Parameters:

  • template_id (String)

    Unique identifier of the report template to remove.



29
30
31
# File 'lib/nexpose/report_template.rb', line 29

def delete_report_template(template_id)
  AJAX.delete(self, "/data/report/templates/#{template_id}")
end

#delete_scan_template(id) ⇒ Object

Delete a scan template from the console. Cannot be used to delete a built-in template.

Parameters:

  • id (String)

    Unique identifier of an existing scan template.



21
22
23
# File 'lib/nexpose/scan_template.rb', line 21

def delete_scan_template(id)
  AJAX.delete(self, "/data/scan/templates/#{URI.encode(id)}")
end

#delete_shared_credential(id) ⇒ Object Also known as: delete_shared_cred



17
18
19
# File 'lib/nexpose/shared_cred.rb', line 17

def delete_shared_credential(id)
  AJAX.post(self, "/data/credential/shared/delete?credid=#{id}")
end

#delete_silo(name, id) ⇒ Object


Delete a silo




342
343
344
345
346
347
# File 'lib/nexpose/silo.rb', line 342

def delete_silo name, id
  using_name = (name and not name.empty?)
  xml = make_xml('SiloDeleteRequest', (using_name ? {'silo-name' => name} : {'silo-id' => id}))
  r = execute xml, '1.2'
  r.success
end

#delete_silo_profile(name, id) ⇒ Object


Delete a silo profile




217
218
219
220
221
222
# File 'lib/nexpose/silo.rb', line 217

def delete_silo_profile name, id
  using_name = (name and not name.empty?)
  xml = make_xml('SiloProfileDeleteRequest', (using_name ? {'name' => name} : {'silo-profile-id' => id}))
  r = execute xml, '1.2'
  r.success
end

#delete_site(site_id) ⇒ Object

Delete the specified site and all associated scan data.

Returns:

  • Whether or not the delete request succeeded.



31
32
33
34
# File 'lib/nexpose/site.rb', line 31

def delete_site(site_id)
  r = execute(make_xml('SiteDeleteRequest', {'site-id' => site_id}))
  r.success
end

#delete_ticket(ticket) ⇒ Boolean

Deletes a Nexpose ticket.

Parameters:

  • ticket (Fixnum)

    Unique ID of the ticket to delete.

Returns:

  • (Boolean)

    Whether or not the ticket deletion succeeded.



26
27
28
29
# File 'lib/nexpose/ticket.rb', line 26

def delete_ticket(ticket)
  # TODO: Take Ticket object, too, and pull out IDs.
  delete_tickets([ticket])
end

#delete_tickets(tickets) ⇒ Boolean

Deletes a Nexpose ticket.

Parameters:

  • tickets (Array[Fixnum])

    Array of unique IDs of tickets to delete.

Returns:

  • (Boolean)

    Whether or not the ticket deletions succeeded.



36
37
38
39
40
41
42
43
44
# File 'lib/nexpose/ticket.rb', line 36

def delete_tickets(tickets)
  # TODO: Take Ticket objects, too, and pull out IDs.
  xml = make_xml('TicketDeleteRequest')
  tickets.each do |id|
    xml.add_element('Ticket', { 'id' => id })
  end

  (execute xml, '1.2').success
end

#delete_user(user_id) ⇒ Boolean

Delete a user from the Nexpose console.

Parameters:

  • user_id (Fixnum)

    Unique ID for the user to delete.

Returns:

  • (Boolean)

    Whether or not the user deletion succeeded.



36
37
38
39
# File 'lib/nexpose/user.rb', line 36

def delete_user(user_id)
  response = execute(make_xml('UserDeleteRequest', { 'id' => user_id }))
  response.success
end

#delete_vuln_exception(id) ⇒ Boolean

Delete an existing vulnerability exception.

Parameters:

  • id (Fixnum)

    The ID of a vuln exception.

Returns:

  • (Boolean)

    Whether or not deletion was successful.



74
75
76
77
78
# File 'lib/nexpose/vuln_exception.rb', line 74

def delete_vuln_exception(id)
  xml = make_xml('VulnerabilityExceptionDeleteRequest',
                 { 'exception-id' => id })
  execute(xml, '1.2').success
end

#download(url, file_name = nil) ⇒ Object

Download a specific URL, typically a report. Include an optional file_name parameter to write the output to a file.

Note: XML and HTML reports have charts not downloaded by this method.

Would need to do something more sophisticated to grab
all the associated image files.


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/nexpose/connection.rb', line 101

def download(url, file_name = nil)
  return nil if url.nil? or url.empty?
  uri = URI.parse(url)
  http = Net::HTTP.new(@host, @port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE # XXX: security issue
  headers = {'Cookie' => "nexposeCCSessionID=#{@session_id}"}
  resp = http.get(uri.to_s, headers)

  if file_name
    File.open(file_name, 'w') { |file| file.write(resp.body) }
  else
    resp.body
  end
end

#engine_activity(engine_id) ⇒ Array[ScanSummary]

Provide a list of current scan activities for a specific Scan Engine.

Returns:

  • (Array[ScanSummary])

    Array of ScanSummary objects associated with each active scan on the engine.



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/nexpose/engine.rb', line 24

def engine_activity(engine_id)
  xml = make_xml('EngineActivityRequest', {'engine-id' => engine_id})
  r = execute(xml)
  arr = []
  if r.success
    r.res.elements.each('//ScanSummary') do |scan_event|
      arr << ScanSummary.parse(scan_event)
    end
  end
  arr
end

#execute(xml, version = '1.1') ⇒ Object

Execute an API request



87
88
89
90
91
92
93
# File 'lib/nexpose/connection.rb', line 87

def execute(xml, version = '1.1')
  @request_xml = xml.to_s
  @api_version = version
  response = APIRequest.execute(@url, @request_xml, @api_version)
  @response_xml = response.raw_response_data
  response
end

#filter(field, operator, value = '') ⇒ Array[Asset]

Perform an asset filter search that will locate assets matching the provided conditions.

For example, the following call will return assets with Java installed:

nsc.filter(Search::Field::SOFTWARE, Search::Operator::CONTAINS, 'java')

Parameters:

  • field (String)

    Constant from Search::Field

  • operator (String)

    Constant from Search::Operator

  • value (String) (defaults to: '')

    Search term or constant from Search::Value

Returns:

  • (Array[Asset])

    List of matching assets.



16
17
18
19
20
# File 'lib/nexpose/filter.rb', line 16

def filter(field, operator, value = '')
  criterion = Criterion.new(field, operator, value)
  criteria = Criteria.new(criterion)
  search(criteria)
end

#find_device_by_address(address, site_id = nil) ⇒ Device Also known as: find_asset_by_address

Find a Device by its address.

This is a convenience method for finding a single device from a SiteDeviceListing. If no site_id is provided, the first matching device will be returned when a device occurs across multiple sites.

Parameters:

  • address (String)

    Address of the device to find. Usually the IP address.

  • site_id (FixNum) (defaults to: nil)

    Site ID to restrict search to.

Returns:

  • (Device)

    The first matching Device with the provided address, if found.



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/nexpose/device.rb', line 17

def find_device_by_address(address, site_id = nil)
  r = execute(make_xml('SiteDeviceListingRequest', { 'site-id' => site_id }))
  if r.success
    device = REXML::XPath.first(r.res, "SiteDeviceListingResponse/SiteDevices/device[@address='#{address}']")
    return Device.new(device.attributes['id'].to_i,
                      device.attributes['address'],
                      device.parent.attributes['site-id'],
                      device.attributes['riskfactor'].to_f,
                      device.attributes['riskscore'].to_f) if device
  end
  nil
end

#find_vuln_check(search_term, partial_words = true, all_words = true) ⇒ Array[VulnCheck]

Search for Vulnerability Checks.

Parameters:

  • search_term (String)

    Search terms to search for.

  • partial_words (Boolean) (defaults to: true)

    Allow partial word matches.

  • all_words (Boolean) (defaults to: true)

    All words must be present.

Returns:

  • (Array[VulnCheck])

    List of matching Vulnerability Checks.



78
79
80
81
82
83
84
85
86
# File 'lib/nexpose/vuln.rb', line 78

def find_vuln_check(search_term, partial_words = true, all_words = true)
  uri = "/ajax/vulnck_synopsis.txml?phrase=#{URI.encode(search_term)}"
  uri += '&wholeWords=1' unless partial_words
  uri += '&allWords=1' if all_words
  data = DataTable._get_dyn_table(self, uri)
  data.map do |vuln|
    VulnCheck.new(vuln)
  end
end

#find_vulns_by_date(from, to = nil) ⇒ Array[VulnSynopsis]

Find vulnerabilities by date available in Nexpose. This is not the date the original vulnerability was published, but the date the check was made available in Nexpose.

Parameters:

  • from (String)

    Vulnerability publish date in format YYYY-MM-DD.

  • to (String) (defaults to: nil)

    Vulnerability publish date in format YYYY-MM-DD.

Returns:

  • (Array[VulnSynopsis])

    List of vulnerabilities published in Nexpose between the provided dates.



97
98
99
100
101
# File 'lib/nexpose/vuln.rb', line 97

def find_vulns_by_date(from, to = nil)
  uri = "/ajax/vuln_synopsis.txml?addedMin=#{from}"
  uri += "&addedMax=#{to}" if to
  DataTable._get_dyn_table(self, uri).map { |v| VulnSynopsis.new(v) }
end

#generate_report(report_id, wait = false) ⇒ Object

Generate a new report using the specified report definition.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/nexpose/report.rb', line 25

def generate_report(report_id, wait = false)
  xml = make_xml('ReportGenerateRequest', { 'report-id' => report_id })
  response = execute(xml)
  if response.success
    response.res.elements.each('//ReportSummary') do |summary|
      summary = ReportSummary.parse(summary)
      # If not waiting or the report is finished, return now.
      return summary unless wait && summary.status == 'Started'
    end
  end
  so_far = 0
  while wait
    summary = last_report(report_id)
    return summary unless summary.status == 'Started'
    sleep 5
    so_far += 5
    if so_far % 60 == 0
      puts "Still waiting. Current status: #{summary.status}"
    end
  end
  nil
end

#get_user_id(user_name) ⇒ Object

Retrieve the User ID based upon the user’s login name.

Parameters:

  • user_name (String)

    User name to search for.



27
28
29
# File 'lib/nexpose/user.rb', line 27

def get_user_id(user_name)
  users.find { |user| user.name.eql? user_name }
end

#last_report(report_config_id) ⇒ Object

Get details of the last report generated with the specified report id.



56
57
58
59
# File 'lib/nexpose/report.rb', line 56

def last_report(report_config_id)
  history = report_history(report_config_id)
  history.sort { |a, b| b.generated_on <=> a.generated_on }.first
end

#last_scan(site_id) ⇒ ScanSummary

Retrieve the scan summary statistics for the latest completed scan on a site.

Method will not return data on an active scan.

Parameters:

  • site_id (FixNum)

    Site ID to find latest scan for.

Returns:

  • (ScanSummary)

    details of the last completed scan for a site.



61
62
63
# File 'lib/nexpose/site.rb', line 61

def last_scan(site_id)
  site_scan_history(site_id).select { |scan| scan.end_time }.max_by { |scan| scan.end_time }
end

#list_asset_groupsArray[AssetGroupSummary] Also known as: groups, asset_groups

Retrieve an array of all asset groups the user is authorized to view or manage.

Returns:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/nexpose/group.rb', line 22

def list_asset_groups
  r = execute(make_xml('AssetGroupListingRequest'))

  groups = []
  if r.success
    r.res.elements.each('AssetGroupListingResponse/AssetGroupSummary') do |group|
      groups << AssetGroupSummary.new(group.attributes['id'].to_i,
                                   group.attributes['name'],
                                   group.attributes['description'],
                                   group.attributes['riskscore'].to_f)
    end
  end
  groups
end

#list_backupsArray[Backup]

Retrieve a list of all backups currently stored on the Console.

Returns:

  • (Array[Backup])

    List of backups.



9
10
11
12
# File 'lib/nexpose/backup.rb', line 9

def list_backups
  data = DataTable._get_dyn_table(self, '/admin/global/ajax/backup_listing.txml')
  data.map { |b| Backup.parse(b) }
end

#list_device_vulns(dev_id) ⇒ Array[Vulnerability] Also known as: list_asset_vulns, asset_vulns, device_vulns

List the vulnerability findings for a given device ID.

Parameters:

  • dev_id (Fixnum)

    Unique identifier of a device (asset).

Returns:



70
71
72
73
74
75
76
77
# File 'lib/nexpose/device.rb', line 70

def list_device_vulns(dev_id)
  parameters = { 'devid' => dev_id,
                 'table-id' => 'vulnerability-listing' }
  json = DataTable._get_json_table(self,
                                   '/data/vulnerability/asset-vulnerabilities',
                                   parameters)
  json.map { |vuln| VulnFinding.new(vuln) }
end

#list_engine_poolsArray[EnginePoolSummary] Also known as: engine_pools

Retrieve a list of all Scan Engine Pools managed by the Security Console.

Returns:

  • (Array[EnginePoolSummary])

    Array of EnginePoolSummary objects associated with each engine associated with this security console.



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/nexpose/pool.rb', line 11

def list_engine_pools
  response = execute(make_xml('EnginePoolListingRequest'), '1.2')
  arr = []
  if response.success
    response.res.elements.each('EnginePoolListingResponse/EnginePoolSummary') do |pool|
      arr << EnginePoolSummary.new(pool.attributes['id'],
                                   pool.attributes['name'],
                                   pool.attributes['scope'])
    end
  end
  arr
end

#list_enginesArray[EngineSummary] Also known as: engines

Retrieve a list of all Scan Engines managed by the Security Console.

Returns:

  • (Array[EngineSummary])

    Array of EngineSummary objects associated with each engine associated with this security console.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/nexpose/engine.rb', line 41

def list_engines
  response = execute(make_xml('EngineListingRequest'))
  arr = []
  if response.success
    response.res.elements.each('//EngineSummary') do |engine|
      arr << EngineSummary.new(engine.attributes['id'].to_i,
                               engine.attributes['name'],
                               engine.attributes['address'],
                               engine.attributes['port'].to_i,
                               engine.attributes['status'])
    end
  end
  arr
end

#list_mtuObject


Lists all the multi-tenant users and their attributes.




68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/nexpose/silo.rb', line 68

def list_mtu
  xml = make_xml('MultiTenantUserListingRequest')
  r = execute xml, '1.2'

  if r.success
    res = []
    r.res.elements.each("//MultiTenantUserSummary") do |mtu|
      res << {
        :id => mtu.attributes['id'],
        :full_name => mtu.attributes['full-name'],
        :user_name => mtu.attributes['user-name'],
        :email => mtu.attributes['email'],
        :super_user => mtu.attributes['superuser'],
        :enabled => mtu.attributes['enabled'],
        :auth_module => mtu.attributes['auth-module'],
        :silo_count => mtu.attributes['silo-count'],
        :locked => mtu.attributes['locked']
      }
    end
    res
  else
    false
  end
end

#list_report_templatesArray[ReportTemplateSummary] Also known as: report_templates

Provide a list of all report templates the user can access on the Security Console.

Returns:



11
12
13
14
15
16
17
18
19
20
# File 'lib/nexpose/report_template.rb', line 11

def list_report_templates
  r = execute(make_xml('ReportTemplateListingRequest', {}))
  templates = []
  if r.success
    r.res.elements.each('//ReportTemplateSummary') do |template|
      templates << ReportTemplateSummary.parse(template)
    end
  end
  templates
end

#list_reportsArray[ReportConfigSummary] Also known as: reports

Provide a listing of all report definitions the user can access on the Security Console.

Returns:



11
12
13
14
15
16
17
18
19
20
# File 'lib/nexpose/report.rb', line 11

def list_reports
  r = execute(make_xml('ReportListingRequest'))
  reports = []
  if r.success
    r.res.elements.each('//ReportConfigSummary') do |report|
      reports << ReportConfigSummary.parse(report)
    end
  end
  reports
end

#list_scan_templatesArray[String] Also known as: scan_templates

List the scan templates currently configured on the console.

Returns:

  • (Array[String])

    list of scan templates IDs.



9
10
11
12
# File 'lib/nexpose/scan_template.rb', line 9

def list_scan_templates
  templates = JSON.parse(AJAX.get(self, '/data/scan/templates'))
  templates['valueList']
end

#list_shared_credentialsObject Also known as: list_shared_creds, shared_credentials, shared_creds



5
6
7
8
9
10
11
# File 'lib/nexpose/shared_cred.rb', line 5

def list_shared_credentials
  creds = DataTable._get_json_table(self,
                               '/data/credential/shared/listing',
                               { 'sort' => -1,
                                 'table-id' => 'credential-listing' })
  creds.map { |c| SharedCredentialSummary.from_json(c) }
end

#list_silo_profilesObject


Lists all the silo profiles and their attributes.




186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/nexpose/silo.rb', line 186

def list_silo_profiles
  xml = make_xml('SiloProfileListingRequest')
  r = execute xml, '1.2'

  if r.success
    res = []
    r.res.elements.each("//SiloProfileSummary") do |silo_profile|
      res << {
        :id => silo_profile.attributes['id'],
        :name => silo_profile.attributes['name'],
        :description => silo_profile.attributes['description'],
        :global_report_template_count => silo_profile.attributes['global-report-template-count'],
        :global_scan_engine_count => silo_profile.attributes['global-scan-engine-count'],
        :global_scan_template_count => silo_profile.attributes['global-scan-template-count'],
        :licensed_module_count => silo_profile.attributes['licensed-module-count'],
        :restricted_report_section_count => silo_profile.attributes['restricted-report-section-count'],
        :all_licensed_modules => silo_profile.attributes['all-licensed-modules'],
        :all_global_engines => silo_profile.attributes['all-global-engines'],
        :all_global_report_templates => silo_profile.attributes['all-global-report-templates'],
        :all_global_scan_templates => silo_profile.attributes['all-global-scan-templates']
      }
    end
    res
  else
    false
  end
end

#list_silosObject


Lists all the silos and their attributes.




320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/nexpose/silo.rb', line 320

def list_silos
  xml = make_xml('SiloListingRequest')
  r = execute xml, '1.2'

  if r.success
    res = []
    r.res.elements.each("//SiloSummary") do |silo_profile|
      res << {
        :id => silo_profile.attributes['id'],
        :name => silo_profile.attributes['name'],
        :description => silo_profile.attributes['description']
      }
    end
    res
  else
    false
  end
end

#list_site_devices(site_id = nil) ⇒ Array[Device] Also known as: devices, list_devices, assets, list_assets

Retrieve a list of all of the assets in a site.

If no site-id is specified, then return all of the assets for the Nexpose console, grouped by site-id.

Parameters:

  • site_id (FixNum) (defaults to: nil)

    Site ID to request device listing for. Optional.

Returns:

  • (Array[Device])

    Array of devices associated with the site, or all devices on the console if no site is provided.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/nexpose/device.rb', line 41

def list_site_devices(site_id = nil)
  r = execute(make_xml('SiteDeviceListingRequest', { 'site-id' => site_id }))

  devices = []
  if r.success
    r.res.elements.each('SiteDeviceListingResponse/SiteDevices') do |site|
      site_id = site.attributes['site-id'].to_i
      site.elements.each('device') do |device|
        devices << Device.new(device.attributes['id'].to_i,
                              device.attributes['address'],
                              site_id,
                              device.attributes['riskfactor'].to_f,
                              device.attributes['riskscore'].to_f)
      end
    end
  end
  devices
end

#list_sitesArray[SiteSummary] Also known as: sites

Retrieve a list of all sites the user is authorized to view or manage.

Returns:

  • (Array[SiteSummary])

    Array of SiteSummary objects.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/nexpose/site.rb', line 10

def list_sites
  r = execute(make_xml('SiteListingRequest'))
  arr = []
  if r.success
    r.res.elements.each('SiteListingResponse/SiteSummary') do |site|
      arr << SiteSummary.new(site.attributes['id'].to_i,
                             site.attributes['name'],
                             site.attributes['description'],
                             site.attributes['riskfactor'].to_f,
                             site.attributes['riskscore'].to_f)
    end
  end
  arr
end

#list_ticketsObject Also known as: tickets



6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/nexpose/ticket.rb', line 6

def list_tickets
  # TODO: Should take in filters as arguments.
  xml = make_xml('TicketListingRequest')
  r = execute(xml, '1.2')
  tickets = []
  if r.success
    r.res.elements.each('TicketListingResponse/TicketSummary') do |summary|
      tickets << TicketSummary.parse(summary)
    end
  end
  tickets
end

#list_usersArray[UserSummary] Also known as: users

Retrieve a list of all users configured on this console.

Returns:



10
11
12
13
14
15
16
17
18
19
# File 'lib/nexpose/user.rb', line 10

def list_users
  r = execute(make_xml('UserListingRequest'))
  arr = []
  if r.success
    r.res.elements.each('UserListingResponse/UserSummary') do |summary|
      arr << UserSummary.parse(summary)
    end
  end
  arr
end

#list_vuln_categoriesArray[String] Also known as: vuln_categories

Retrieve a list of the different vulnerability check categories.

Returns:

  • (Array[String])

    Array of currently valid check categories.



38
39
40
41
# File 'lib/nexpose/vuln.rb', line 38

def list_vuln_categories
  data = DataTable._get_dyn_table(self, '/data/vulnerability/categories/dyntable.xml?tableID=VulnCategorySynopsis')
  data.map { |c| c['Category'] }
end

#list_vuln_exceptions(status = nil, duration = nil) ⇒ Array[VulnException] Also known as: vuln_exceptions

Retrieve vulnerability exceptions.

Parameters:

  • status (String) (defaults to: nil)

    Filter exceptions by the current status. @see Nexpose::VulnException::Status

  • duration (String) (defaults to: nil)

    A time interval in the format “PnYnMnDTnHnMnS”.

Returns:

  • (Array[VulnException])

    List of matching vulnerability exceptions.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/nexpose/vuln_exception.rb', line 13

def list_vuln_exceptions(status = nil, duration = nil)
  option = {}
  option['status'] = status if status
  option['time-duration'] = duration if duration
  xml = make_xml('VulnerabilityExceptionListingRequest', option)
  response = execute(xml, '1.2')

  xs = []
  if response.success
    response.res.elements.each('//VulnerabilityException') do |ve|
      xs << VulnException.parse(ve)
    end
  end
  xs
end

#list_vuln_typesArray[String] Also known as: vuln_types

Retrieve a list of the different vulnerability check types.

Returns:

  • (Array[String])

    Array of currently valid check types.



49
50
51
52
# File 'lib/nexpose/vuln.rb', line 49

def list_vuln_types
  data = DataTable._get_dyn_table(self, '/ajax/vulnck_cat_synopsis.txml')
  data.map { |c| c['Category'] }
end

#list_vulns(full = false) ⇒ Array[Vulnerability|VulnerabilitySummary] Also known as: vulns

Retrieve summary details of all vulnerabilities.

Parameters:

  • full (Boolean) (defaults to: false)

    Whether or not to gather the full summary. Without the flag, only id, title, and severity are returned. It can take twice a long to retrieve full summary information.

Returns:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/nexpose/vuln.rb', line 13

def list_vulns(full = false)
  xml = make_xml('VulnerabilityListingRequest')
  # TODO: Add a flag to do stream parsing of the XML to improve performance.
  response = execute(xml, '1.2')
  vulns = []
  if response.success
    response.res.elements.each('VulnerabilityListingResponse/VulnerabilitySummary') do |vuln|
      if full
        vulns << VulnerabilitySummary.parse(vuln)
      else
        vulns << Vulnerability.new(vuln.attributes['id'],
                                   vuln.attributes['title'],
                                   vuln.attributes['severity'].to_i)
      end
    end
  end
  vulns
end

#loginObject

Establish a new connection and Session ID



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/nexpose/connection.rb', line 65

def 
  begin
     = {'sync-id' => 0, 'password' => @password, 'user-id' => @username}
    ['silo-id'] = @silo_id if @silo_id
    r = execute(make_xml('LoginRequest', ))
    if r.success
      @session_id = r.sid
      true
    end
  rescue APIError
    raise AuthenticationFailed.new(r)
  end
end

#logoutObject

Logout of the current connection

Raises:



80
81
82
83
84
# File 'lib/nexpose/connection.rb', line 80

def logout
  r = execute(make_xml('LogoutRequest', {'sync-id' => 0}))
  return true if r.success
  raise APIError.new(r, 'Logout failed')
end

#pause_scan(scan_id) ⇒ Object

Pauses a scan.

Parameters:

  • scan_id (Fixnum)

    The scan ID.



176
177
178
179
# File 'lib/nexpose/scan.rb', line 176

def pause_scan(scan_id)
  r = execute(make_xml('ScanPauseRequest', { 'scan-id' => scan_id }))
  r.success ? r.attributes['success'] : nil
end

#recall_vuln_exception(id) ⇒ Boolean

Recall a vulnerability exception. Recall is used by a submitter to undo an exception request that has not been approved yet.

You can only recall a vulnerability exception that has ‘Under Review’ status.

Parameters:

  • id (Fixnum)

    Unique identifier of the exception to resubmit.

Returns:

  • (Boolean)

    Whether or not the recall was accepted by the console.



63
64
65
66
67
# File 'lib/nexpose/vuln_exception.rb', line 63

def recall_vuln_exception(id)
  xml = make_xml('VulnerabilityExceptionRecallRequest',
                 { 'exception-id' => id })
  execute(xml, '1.2').success
end

#report_history(report_config_id) ⇒ Object

Provide a history of all reports generated with the specified report definition.



50
51
52
53
# File 'lib/nexpose/report.rb', line 50

def report_history(report_config_id)
  xml = make_xml('ReportHistoryRequest', { 'reportcfg-id' => report_config_id })
  ReportSummary.parse_all(execute(xml))
end

#restartObject

Restart the application.

There is no response to a RestartRequest. When the application shuts down as part of the restart process, it terminates any active connections. Therefore, the application cannot issue a response when it restarts.



60
61
62
# File 'lib/nexpose/manage.rb', line 60

def restart
  execute(make_xml('RestartRequest', {})).success
end

#resubmit_vuln_exception(id, comment, reason = nil) ⇒ Boolean

Resubmit a vulnerability exception request with a new comment and reason after an exception has been rejected.

You can only resubmit a request that has a “Rejected” status; if an exception is “Approved” or “Under Review” you will receive an error message stating that the exception request cannot be resubmitted.

Parameters:

  • id (Fixnum)

    Unique identifier of the exception to resubmit.

  • comment (String)

    Comment to justify the exception resubmission.

  • reason (String) (defaults to: nil)

    The reason for the exception status, if changing. @see Nexpose::VulnException::Reason

Returns:

  • (Boolean)

    Whether or not the resubmission was valid.



44
45
46
47
48
49
50
51
52
# File 'lib/nexpose/vuln_exception.rb', line 44

def resubmit_vuln_exception(id, comment, reason = nil)
  options = { 'exception-id' => id }
  options['reason'] = reason if reason
  xml = make_xml('VulnerabilityExceptionResubmitRequest', options)
  comment_xml = make_xml('comment', {}, comment, false)
  xml.add_element(comment_xml)
  r = execute(xml, '1.2')
  r.success
end

#resume_scan(scan_id) ⇒ Object

Resumes a scan.

Parameters:

  • scan_id (Fixnum)

    The scan ID.



167
168
169
170
# File 'lib/nexpose/scan.rb', line 167

def resume_scan(scan_id)
  r = execute(make_xml('ScanResumeRequest', { 'scan-id' => scan_id }))
  r.success ? r.attributes['success'] : nil
end

#role_delete(role, scope = Scope::SILO) ⇒ Object Also known as: delete_role



66
67
68
69
70
71
72
# File 'lib/nexpose/role.rb', line 66

def role_delete(role, scope = Scope::SILO)
  xml = %Q(<RoleDeleteRequest session-id="#{@session_id}">)
  xml << %Q(<Role name="#{role}" scope="#{scope}"/>)
  xml << '</RoleDeleteRequest>' 
  response = execute(xml, '1.2')
  response.success
end

#role_listingObject Also known as: roles

Returns a summary list of all roles.



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/nexpose/role.rb', line 52

def role_listing
  xml = make_xml('RoleListingRequest')
  r = execute(xml, '1.2')
  roles = []
  if r.success
    r.res.elements.each('RoleListingResponse/RoleSummary') do |summary|
      roles << RoleSummary::parse(summary)
    end
  end
  roles
end

#scan_activityArray[ScanSummary]

Retrieve a list of current scan activities across all Scan Engines managed by Nexpose.

Returns:

  • (Array[ScanSummary])

    Array of ScanSummary objects associated with each active scan on the engines.



187
188
189
190
191
192
193
194
195
196
# File 'lib/nexpose/scan.rb', line 187

def scan_activity
  r = execute(make_xml('ScanActivityRequest'))
  res = []
  if r.success
    r.res.elements.each('//ScanSummary') do |scan|
      res << ScanSummary.parse(scan)
    end
  end
  res
end

#scan_asset(site_id, asset) ⇒ Scan

Perform an ad hoc scan of a single asset of a site.

Parameters:

  • site_id (Fixnum)

    Site ID that the assets belong to.

  • asset (HostName|IPRange)

    Asset to scan.

Returns:

  • (Scan)

    Scan launch information.



45
46
47
# File 'lib/nexpose/scan.rb', line 45

def scan_asset(site_id, asset)
  scan_assets(site_id, [asset])
end

#scan_assets(site_id, assets) ⇒ Scan

Perform an ad hoc scan of a subset of assets for a site. Only assets from a single site should be submitted per request. Method is designed to take objects filtered from Site#assets.

For example:

site = Site.load(nsc, 5)
nsc.scan_assets(5, site.assets.take(10))

Parameters:

  • site_id (Fixnum)

    Site ID that the assets belong to.

  • assets (Array[HostName|IPRange])

    List of assets to scan.

Returns:

  • (Scan)

    Scan launch information.



61
62
63
64
65
66
67
68
# File 'lib/nexpose/scan.rb', line 61

def scan_assets(site_id, assets)
  xml = make_xml('SiteDevicesScanRequest', { 'site-id' => site_id })
  hosts = REXML::Element.new('Hosts')
  assets.each { |asset| _append_asset!(hosts, asset) }
  xml.add_element(hosts)

  _scan_ad_hoc(xml)
end

#scan_device(device) ⇒ Scan

Perform an ad hoc scan of a single device.

Parameters:

  • device (Device)

    Device to scan.

Returns:

  • (Scan)

    Scan launch information.



11
12
13
# File 'lib/nexpose/scan.rb', line 11

def scan_device(device)
  scan_devices([device])
end

#scan_devices(devices) ⇒ Scan

Perform an ad hoc scan of a subset of devices for a site. Nexpose only allows devices from a single site to be submitted per request. Method is designed to take objects from a Device listing.

For example:

devices = nsc.devices(5)
nsc.scan_devices(devices.take(10))

Parameters:

  • devices (Array[Device])

    List of devices to scan.

Returns:

  • (Scan)

    Scan launch information.



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/nexpose/scan.rb', line 27

def scan_devices(devices)
  site_id = devices.map { |d| d.site_id }.uniq.first
  xml = make_xml('SiteDevicesScanRequest', { 'site-id' => site_id })
  elem = REXML::Element.new('Devices')
  devices.each do |device|
    elem.add_element('device', { 'id' => "#{device.id}" })
  end
  xml.add_element(elem)

  _scan_ad_hoc(xml)
end

#scan_ips(site_id, ip_addresses) ⇒ Scan

Perform an ad hoc scan of a subset of IP addresses for a site. Only IPs from a single site can be submitted per request, and IP addresses must already be included in the site configuration. Method is designed for scanning when the targets are coming from an external source that does not have access to internal identfiers.

For example:

to_scan = ['192.168.2.1', '192.168.2.107']
nsc.scan_ips(5, to_scan)

Parameters:

  • site_id (Fixnum)

    Site ID that the assets belong to.

  • ip_addresses (Array[String])

    Array of IP addresses to scan.

Returns:

  • (Scan)

    Scan launch information.



84
85
86
87
88
89
90
91
92
93
# File 'lib/nexpose/scan.rb', line 84

def scan_ips(site_id, ip_addresses)
  xml = make_xml('SiteDevicesScanRequest', { 'site-id' => site_id })
  hosts = REXML::Element.new('Hosts')
  ip_addresses.each do |ip|
    xml.add_element('range', { 'from' => ip })
  end
  xml.add_element(hosts)

  _scan_ad_hoc(xml)
end

#scan_site(site_id) ⇒ Scan

Initiate a site scan.

Parameters:

  • site_id (Fixnum)

    Site ID to scan.

Returns:

  • (Scan)

    Scan launch information.



100
101
102
103
104
# File 'lib/nexpose/scan.rb', line 100

def scan_site(site_id)
  xml = make_xml('SiteScanRequest', { 'site-id' => site_id })
  response = execute(xml)
  Scan.parse(response.res) if response.success
end

#scan_statistics(scan_id) ⇒ ScanSummary

Get scan statistics, including node and vulnerability breakdowns.

Parameters:

  • scan_id (Fixnum)

    Scan ID to retrieve statistics for.

Returns:

  • (ScanSummary)

    ScanSummary object providing statistics for the scan.



203
204
205
206
207
208
209
210
# File 'lib/nexpose/scan.rb', line 203

def scan_statistics(scan_id)
  r = execute(make_xml('ScanStatisticsRequest', { 'scan-id' => scan_id }))
  if r.success
    ScanSummary.parse(r.res.elements['//ScanSummary'])
  else
    false
  end
end

#scan_status(scan_id) ⇒ String

Retrieve the status of a scan.

Parameters:

  • scan_id (Fixnum)

    The scan ID.

Returns:

  • (String)

    Current status of the scan. See Nexpose::Scan::Status.



158
159
160
161
# File 'lib/nexpose/scan.rb', line 158

def scan_status(scan_id)
  r = execute(make_xml('ScanStatusRequest', { 'scan-id' => scan_id }))
  r.success ? r.attributes['status'] : nil
end

#search(criteria) ⇒ Array[Asset]

Perform a search that will match the criteria provided.

For example, the following call will return assets with Java and .NET:

java_criterion = Criterion.new(Search::Field::SOFTWARE,
                               Search::Operator::CONTAINS,
                               'java')
dot_net_criterion = Criterion.new(Search::Field::SOFTWARE,
                                  Search::Operator::CONTAINS,
                                  '.net')
criteria = Criteria.new([java_criterion, dot_net_criterion])
results = nsc.search(criteria)

Parameters:

  • criteria (Criteria)

    Criteria search object.

Returns:

  • (Array[Asset])

    List of matching assets.



37
38
39
40
41
42
# File 'lib/nexpose/filter.rb', line 37

def search(criteria)
  results = DataTable._get_json_table(self,
                                      '/data/asset/filterAssets',
                                      criteria._to_payload)
  results.map { |a| Asset.new(a) }
end

#send_log(uri = 'https://support.rapid7.com') ⇒ Object

Output diagnostic information into log files, zip the files, and encrypt the archive with a PGP public key that is provided as a parameter for the API call. Then upload the archive using HTTPS to a URL that is specified as an API parameter.

Parameters:

  • url

    Upload server to send the support log package to.



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/nexpose/manage.rb', line 71

def send_log(uri = 'https://support.rapid7.com')
  url = REXML::Element.new('URL')
  url.text = uri
  tpt = REXML::Element.new('Transport')
  tpt.add_attribute('protocol', 'https')
  tpt << url
  xml = make_xml('SendLogRequest')
  xml << tpt

  execute(xml).success
end

#site_scan_history(site_id) ⇒ Array[ScanSummary]

Retrieve a list of all previous scans of the site.

Parameters:

  • site_id (FixNum)

    Site ID to request scan history for.

Returns:

  • (Array[ScanSummary])

    Array of ScanSummary objects representing each scan run to date on the site provided.



42
43
44
45
46
47
48
49
50
51
# File 'lib/nexpose/site.rb', line 42

def site_scan_history(site_id)
  r = execute(make_xml('SiteScanHistoryRequest', {'site-id' => site_id}))
  scans = []
  if r.success
    r.res.elements.each('SiteScanHistoryResponse/ScanSummary') do |scan_event|
      scans << ScanSummary.parse(scan_event)
    end
  end
  scans
end

#start_updateObject

Induce the application to retrieve required updates and restart if necessary.



49
50
51
# File 'lib/nexpose/manage.rb', line 49

def start_update
  execute(make_xml('StartUpdateRequest', {})).success
end

#stop_scan(scan_id, wait_sec = 0) ⇒ Object

Stop a running or paused scan.

Parameters:

  • scan_id (Fixnum)

    ID of the scan to stop.

  • wait_sec (Fixnum) (defaults to: 0)

    Number of seconds to wait for status to be updated.



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/nexpose/scan.rb', line 139

def stop_scan(scan_id, wait_sec = 0)
  r = execute(make_xml('ScanStopRequest', { 'scan-id' => scan_id }))
  if r.success
    so_far = 0
    while so_far < wait_sec
      status = scan_status(scan_id)
      return status if status == 'stopped'
      sleep 5
      so_far += 5
    end
  end
  r.success
end

#system_informationObject

Obtain system data, such as total RAM, free RAM, total disk space, free disk space, CPU speed, number of CPU cores, and other vital information.



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/nexpose/manage.rb', line 32

def system_information
  r = execute(make_xml('SystemInformationRequest', {}))

  if r.success
    res = {}
    r.res.elements.each('//Statistic') do |stat|
      res[stat.attributes['name'].to_s] = stat.text.to_s
    end
    res
  else
    false
  end
end

#vuln_details(vuln_id) ⇒ VulnerabilityDetail

Retrieve details for a vulnerability.

Parameters:

  • vuln_id (String)

    Nexpose vulnerability ID, such as ‘windows-duqu-cve-2011-3402’.

Returns:



61
62
63
64
65
66
67
68
69
# File 'lib/nexpose/vuln.rb', line 61

def vuln_details(vuln_id)
  xml = make_xml('VulnerabilityDetailsRequest', { 'vuln-id' => vuln_id })
  response = execute(xml, '1.2')
  if response.success
    response.res.elements.each('VulnerabilityDetailsResponse/Vulnerability') do |vuln|
      return VulnerabilityDetail.parse(vuln)
    end
  end
end