nexpose 0.8.9 → 0.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6698a2821faefa7c1822f324cc1bfd355869ad7f
4
- data.tar.gz: 3a14efb354cbc7036cf829f60088ceeaa0f7a80b
3
+ metadata.gz: 81928c1e3298ba80b864e0d14499f58a9a41eae2
4
+ data.tar.gz: dcbe6c5b9df95b254fa98f3eb5ec2041492d389a
5
5
  SHA512:
6
- metadata.gz: 219848942e56f658d1a3f43e8411ded2c12e693d5f258106196ddca5121c3434be50c17dffd45fe61504d5d76050bd77c123ea3d844e5f07a65656a353b03ea2
7
- data.tar.gz: 89ae18299c87ef71a2805038ef3f1e3c7ab7a53cf87e0c66f799dbaa83e024f7714dc4198854d509156646472aea80d344f215c2de7b4fcfa6d71535ca87ef97
6
+ metadata.gz: aa9189178c6c2d497635cc871473f78277abe75374bcf32ac883303463b079b73bc5bdacdac0d8292fcfbd0d326f1d6754235fe2b3ab8d19dcbb260c651cb09e
7
+ data.tar.gz: 7fc4dc7d5a376c7a6e1a0f440e48b532cb73acb1c4470973528fb228be3d8ccbfb60d1d6acd55ce9c1ee00d3aed91dea79b691b484cfddd3bd0374bef0a5690e
data/lib/nexpose/ajax.rb CHANGED
@@ -119,6 +119,15 @@ module Nexpose
119
119
  uri
120
120
  end
121
121
 
122
+ def preserving_preference(nsc, pref)
123
+ begin
124
+ orig = _get_rows(nsc, pref)
125
+ yield
126
+ ensure
127
+ _set_rows(nsc, pref, orig)
128
+ end
129
+ end
130
+
122
131
  ###
123
132
  # Internal helper methods
124
133
 
@@ -154,5 +163,27 @@ module Nexpose
154
163
  raise Nexpose::APIError.new(response, "#{req_type} request to #{request.path} failed. #{request.body}")
155
164
  end
156
165
  end
166
+
167
+ def _get_rows(nsc, pref)
168
+ uri = '/ajax/user_pref_get.txml'
169
+ resp = get(nsc, uri, CONTENT_TYPE::XML, 'name' => "#{pref}.rows")
170
+ xml = REXML::Document.new(resp)
171
+ if val = REXML::XPath.first(xml, 'GetUserPref/userPref')
172
+ val.text.to_i
173
+ else
174
+ 10
175
+ end
176
+ end
177
+
178
+ def _set_rows(nsc, pref, value)
179
+ uri = '/ajax/user_pref_set.txml'
180
+ params = { 'name' => "#{pref}.rows",
181
+ 'value' => value }
182
+ resp = get(nsc, uri, CONTENT_TYPE::XML, params)
183
+ xml = REXML::Document.new(resp)
184
+ if attr = REXML::XPath.first(xml, 'SetUserPref/@success')
185
+ attr.value == '1'
186
+ end
187
+ end
157
188
  end
158
189
  end
@@ -93,6 +93,22 @@ module Nexpose
93
93
  alias_method :asset_vulns, :list_device_vulns
94
94
  alias_method :device_vulns, :list_device_vulns
95
95
 
96
+ # Retrieve a list of assets which completed in a given scan. If called
97
+ # during a scan, this method returns currently completed assets. A
98
+ # "completed" asset can be in one of three states: completed successfully,
99
+ # failed due to an error, or stopped by a user.
100
+ #
101
+ # @param [Fixnum] scan_id Unique identifier of a scan.
102
+ # @return [Array[CompletedAsset]] List of completed assets.
103
+ #
104
+ def completed_assets(scan_id)
105
+ uri = "/data/asset/scan/#{scan_id}/complete-assets"
106
+ AJAX.preserving_preference(self, 'scan-complete-assets') do
107
+ data = DataTable._get_json_table(self, uri, {}, 500, nil, false)
108
+ data.map(&CompletedAsset.method(:parse_json))
109
+ end
110
+ end
111
+
96
112
  def delete_device(device_id)
97
113
  r = execute(make_xml('DeviceDeleteRequest', { 'device-id' => device_id }))
98
114
  r.success
@@ -104,7 +120,6 @@ module Nexpose
104
120
  # Object that represents a single device in a Nexpose security console.
105
121
  #
106
122
  class Device
107
-
108
123
  # A unique device ID (assigned automatically by the Nexpose console).
109
124
  attr_reader :id
110
125
  # IP Address or Hostname of this device.
@@ -124,4 +139,53 @@ module Nexpose
124
139
  @risk_score = risk_score.to_f
125
140
  end
126
141
  end
142
+
143
+ # Summary object of a completed asset for a scan.
144
+ #
145
+ class CompletedAsset
146
+ # Unique identifier of an asset.
147
+ attr_reader :id
148
+ # IP address of the asset.
149
+ attr_reader :ip
150
+ # Host name of the asset, if discovered.
151
+ attr_reader :host_name
152
+ # Operating system fingerprint of the asset.
153
+ attr_reader :os
154
+ # Number of vulnerabilities discovered on the asset.
155
+ attr_reader :vulns
156
+ # Status of the asset on scan completion.
157
+ # One of :completed, :error, or :stopped.
158
+ attr_reader :status
159
+ # Time it took to scan the asset, in milliseconds.
160
+ attr_reader :duration
161
+
162
+ # Internal constructor to be called by #parse_json.
163
+ def initialize(&block)
164
+ instance_eval(&block) if block_given?
165
+ end
166
+
167
+ # Convenience method for assessing "ip" as "ip_address".
168
+ def ip_address
169
+ ip
170
+ end
171
+
172
+ # Convenience method for assessing "os" as "operating_system".
173
+ def operating_system
174
+ os
175
+ end
176
+
177
+ # Internal method for converting a JSON representation into a CompletedScan
178
+ # object.
179
+ def self.parse_json(json)
180
+ new do
181
+ @id = json['id'].to_i
182
+ @ip = json['ipAddress']
183
+ @host_name = json['hostName']
184
+ @os = json['operatingSystem']
185
+ @vulns = json['vulnerabilityCount']
186
+ @status = json['scanStatusTranslation'].downcase.to_sym
187
+ @duration = json['duration']
188
+ end
189
+ end
190
+ end
127
191
  end
@@ -33,6 +33,14 @@ module Nexpose
33
33
  module Protocol
34
34
  HTTP = 'HTTP'
35
35
  HTTPS = 'HTTPS'
36
+ LDAP = 'LDAP'
37
+ LDAPS = 'LDAPS'
38
+ end
39
+
40
+ module Type
41
+ VSPHERE = 'VSPHERE'
42
+ AWS = 'AWS'
43
+ ACTIVESYNC = 'ACTIVESYNC'
36
44
  end
37
45
 
38
46
  # A unique identifier for this connection.
@@ -41,6 +49,9 @@ module Nexpose
41
49
  # A unique name for this connection.
42
50
  attr_accessor :name
43
51
 
52
+ # Type of discovery connection
53
+ attr_accessor :type
54
+
44
55
  # The IP address or fully qualified domain name of the server.
45
56
  attr_accessor :address
46
57
 
@@ -70,6 +81,7 @@ module Nexpose
70
81
  #
71
82
  def initialize(name, address, user, password = nil)
72
83
  @name, @address, @user, @password = name, address, user, password
84
+ @type = nil # for backwards compatibilitly, at some point should set this to Type::VSPHERE
73
85
  @id = -1
74
86
  @port = 443
75
87
  @protocol = Protocol::HTTPS
@@ -131,12 +143,13 @@ module Nexpose
131
143
 
132
144
  def as_xml
133
145
  xml = REXML::Element.new('DiscoveryConnection')
134
- xml.add_attributes({ 'name' => @name,
135
- 'address' => @address,
136
- 'port' => @port,
137
- 'protocol' => @protocol,
138
- 'user-name' => @user,
139
- 'password' => @password })
146
+ xml.attributes['name'] = @name
147
+ xml.attributes['address'] = @address
148
+ xml.attributes['port'] = @port
149
+ xml.attributes['protocol'] = @protocol
150
+ xml.attributes['user-name'] = @user
151
+ xml.attributes['password'] = @password
152
+ xml.attributes['type'] = @type if @type
140
153
  xml
141
154
  end
142
155
 
@@ -188,4 +201,23 @@ module Nexpose
188
201
  end
189
202
  end
190
203
  end
204
+
205
+ class MobileDiscoveryConnection < DiscoveryConnection
206
+ # Create a new Mobile discovery connection.
207
+ #
208
+ # @param [String] name Name to assign to this connection.
209
+ # @param [DiscoveryConnection::Protocol] protocol The protocol to use for discovery - LDAPS or LDAP
210
+ # @param [String] address IP or fully qualified domain name of the
211
+ # connection server.
212
+ # @param [String] user User name for credentials on this connection.
213
+ # @param [String] password Password for credentials on this connection.
214
+ #
215
+ def initialize(name, protocol, address, user, password = nil)
216
+ @name, @protocol, @address, @user, @password = name, protocol, address, user, password
217
+ @type = Type::ACTIVESYNC
218
+ @id = -1
219
+ @port = 443 #port not used for mobile connection
220
+ end
221
+
222
+ end
191
223
  end
@@ -2,6 +2,7 @@ module Nexpose
2
2
  module Search
3
3
  module Field
4
4
 
5
+ ###### vSphere Filters ######
5
6
  # Valid Operators: IS, IS_NOT, CONTAINS, NOT_CONTAINS, STARTS_WITH
6
7
  CLUSTER = 'CLUSTER'
7
8
 
@@ -23,6 +24,14 @@ module Nexpose
23
24
 
24
25
  # Valid Operators: IS, IS_NOT, CONTAINS, NOT_CONTAINS, STARTS_WITH
25
26
  VIRTUAL_MACHINE_NAME = 'VM'
27
+
28
+ ###### Mobile Filters ######
29
+ # Valid Operators: CONTAINS, NOT_CONTAINS
30
+ OPERATING_SYSTEM = 'DEVICE_OPERATING_SYSTEM'
31
+
32
+ # Valid Operators: IS, IS_NOT, CONTAINS, NOT_CONTAINS, STARTS_WITH
33
+ USER = 'DEVICE_USER_DISPLAY_NAME'
34
+
26
35
  end
27
36
 
28
37
  module Value
data/lib/nexpose/scan.rb CHANGED
@@ -520,7 +520,6 @@ module Nexpose
520
520
  # and vuln-potential.
521
521
  #
522
522
  class Status
523
-
524
523
  attr_reader :severities, :count
525
524
 
526
525
  def initialize(severity = nil, count = 0)
@@ -547,7 +546,6 @@ module Nexpose
547
546
  # Struct class for tracking scan launch information.
548
547
  #
549
548
  class Scan
550
-
551
549
  # The scan ID when a scan is successfully launched.
552
550
  attr_reader :id
553
551
  # The engine the scan was dispatched to.
@@ -578,4 +576,48 @@ module Nexpose
578
576
  UNKNOWN = 'unknown'
579
577
  end
580
578
  end
579
+
580
+ # Summary object of a completed scan for a site.
581
+ #
582
+ class CompletedScan
583
+ # Unique identifier of a scan.
584
+ attr_reader :id
585
+ # Start time of the scan.
586
+ attr_reader :start_time
587
+ # Completion time of the scan.
588
+ attr_reader :end_time
589
+ # Elapsed time of the scan in milliseconds.
590
+ attr_reader :duration
591
+ # Number of vulnerabilities discovered in the scan.
592
+ attr_reader :vulns
593
+ # Number of live assets discovered in the scan.
594
+ attr_reader :assets
595
+ # Cumulative risk score for all assets in the scan.
596
+ attr_reader :risk_score
597
+ # Scan type. One of :scheduled or :manual
598
+ attr_reader :type
599
+ # Name of the engine where the scan was run. Not the unique ID.
600
+ attr_reader :engine_name
601
+
602
+ # Internal constructor to be called by #parse_json.
603
+ def initialize(&block)
604
+ instance_eval(&block) if block_given?
605
+ end
606
+
607
+ # Internal method for converting a JSON representation into a CompletedScan
608
+ # object.
609
+ def self.parse_json(json)
610
+ new do
611
+ @id = json['scanID']
612
+ @start_time = Time.at(json['startTime'] / 1000)
613
+ @end_time = Time.at(json['endTime'] / 1000)
614
+ @duration = json['duration']
615
+ @vulns = json['vulnerabilityCount']
616
+ @assets = json['liveHosts']
617
+ @risk_score = json['riskScore']
618
+ @type = json['startedByCD'] == 'S' ? :scheduled : :manual
619
+ @engine_name = json['scanEngineName']
620
+ end
621
+ end
622
+ end
581
623
  end
data/lib/nexpose/site.rb CHANGED
@@ -29,7 +29,7 @@ module Nexpose
29
29
  # @return Whether or not the delete request succeeded.
30
30
  #
31
31
  def delete_site(site_id)
32
- r = execute(make_xml('SiteDeleteRequest', {'site-id' => site_id}))
32
+ r = execute(make_xml('SiteDeleteRequest', { 'site-id' => site_id }))
33
33
  r.success
34
34
  end
35
35
 
@@ -40,7 +40,7 @@ module Nexpose
40
40
  # each scan run to date on the site provided.
41
41
  #
42
42
  def site_scan_history(site_id)
43
- r = execute(make_xml('SiteScanHistoryRequest', {'site-id' => site_id}))
43
+ r = execute(make_xml('SiteScanHistoryRequest', { 'site-id' => site_id }))
44
44
  scans = []
45
45
  if r.success
46
46
  r.res.elements.each('SiteScanHistoryResponse/ScanSummary') do |scan_event|
@@ -59,7 +59,18 @@ module Nexpose
59
59
  # @return [ScanSummary] details of the last completed scan for a site.
60
60
  #
61
61
  def last_scan(site_id)
62
- site_scan_history(site_id).select { |scan| scan.end_time }.max_by { |scan| scan.end_time }
62
+ site_scan_history(site_id).select(&:end_time).max_by(&:end_time)
63
+ end
64
+
65
+ # Retrieve a history of the completed scans for a given site.
66
+ #
67
+ # @param [FixNum] site_id Site ID to find scans for.
68
+ # @return [CompletedScan] details of the completed scans for the site.
69
+ #
70
+ def completed_scans(site_id)
71
+ table = { 'table-id' => 'site-completed-scans' }
72
+ data = DataTable._get_json_table(self, "/data/scan/site/#{site_id}", table)
73
+ data.map(&CompletedScan.method(:parse_json))
63
74
  end
64
75
  end
65
76
 
@@ -178,7 +189,7 @@ module Nexpose
178
189
  #
179
190
  # @param [String] hostname FQDN or DNS-resolvable host name of an asset.
180
191
  def remove_host(hostname)
181
- @assets = assets.reject { |asset| asset == HostName.new(hostname) }
192
+ @assets = assets.reject { |asset| asset == HostName.new(hostname) }
182
193
  end
183
194
 
184
195
  # Adds an asset to this site by IP address.
@@ -228,8 +239,8 @@ module Nexpose
228
239
  #
229
240
  def remove_asset(asset)
230
241
  begin
231
- # If the asset registers as a valid IP, store as IP.
232
- ip = IPAddr.new(asset)
242
+ # If the asset registers as a valid IP, remove as IP.
243
+ IPAddr.new(asset)
233
244
  remove_ip(asset)
234
245
  rescue ArgumentError => e
235
246
  if e.message == 'invalid address'
@@ -531,7 +542,6 @@ module Nexpose
531
542
  # Object that represents the summary of a Nexpose Site.
532
543
  #
533
544
  class SiteSummary
534
-
535
545
  # The Site ID.
536
546
  attr_reader :id
537
547
  # The Site Name.
@@ -557,7 +567,6 @@ module Nexpose
557
567
  # Object that represents a hostname to be added to a site.
558
568
  #
559
569
  class HostName
560
-
561
570
  # Named host (usually DNS or Netbios name).
562
571
  attr_accessor :host
563
572
 
@@ -595,7 +604,6 @@ module Nexpose
595
604
  # If to is nil then the from field will be used to specify a single IP Address only.
596
605
  #
597
606
  class IPRange
598
-
599
607
  # Start of range *Required
600
608
  attr_accessor :from
601
609
  # End of range *Optional (If nil then IPRange is a single IP Address)
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.8.9
4
+ version: 0.8.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - HD Moore
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2014-10-20 00:00:00.000000000 Z
14
+ date: 2014-10-29 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rex
@@ -96,7 +96,6 @@ files:
96
96
  - lib/nexpose/role.rb
97
97
  - lib/nexpose/scan.rb
98
98
  - lib/nexpose/scan_template.rb
99
- - lib/nexpose/settings.xml
100
99
  - lib/nexpose/shared_cred.rb
101
100
  - lib/nexpose/silo.rb
102
101
  - lib/nexpose/silo_profile.rb
@@ -1,14 +0,0 @@
1
- <GlobalSettings>
2
- <riskModel id="real_risk" recalculation_duration="do_not_recalculate"></riskModel>
3
- <RiskConfig includeRiskModifiers="false">
4
- <RiskModifiers veryHigh="2" high="1.5" medium="1" low="0.75" veryLow="0.5"></RiskModifiers>
5
- </RiskConfig>
6
- <ControlsScan>
7
- <enableControlsScan enabled="0"></enableControlsScan>
8
- </ControlsScan>
9
- <ExcludedHosts>
10
- <range from="10.4.18.219"></range>
11
- <range from="10.4.25.117"></range>
12
- </ExcludedHosts>
13
- </GlobalSettings>
14
-