nexpose 0.6.3 → 0.6.4

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: a7bb33f6e513e5e433ca6ce6595e2e5c57362605
4
- data.tar.gz: bb1e25e94229c4079e9ad18f3acaf84cf584c697
3
+ metadata.gz: 4397794b70770fea503a7f1613d55350ecdb34e4
4
+ data.tar.gz: 94ca3aff891805148565fe6b868ea2c22f847038
5
5
  SHA512:
6
- metadata.gz: a1987527f194e406880839a82c6486d7cf1866cc0bb275506a8ca7aff75bb9a6b971af01c343979de2f395713e857904b5408bfaccadf1f0399bbca6d06f816e
7
- data.tar.gz: 275e2fdb7bed01c80d6d97f297235f0ca4ee36a23e4aa003b85156c8b46ce1010e3908af2a4eeccfcf8c7efc8a29740d89dbcc40aecba2de9ab84f870a9301c9
6
+ metadata.gz: 2c274049ae4574d6201fe233221c729aa23ab9a5df81397cfda75601f3f3cd59ce830bd8fd43573879b29ea6f74f7e18bca3fe6ce8da9f2e549c9efb0dbb7e15
7
+ data.tar.gz: c2113f68a3c3c06e6c3f070ed9114f8351b7b01948dfa540e12558b6157d2e5eb17a85f2e9276314f7dfb64147ec5b7f7e8651dbc85180b69cf18c84d4524381
data/lib/nexpose.rb CHANGED
@@ -61,6 +61,7 @@ require 'nexpose/alert'
61
61
  require 'nexpose/ajax'
62
62
  require 'nexpose/api_request'
63
63
  require 'nexpose/common'
64
+ require 'nexpose/console'
64
65
  require 'nexpose/creds'
65
66
  require 'nexpose/shared_cred'
66
67
  require 'nexpose/data_table'
@@ -0,0 +1,71 @@
1
+ module Nexpose
2
+
3
+ # Nexpose console configuration class.
4
+ #
5
+ # Changes to this object are not persisted until the #save method is called.
6
+ #
7
+ # Example usage:
8
+ # config = Nexpose::Console.load(nsc)
9
+ # config.session_timeout = 600
10
+ # config.save(nsc)
11
+ #
12
+ class Console
13
+
14
+ # Session timeout for the Nexpose web server (in seconds).
15
+ # The web interface enforces a value from 60 to 604,800 [1 minute to 7 days].
16
+ attr_accessor :session_timeout
17
+
18
+ # Impose a limit on the number of scan threads which an individual scan can use.
19
+ attr_accessor :scan_threads_limit
20
+
21
+ # Whether to retrieve incremental scan results from distributed engines.
22
+ attr_accessor :incremental_scan_results
23
+
24
+ # XML document representing the entire configuration.
25
+ attr_accessor :xml
26
+
27
+ # Construct a new Nexpose Security Console configuration object.
28
+ # Not meant to be called publicly.
29
+ # @see #load
30
+ #
31
+ # @param [REXML::Document] xml Parsed XML representation of the configuration.
32
+ #
33
+ def initialize(xml)
34
+ @xml = xml
35
+
36
+ nsc = REXML::XPath.first(@xml, 'NeXposeSecurityConsole')
37
+ @scan_threads_limit = nsc.attributes['scanThreadsLimit'].to_i
38
+ @incremental_scan_results = nsc.attributes['realtimeIntegration'] == '1'
39
+
40
+ web_server = REXML::XPath.first(nsc, 'WebServer')
41
+ @session_timeout = web_server.attributes['sessionTimeout'].to_i
42
+ end
43
+
44
+ # Load existing Nexpose security console configuration.
45
+ #
46
+ # @param [Connection] connection Nexpose connection.
47
+ #
48
+ def self.load(connection)
49
+ xml = REXML::Document.new(Nexpose::AJAX.get(connection, '/ajax/nsc_config.txml'))
50
+ new(xml)
51
+ end
52
+
53
+ # Save modifications to the Nexpose security console.
54
+ #
55
+ # @param [Connection] connection Nexpose connection.
56
+ # @return [Boolean] true if configuration successfully saved.
57
+ #
58
+ def save(connection)
59
+ nsc = REXML::XPath.first(@xml, 'NeXposeSecurityConsole')
60
+ nsc.attributes['scanThreadsLimit'] = @scan_threads_limit.to_i
61
+ nsc.attributes['realtimeIntegration'] = @incremental_scan_results ? '1' : '0'
62
+
63
+ web_server = REXML::XPath.first(nsc, 'WebServer')
64
+ web_server.attributes['sessionTimeout'] = @session_timeout.to_i
65
+
66
+ response = REXML::Document.new(Nexpose::AJAX.post(connection, '/ajax/save_nsc_config.txml', @xml))
67
+ saved = REXML::XPath.first(response, 'SaveConfig')
68
+ saved.attributes['success'] == '1'
69
+ end
70
+ end
71
+ end
data/lib/nexpose/creds.rb CHANGED
@@ -9,6 +9,26 @@ module Nexpose
9
9
  class Credential
10
10
  include XMLUtils
11
11
 
12
+ DEFAULT_PORTS = { 'cvs' => 2401,
13
+ 'ftp' => 21,
14
+ 'http' => 80,
15
+ 'as400' => 449,
16
+ 'notes' => 1352,
17
+ 'tds' => 1433,
18
+ 'sybase' => 5000,
19
+ 'cifs' => 445,
20
+ 'cifshash' => 445,
21
+ 'oracle' => 1521,
22
+ 'pop' => 110,
23
+ 'postgresql' => 5432,
24
+ 'remote execution' => 512,
25
+ 'snmp' => 161,
26
+ 'ssh' => 22,
27
+ 'ssh-key' => 22,
28
+ 'telnet' => 23,
29
+ 'mysql' => 3306,
30
+ 'db2' => 50000 }
31
+
12
32
  # Security blob for an existing set of credentials
13
33
  attr_accessor :blob
14
34
  # The service for these credentials. Can be All.
@@ -62,6 +62,19 @@ module Nexpose
62
62
  alias_method :assets, :list_site_devices
63
63
  alias_method :list_assets, :list_site_devices
64
64
 
65
+ # Get a list of all assets currently associated with a group.
66
+ #
67
+ # @param [Fixnum] dev_id Unique identifier of a device (asset).
68
+ # @return [Array[Asset]] List of group assets.
69
+ #
70
+ def group_assets(group_id)
71
+ payload = { 'sort' => 'assetName',
72
+ 'table-id' => 'group-assets',
73
+ 'groupID' => group_id }
74
+ results = DataTable._get_json_table(self, '/data/asset/group', payload)
75
+ results.map { |a| Asset.new(a) }
76
+ end
77
+
65
78
  # List the vulnerability findings for a given device ID.
66
79
  #
67
80
  # @param [Fixnum] dev_id Unique identifier of a device (asset).
@@ -101,6 +101,10 @@ module Nexpose
101
101
  # Valid Operators: IN, NOT_IN
102
102
  IP_RANGE = 'IP_RANGE'
103
103
 
104
+ # Valid Operators: IS, IS_NOT, IN_RANGE
105
+ # Valid Values: Integers from 1 to 65535
106
+ OPEN_PORT = 'OPEN_PORT'
107
+
104
108
  # Valid Operators: CONTAINS, NOT_CONTAINS, IS_EMPTY, IS_NOT_EMPTY
105
109
  OS = 'OS'
106
110
 
@@ -130,6 +134,10 @@ module Nexpose
130
134
  # Valid Operators: CONTAINS, NOT_CONTAINS
131
135
  SOFTWARE = 'SOFTWARE'
132
136
 
137
+ # Valid Operators: ARE
138
+ # Valid Values: PRESENT, NOT_PRESENT
139
+ VALIDATED_VULNERABILITIES = 'VULNERABILITY_VALIDATED_STATUS'
140
+
133
141
  # Search against vulnerability titles that an asset contains.
134
142
  # Valid Operators: CONTAINS, NOT_CONTAINS
135
143
  VULNERABILITY = 'VULNERABILITY'
@@ -146,6 +154,7 @@ module Nexpose
146
154
  NOT_CONTAINS = 'NOT_CONTAINS'
147
155
  IS = 'IS'
148
156
  IS_NOT = 'IS_NOT'
157
+ ARE = 'ARE'
149
158
  IN = 'IN'
150
159
  NOT_IN = 'NOT_IN'
151
160
  IN_RANGE = 'IN_RANGE'
@@ -214,6 +223,11 @@ module Nexpose
214
223
  FORMAT = '%m/%d/%Y'
215
224
  end
216
225
 
226
+ module ValidatedVulnerability
227
+ NOT_PRESENT = 1
228
+ PRESENT = 0
229
+ end
230
+
217
231
  module VulnerabilityExposure
218
232
  MALWARE = 'type:"malware_type", name:"malwarekit"'
219
233
  # TODO: A problem in Nexpose causes these values to not be constant.
@@ -146,6 +146,30 @@ module Nexpose
146
146
  gen.attributes['disableWebSpider'] = enable ? '0' : '1'
147
147
  end
148
148
 
149
+ # Add custom TCP ports to scan for services
150
+ # @param [Array] ports to scan
151
+ def tcp_service_ports=(ports)
152
+ service_ports = REXML::XPath.first(@xml, 'ScanTemplate/ServiceDiscovery/TCPPortScan')
153
+ service_ports.attributes['mode'] = "custom"
154
+ service_ports.attributes['method'] = "syn"
155
+ REXML::XPath.first(service_ports, './portList').text = ports.join(",")
156
+ end
157
+
158
+ # Add custom UDP ports to scan for services
159
+ # @param [Array] posts to scan
160
+ def udp_service_ports=(ports)
161
+ service_ports = REXML::XPath.first(@xml, 'ScanTemplate/ServiceDiscovery/UDPPortScan')
162
+ service_ports.attributes['mode'] = "custom"
163
+ REXML::XPath.first(service_ports, './portList').text = ports.join(",")
164
+ end
165
+
166
+ # Disable UDP port scan
167
+ # @param [Boolean] enable or disable UDP ports
168
+ def enable_udp_ports=(enable)
169
+ service_ports = REXML::XPath.first(@xml, 'ScanTemplate/ServiceDiscovery/UDPPortScan')
170
+ service_ports.attributes['mode'] = 'none' unless enable
171
+ end
172
+
149
173
  # @return [Boolean] Whether to correlate reliable checks with regular checks.
150
174
  def correlate?
151
175
  vuln_checks = REXML::XPath.first(@xml, 'ScanTemplate/VulnerabilityChecks')
@@ -111,46 +111,93 @@ module Nexpose
111
111
  !!(response =~ /success="1"/)
112
112
  end
113
113
 
114
- def to_xml
115
- xml = '<Credential '
116
- xml << %( id="#{@id}">)
117
-
118
- xml << %(<Name>#{@name}</Name>)
119
- xml << %(<Description>#{@description}</Description>)
120
-
121
- xml << %(<Services><Service type="#{@type}"></Service></Services>)
122
-
123
- xml << '<Account type="nexpose">'
124
- xml << %(<Field name="database">#{@database}</Field>)
125
- xml << %(<Field name="domain">#{@domain}</Field>)
126
- xml << %(<Field name="username">#{@username}</Field>)
127
- xml << %(<Field name="ntlmhash">#{@ntlm_hash}</Field>) if @ntlm_hash
128
- xml << %(<Field name="password">#{@password}</Field>) if @password
129
- xml << %(<Field name="pemkey">#{@pem_key}</Field>) if @pem_key
130
- xml << %(<Field name="privilegeelevationusername">#{@privilege_username}</Field>)
131
- xml << %(<Field name="privilegeelevationpassword">#{@privilege_password}</Field>) if @privilege_password
132
- xml << %(<Field name="privilegeelevationtype">#{@privilege_type}</Field>) if @privilege_type
133
- xml << '</Account>'
134
-
135
- xml << '<Restrictions>'
136
- xml << %(<Restriction type="host">#{@host}</Restriction>) if @host
137
- xml << %(<Restriction type="port">#{@port}</Restriction>) if @port
138
- xml << '</Restrictions>'
139
-
140
- xml << %(<Sites all="#{@all_sites ? 1 : 0}">)
141
- @sites.each do |site|
142
- xml << %(<Site id="#{site}")
143
- xml << ' enabled="0"' if @disabled.member? site
144
- xml << '></Site>'
114
+ def as_xml
115
+ xml = REXML::Element.new('Credential')
116
+ xml.add_attribute('id', @id)
117
+
118
+ name = xml.add_element('Name').add_text(@name)
119
+
120
+ desc = xml.add_element('Description').add_text(@description)
121
+
122
+ services = xml.add_element('Services')
123
+ service = services.add_element('Service').add_attribute('type', @type)
124
+
125
+ (account = xml.add_element('Account')).add_attribute('type', 'nexpose')
126
+ account.add_element('Field', { 'name' => 'database' }).add_text(@database)
127
+
128
+ account.add_element('Field', { 'name' => 'domain' }).add_text(@domain)
129
+ account.add_element('Field', { 'name' => 'username' }).add_text(@username)
130
+ account.add_element('Field', { 'name' => 'ntlmhash' }).add_text(@ntlm_hash) if @ntlm_hash
131
+ account.add_element('Field', { 'name' => 'password' }).add_text(@password) if @password
132
+ account.add_element('Field', { 'name' => 'pemkey' }).add_text(@pem_key) if @pem_key
133
+ account.add_element('Field', { 'name' => 'privilegeelevationusername' }).add_text(@privilege_username)
134
+ account.add_element('Field', { 'name' => 'privilegeelevationpassword' }).add_text(@privilege_password) if @privilege_password
135
+ account.add_element('Field', { 'name' => 'privilegeelevationtype' }).add_text(@privilege_type) if @privilege_type
136
+
137
+ restrictions = xml.add_element('Restrictions')
138
+ restrictions.add_element('Restriction', { 'type' => 'host' }).add_text(@host) if @host
139
+ restrictions.add_element('Restriction', { 'type' => 'port' }).add_text(@port) if @port
140
+
141
+ sites = xml.add_element('Sites')
142
+ sites.add_attribute('all', @all_sites ? 1 : 0)
143
+ @sites.each do |s|
144
+ site = sites.add_element('Site')
145
+ site.add_attribute('id', s)
146
+ site.add_attribute('enabled', 0) if @disabled.member? s
145
147
  end
146
148
  if @sites.empty?
147
- @disabled.each do |site|
148
- xml << %(<Site id="#{site}" enabled="0"></Site>)
149
+ @disabled.each do |s|
150
+ site = sites.add_element('Site')
151
+ site.add_attribute('id', s)
152
+ site.add_attribute('enabled', 0)
149
153
  end
150
154
  end
151
- xml << '</Sites>'
152
155
 
153
- xml << '</Credential>'
156
+ xml
157
+ end
158
+
159
+ def to_xml
160
+ as_xml.to_s
161
+ end
162
+
163
+ # Test this credential against a target where the credentials should apply.
164
+ # Only works for a newly created credential. Loading an existing credential
165
+ # will likely fail.
166
+ #
167
+ # @param [Connection] nsc An active connection to the security console.
168
+ # @param [String] target Target host to check credentials against.
169
+ # @param [Fixnum] engine_id ID of the engine to use for testing credentials.
170
+ # Will default to the local engine if none is provided.
171
+ #
172
+ def test(nsc, target, engine_id = nil)
173
+ unless engine_id
174
+ local_engine = nsc.engines.find { |e| e.name == 'Local scan engine' }
175
+ engine_id = local_engine.id
176
+ end
177
+
178
+ parameters = _to_param(target, engine_id)
179
+ xml = AJAX.form_post(nsc, '/ajax/test_admin_credentials.txml', parameters)
180
+ result = REXML::XPath.first(REXML::Document.new(xml), 'TestAdminCredentialsResult')
181
+ result.attributes['success'].to_i == 1
182
+ end
183
+
184
+ def _to_param(target, engine_id)
185
+ port = @port
186
+ port = Credential::DEFAULT_PORTS[@type] if port.nil?
187
+
188
+ { engineid: engine_id,
189
+ sc_creds_dev: target,
190
+ sc_creds_svc: @type,
191
+ sc_creds_database: @database,
192
+ sc_creds_domain: @domain,
193
+ sc_creds_uname: @username,
194
+ sc_creds_password: @password,
195
+ sc_creds_pemkey: @pem_key,
196
+ sc_creds_port: port,
197
+ sc_creds_privilegeelevationusername: @privilege_username,
198
+ sc_creds_privilegeelevationpassword: @privilege_password,
199
+ sc_creds_privilegeelevationtype: @privilege_type,
200
+ siteid: -1 }
154
201
  end
155
202
 
156
203
  def self.parse(xml)
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.6.3
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - HD Moore
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-02-25 00:00:00.000000000 Z
13
+ date: 2014-03-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: librex
@@ -72,6 +72,7 @@ files:
72
72
  - lib/nexpose/api_request.rb
73
73
  - lib/nexpose/common.rb
74
74
  - lib/nexpose/connection.rb
75
+ - lib/nexpose/console.rb
75
76
  - lib/nexpose/creds.rb
76
77
  - lib/nexpose/dag.rb
77
78
  - lib/nexpose/data_table.rb
@@ -116,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
117
  version: '0'
117
118
  requirements: []
118
119
  rubyforge_project:
119
- rubygems_version: 2.2.0
120
+ rubygems_version: 2.2.2
120
121
  signing_key:
121
122
  specification_version: 4
122
123
  summary: Ruby API for Rapid7 Nexpose