nexpose 0.8.9 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
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
-