nexpose 0.8.18 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nexpose.rb +3 -2
- data/lib/nexpose/ajax.rb +2 -0
- data/lib/nexpose/api.rb +11 -3
- data/lib/nexpose/api_request.rb +32 -21
- data/lib/nexpose/connection.rb +1 -1
- data/lib/nexpose/credential.rb +108 -0
- data/lib/nexpose/dag.rb +1 -1
- data/lib/nexpose/filter.rb +6 -4
- data/lib/nexpose/report.rb +8 -8
- data/lib/nexpose/scan.rb +2 -2
- data/lib/nexpose/{shared_cred.rb → shared_credential.rb} +5 -46
- data/lib/nexpose/site.rb +2 -2
- data/lib/nexpose/{creds.rb → site_credential.rb} +13 -83
- data/lib/nexpose/tag.rb +1 -1
- data/lib/nexpose/util.rb +18 -6
- data/lib/nexpose/version.rb +1 -1
- data/nexpose.gemspec +24 -0
- metadata +11 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b26ec57d92c374454b5be75b30201eddfcf23e99
|
4
|
+
data.tar.gz: 621fad61669205dbf85052ee210019f00578fb50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27b3f31b2baa7db3637a65f5b9c2bfbdf9af2f8f0918ad7cf1af724c285a219b9e4e0faaf85a8a89b51c8a53ab079327f7d6029decf39dda1e489852271edd5a
|
7
|
+
data.tar.gz: 1fd837247c8a92f57d138712d8e7de1585f695353dc75fdaa14b16d5aac9ce4720dbbb480911867f6e2cede17dec9b3460621dd0d84bff06063669894b28b9de
|
data/lib/nexpose.rb
CHANGED
@@ -66,8 +66,9 @@ require 'nexpose/api'
|
|
66
66
|
require 'nexpose/api_request'
|
67
67
|
require 'nexpose/common'
|
68
68
|
require 'nexpose/console'
|
69
|
-
require 'nexpose/
|
70
|
-
require 'nexpose/
|
69
|
+
require 'nexpose/credential'
|
70
|
+
require 'nexpose/site_credential'
|
71
|
+
require 'nexpose/shared_credential'
|
71
72
|
require 'nexpose/data_table'
|
72
73
|
require 'nexpose/device'
|
73
74
|
require 'nexpose/discovery'
|
data/lib/nexpose/ajax.rb
CHANGED
data/lib/nexpose/api.rb
CHANGED
@@ -25,12 +25,13 @@ module Nexpose
|
|
25
25
|
next if k == :url # Do not store self-referential URL.
|
26
26
|
# Store resource URLs separately and create lazy accessors.
|
27
27
|
if v.is_a?(Hash) && v.key?(:url)
|
28
|
-
|
29
|
-
self.class.send(:define_method, k, proc { |conn = nsc| load_resource(conn, k, instance_variable_get("@#{k}_url")) })
|
28
|
+
self.class.send(:define_method, k, proc { |conn = nsc| load_resource(conn, k, v[:url].gsub(/.*\/api/, '/api')) })
|
30
29
|
else
|
31
30
|
# Convert timestamps.
|
32
31
|
if v.is_a?(String) && v.match(/^\d{8}T\d{6}\.\d{3}/)
|
33
32
|
instance_variable_set("@#{k}", ISO8601.to_time(v))
|
33
|
+
elsif v.is_a?(Array) && k == :attributes
|
34
|
+
instance_variable_set("@#{k}", v.map { |h| { h[:key] => h[:value] } })
|
34
35
|
else
|
35
36
|
instance_variable_set("@#{k}", v)
|
36
37
|
end
|
@@ -54,7 +55,13 @@ module Nexpose
|
|
54
55
|
obj = class_from_string(k)
|
55
56
|
resp = AJAX.get(nsc, url, AJAX::CONTENT_TYPE::JSON)
|
56
57
|
hash = JSON.parse(resp, symbolize_names: true)
|
57
|
-
|
58
|
+
if hash.is_a?(Array)
|
59
|
+
resources = hash.map { |e| obj.method(:new).call.object_from_hash(nsc, e) }
|
60
|
+
elsif hash.key?(:resources)
|
61
|
+
resources = hash[:resources].map { |e| obj.method(:new).call.object_from_hash(nsc, e) }
|
62
|
+
else
|
63
|
+
resources = obj.method(:new).call.object_from_hash(nsc, hash)
|
64
|
+
end
|
58
65
|
instance_variable_set("@#{k}", resources)
|
59
66
|
self.class.send(:define_method, k, proc { instance_variable_get("@#{k}") })
|
60
67
|
resources
|
@@ -70,6 +77,7 @@ module Nexpose
|
|
70
77
|
#
|
71
78
|
def class_from_string(field)
|
72
79
|
str = field.to_s.split('_').map(&:capitalize!).join
|
80
|
+
str = 'Vulnerability' if str == 'Vulnerabilities'
|
73
81
|
str.chop! if str.end_with?('s')
|
74
82
|
Object.const_get('Nexpose').const_get(str)
|
75
83
|
end
|
data/lib/nexpose/api_request.rb
CHANGED
@@ -47,34 +47,45 @@ module Nexpose
|
|
47
47
|
@http.read_timeout = options[:timeout] if options.key? :timeout
|
48
48
|
@raw_response = @http.post(@uri.path, @req, @headers)
|
49
49
|
@raw_response_data = @raw_response.read_body
|
50
|
-
@res = parse_xml(@raw_response_data)
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
# Allow the :raw keyword to bypass XML parsing.
|
52
|
+
if options[:raw]
|
53
|
+
if raw_response_data =~ /success="1"/
|
54
|
+
@success = true
|
55
|
+
else
|
56
|
+
@success = false
|
57
|
+
@error = "User requested raw XML response. Not parsing failures."
|
58
|
+
end
|
59
|
+
else
|
60
|
+
@res = parse_xml(@raw_response_data)
|
56
61
|
|
57
|
-
|
62
|
+
unless @res.root
|
63
|
+
@error = 'Nexpose service returned invalid XML.'
|
64
|
+
return @sid
|
65
|
+
end
|
58
66
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@
|
67
|
+
@sid = attributes['session-id']
|
68
|
+
|
69
|
+
if (attributes['success'] and attributes['success'].to_i == 1)
|
70
|
+
@success = true
|
71
|
+
elsif @api_version =~ /1.2/ and @res and (@res.get_elements '//Exception').count < 1
|
72
|
+
@success = true
|
73
|
+
else
|
74
|
+
@success = false
|
75
|
+
if @api_version =~ /1.2/
|
76
|
+
@res.elements.each('//Exception/Message') do |message|
|
67
77
|
@error = message.text.sub(/.*Exception: */, '')
|
68
|
-
|
78
|
+
end
|
69
79
|
@res.elements.each('//Exception/Stacktrace') do |stacktrace|
|
70
80
|
@trace = stacktrace.text
|
71
81
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
else
|
83
|
+
@res.elements.each('//message') do |message|
|
84
|
+
@error = message.text.sub(/.*Exception: */, '')
|
85
|
+
end
|
86
|
+
@res.elements.each('//stacktrace') do |stacktrace|
|
87
|
+
@trace = stacktrace.text
|
88
|
+
end
|
78
89
|
end
|
79
90
|
end
|
80
91
|
end
|
data/lib/nexpose/connection.rb
CHANGED
@@ -0,0 +1,108 @@
|
|
1
|
+
module Nexpose
|
2
|
+
|
3
|
+
# Contains the shared methods for the SiteCredential and SharedCredential Objects.
|
4
|
+
# See Nexpose::SiteCredential or Nexpose::SharedCredential for additional info.
|
5
|
+
class Credential
|
6
|
+
|
7
|
+
# Mapping of Common Ports.
|
8
|
+
DEFAULT_PORTS = { 'cvs' => 2401,
|
9
|
+
'ftp' => 21,
|
10
|
+
'http' => 80,
|
11
|
+
'as400' => 449,
|
12
|
+
'notes' => 1352,
|
13
|
+
'tds' => 1433,
|
14
|
+
'sybase' => 5000,
|
15
|
+
'cifs' => 445,
|
16
|
+
'cifshash' => 445,
|
17
|
+
'oracle' => 1521,
|
18
|
+
'pop' => 110,
|
19
|
+
'postgresql' => 5432,
|
20
|
+
'remote execution' => 512,
|
21
|
+
'snmp' => 161,
|
22
|
+
'snmpv3' => 161,
|
23
|
+
'ssh' => 22,
|
24
|
+
'ssh-key' => 22,
|
25
|
+
'telnet' => 23,
|
26
|
+
'mysql' => 3306,
|
27
|
+
'db2' => 50000 }
|
28
|
+
|
29
|
+
|
30
|
+
# Credential Service/Type Options.
|
31
|
+
module Service
|
32
|
+
CVS = 'cvs' # Concurrent Versioning System (CVS)
|
33
|
+
FTP = 'ftp' # File Transfer Protocol (FTP)
|
34
|
+
HTTP = 'http' # Web Site HTTP Authentication
|
35
|
+
AS400 = 'as400' # IBM AS/400
|
36
|
+
NOTES = 'notes' # Lotus Notes/Domino
|
37
|
+
TDS = 'tds' # Microsoft SQL Server
|
38
|
+
SYBASE = 'sybase' # Sybase SQL Server
|
39
|
+
CIFS = 'cifs' # Microsoft Windows/Samba (SMB/CIFS)
|
40
|
+
CIFSHASH = 'cifshash' # Microsoft Windows/Samba LM/NTLM Hash (SMB/CIFS)
|
41
|
+
ORACLE = 'oracle' # Oracle
|
42
|
+
POP = 'pop' # Post Office Protocol (POP)
|
43
|
+
POSTGRESQL = 'postgresql' # PostgreSQL
|
44
|
+
REMOTE_EXECUTION = 'remote execution' # Remote Execution
|
45
|
+
SNMP = 'snmp' # Simple Network Management Protocol
|
46
|
+
SNMPV3 = 'snmpv3' # Simple Network Management Protocol v3
|
47
|
+
SSH = 'ssh' # Secure Shell (SSH)
|
48
|
+
SSH_KEY = 'ssh-key' # Secure Shell (SSH) Public Key
|
49
|
+
TELNET = 'telnet' # TELNET
|
50
|
+
MYSQL = 'mysql' # MySQL Server
|
51
|
+
DB2 = 'db2' # DB2
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Permission Elevation / Privilege Escalation Types.
|
56
|
+
module ElevationType
|
57
|
+
NONE = 'NONE'
|
58
|
+
SUDO = 'SUDO'
|
59
|
+
SUDOSU = 'SUDOSU'
|
60
|
+
SU = 'SU'
|
61
|
+
PBRUN = 'PBRUN'
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Test this credential against a target where the credentials should apply.
|
66
|
+
# Only works for a newly created credential. Loading an existing credential
|
67
|
+
# will likely fail.
|
68
|
+
#
|
69
|
+
# @param [Connection] nsc An active connection to the security console.
|
70
|
+
# @param [String] target Target host to check credentials against.
|
71
|
+
# @param [Fixnum] engine_id ID of the engine to use for testing credentials.
|
72
|
+
# Will default to the local engine if none is provided.
|
73
|
+
#
|
74
|
+
def test(nsc, target, engine_id = nil, siteid = -1)
|
75
|
+
unless engine_id
|
76
|
+
engine_id = nsc.engines.find { |e| e.name == 'Local scan engine' }.id
|
77
|
+
end
|
78
|
+
@port = Credential::DEFAULT_PORTS[@service] if @port.nil?
|
79
|
+
parameters = _to_param(target, engine_id, @port, siteid)
|
80
|
+
xml = AJAX.form_post(nsc, '/ajax/test_admin_credentials.txml', parameters)
|
81
|
+
result = REXML::XPath.first(REXML::Document.new(xml), 'TestAdminCredentialsResult')
|
82
|
+
result.attributes['success'].to_i == 1
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def _to_param(target, engine_id, port, siteid)
|
87
|
+
{ engineid: engine_id,
|
88
|
+
sc_creds_dev: target,
|
89
|
+
sc_creds_svc: @service,
|
90
|
+
sc_creds_database: @database,
|
91
|
+
sc_creds_domain: @domain,
|
92
|
+
sc_creds_uname: @username,
|
93
|
+
sc_creds_password: @password,
|
94
|
+
sc_creds_pemkey: @pem_key,
|
95
|
+
sc_creds_port: port,
|
96
|
+
sc_creds_privilegeelevationusername: @privilege_username,
|
97
|
+
sc_creds_privilegeelevationpassword: @privilege_password,
|
98
|
+
sc_creds_privilegeelevationtype: @privilege_type,
|
99
|
+
sc_creds_snmpv3authtype: @auth_type,
|
100
|
+
sc_creds_snmpv3privtype: @privacy_type,
|
101
|
+
sc_creds_snmpv3privpassword: @privacy_password,
|
102
|
+
siteid: siteid }
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
data/lib/nexpose/dag.rb
CHANGED
data/lib/nexpose/filter.rb
CHANGED
@@ -283,11 +283,12 @@ module Nexpose
|
|
283
283
|
|
284
284
|
# Convert this object into the map format expected by Nexpose.
|
285
285
|
#
|
286
|
-
def
|
286
|
+
def to_hash
|
287
287
|
{ 'metadata' => { 'fieldName' => field },
|
288
288
|
'operator' => operator,
|
289
289
|
'values' => Array(value) }
|
290
290
|
end
|
291
|
+
alias_method :to_map, :to_hash
|
291
292
|
|
292
293
|
def self.parse(json)
|
293
294
|
Criterion.new(json['metadata']['fieldName'],
|
@@ -310,15 +311,16 @@ module Nexpose
|
|
310
311
|
@match = match.upcase
|
311
312
|
end
|
312
313
|
|
313
|
-
def
|
314
|
+
def to_hash
|
314
315
|
{ 'operator' => @match,
|
315
|
-
'criteria' => @criteria.map { |c| c.
|
316
|
+
'criteria' => @criteria.map { |c| c.to_hash } }
|
316
317
|
end
|
318
|
+
alias_method :to_map, :to_hash
|
317
319
|
|
318
320
|
# Convert this object into the format expected by Nexpose.
|
319
321
|
#
|
320
322
|
def to_json
|
321
|
-
JSON.generate(
|
323
|
+
JSON.generate(to_hash)
|
322
324
|
end
|
323
325
|
|
324
326
|
# Generate the payload needed for a POST request for Asset Filter.
|
data/lib/nexpose/report.rb
CHANGED
@@ -222,23 +222,23 @@ module Nexpose
|
|
222
222
|
xml << '</AdhocReportConfig>'
|
223
223
|
end
|
224
224
|
|
225
|
-
include XMLUtils
|
226
|
-
include HTMLUtils
|
227
|
-
|
228
225
|
# Generate a report once using a simple configuration.
|
229
226
|
#
|
230
|
-
# For XML-based reports, only the
|
227
|
+
# For XML-based reports, only the textual report is returned and not any images.
|
231
228
|
#
|
232
229
|
# @param [Connection] connection Nexpose connection.
|
233
230
|
# @param [Fixnum] timeout How long, in seconds, to wait for the report to
|
234
231
|
# generate. Larger reports can take a significant amount of time.
|
232
|
+
# @param [Boolean] raw Whether to bypass response parsing an use the raw
|
233
|
+
# response. If this option is used, error will only be exposed by
|
234
|
+
# examining Connection#response_xml.
|
235
235
|
# @return Report in text format except for PDF, which returns binary data.
|
236
236
|
#
|
237
|
-
def generate(connection, timeout = 300)
|
237
|
+
def generate(connection, timeout = 300, raw = false)
|
238
238
|
xml = %(<ReportAdhocGenerateRequest session-id="#{connection.session_id}">)
|
239
239
|
xml << to_xml
|
240
240
|
xml << '</ReportAdhocGenerateRequest>'
|
241
|
-
response = connection.execute(xml, '1.1', timeout: timeout)
|
241
|
+
response = connection.execute(xml, '1.1', timeout: timeout, raw: raw)
|
242
242
|
if response.success
|
243
243
|
content_type_response = response.raw_response.header['Content-Type']
|
244
244
|
if content_type_response =~ /multipart\/mixed;\s*boundary=([^\s]+)/
|
@@ -254,9 +254,9 @@ module Nexpose
|
|
254
254
|
if /.*base64.*/ =~ part.header.to_s
|
255
255
|
if @format =~ /(?:ht|x)ml/
|
256
256
|
if part.header.to_s =~ %r(text/xml)
|
257
|
-
return
|
257
|
+
return part.content.unpack('m*')[0].to_s
|
258
258
|
elsif part.header.to_s =~ %r(text/html)
|
259
|
-
return
|
259
|
+
return part.content.unpack('m*')[0].to_s
|
260
260
|
end
|
261
261
|
else # text|pdf|csv|rtf
|
262
262
|
return part.content.unpack('m*')[0]
|
data/lib/nexpose/scan.rb
CHANGED
@@ -263,7 +263,7 @@ module Nexpose
|
|
263
263
|
case resp
|
264
264
|
when Net::HTTPSuccess
|
265
265
|
if zip_file
|
266
|
-
File.open(zip_file, 'wb') { |file| file.write(resp.body) }
|
266
|
+
::File.open(zip_file, 'wb') { |file| file.write(resp.body) }
|
267
267
|
else
|
268
268
|
resp.body
|
269
269
|
end
|
@@ -296,7 +296,7 @@ module Nexpose
|
|
296
296
|
data = Rex::MIME::Message.new
|
297
297
|
data.add_part(site_id.to_s, nil, nil, 'form-data; name="siteid"')
|
298
298
|
data.add_part(session_id, nil, nil, 'form-data; name="nexposeCCSessionID"')
|
299
|
-
scan = File.new(zip_file, 'rb')
|
299
|
+
scan = ::File.new(zip_file, 'rb')
|
300
300
|
data.add_part(scan.read, 'application/zip', 'binary',
|
301
301
|
"form-data; name=\"scan\"; filename=\"#{zip_file}\"")
|
302
302
|
|
@@ -21,14 +21,16 @@ module Nexpose
|
|
21
21
|
alias_method :delete_shared_cred, :delete_shared_credential
|
22
22
|
end
|
23
23
|
|
24
|
-
class SharedCredentialSummary
|
24
|
+
class SharedCredentialSummary < Credential
|
25
25
|
|
26
26
|
# Unique ID assigned to this credential by Nexpose.
|
27
27
|
attr_accessor :id
|
28
28
|
# Name to identify this credential.
|
29
29
|
attr_accessor :name
|
30
|
-
# The credential type. See Nexpose::Credential::
|
31
|
-
attr_accessor :
|
30
|
+
# The credential service/type. See Nexpose::Credential::Service.
|
31
|
+
attr_accessor :service
|
32
|
+
alias :type :service
|
33
|
+
alias :type= :service=
|
32
34
|
# Domain or realm.
|
33
35
|
attr_accessor :domain
|
34
36
|
# User name.
|
@@ -168,49 +170,6 @@ module Nexpose
|
|
168
170
|
as_xml.to_s
|
169
171
|
end
|
170
172
|
|
171
|
-
# Test this credential against a target where the credentials should apply.
|
172
|
-
# Only works for a newly created credential. Loading an existing credential
|
173
|
-
# will likely fail.
|
174
|
-
#
|
175
|
-
# @param [Connection] nsc An active connection to the security console.
|
176
|
-
# @param [String] target Target host to check credentials against.
|
177
|
-
# @param [Fixnum] engine_id ID of the engine to use for testing credentials.
|
178
|
-
# Will default to the local engine if none is provided.
|
179
|
-
#
|
180
|
-
def test(nsc, target, engine_id = nil)
|
181
|
-
unless engine_id
|
182
|
-
local_engine = nsc.engines.find { |e| e.name == 'Local scan engine' }
|
183
|
-
engine_id = local_engine.id
|
184
|
-
end
|
185
|
-
|
186
|
-
parameters = _to_param(target, engine_id)
|
187
|
-
xml = AJAX.form_post(nsc, '/ajax/test_admin_credentials.txml', parameters)
|
188
|
-
result = REXML::XPath.first(REXML::Document.new(xml), 'TestAdminCredentialsResult')
|
189
|
-
result.attributes['success'].to_i == 1
|
190
|
-
end
|
191
|
-
|
192
|
-
def _to_param(target, engine_id)
|
193
|
-
port = @port
|
194
|
-
port = Credential::DEFAULT_PORTS[@type] if port.nil?
|
195
|
-
|
196
|
-
{ engineid: engine_id,
|
197
|
-
sc_creds_dev: target,
|
198
|
-
sc_creds_svc: @type,
|
199
|
-
sc_creds_database: @database,
|
200
|
-
sc_creds_domain: @domain,
|
201
|
-
sc_creds_uname: @username,
|
202
|
-
sc_creds_password: @password,
|
203
|
-
sc_creds_pemkey: @pem_key,
|
204
|
-
sc_creds_port: port,
|
205
|
-
sc_creds_privilegeelevationusername: @privilege_username,
|
206
|
-
sc_creds_privilegeelevationpassword: @privilege_password,
|
207
|
-
sc_creds_privilegeelevationtype: @privilege_type,
|
208
|
-
sc_creds_snmpv3authtype: @auth_type,
|
209
|
-
sc_creds_snmpv3privtype: @privacy_type,
|
210
|
-
sc_creds_snmpv3privpassword: @privacy_password,
|
211
|
-
siteid: -1 }
|
212
|
-
end
|
213
|
-
|
214
173
|
def self.parse(xml)
|
215
174
|
rexml = REXML::Document.new(xml)
|
216
175
|
rexml.elements.each('Credential') do |c|
|
data/lib/nexpose/site.rb
CHANGED
@@ -352,7 +352,7 @@ module Nexpose
|
|
352
352
|
'tag' => @description.nil? ? '' : @description,
|
353
353
|
'riskFactor' => @risk_factor,
|
354
354
|
# 'vCenter' => @discovery_connection_id,
|
355
|
-
'searchCriteria' => @criteria.nil? ? { 'operator' => 'AND' } : @criteria.
|
355
|
+
'searchCriteria' => @criteria.nil? ? { 'operator' => 'AND' } : @criteria.to_hash }
|
356
356
|
json = JSON.generate(details)
|
357
357
|
|
358
358
|
response = AJAX.post(nsc, uri, json, AJAX::CONTENT_TYPE::JSON)
|
@@ -494,7 +494,7 @@ module Nexpose
|
|
494
494
|
end
|
495
495
|
|
496
496
|
s.elements.each('Credentials/adminCredentials') do |cred|
|
497
|
-
site.credentials <<
|
497
|
+
site.credentials << SiteCredential.parse(cred)
|
498
498
|
end
|
499
499
|
|
500
500
|
s.elements.each('ScanConfig') do |scan_config|
|
@@ -6,29 +6,9 @@ module Nexpose
|
|
6
6
|
# be passed back as is during a Site Save operation. This object
|
7
7
|
# can only be used to create a new set of credentials.
|
8
8
|
#
|
9
|
-
class Credential
|
9
|
+
class SiteCredential < 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
|
-
'snmpv3' => 161,
|
27
|
-
'ssh' => 22,
|
28
|
-
'ssh-key' => 22,
|
29
|
-
'telnet' => 23,
|
30
|
-
'mysql' => 3306,
|
31
|
-
'db2' => 50000 }
|
32
12
|
|
33
13
|
# Security blob for an existing set of credentials
|
34
14
|
attr_accessor :blob
|
@@ -38,8 +18,6 @@ module Nexpose
|
|
38
18
|
attr_accessor :host
|
39
19
|
# The port on which to use these credentials.
|
40
20
|
attr_accessor :port
|
41
|
-
# The user id or username
|
42
|
-
attr_accessor :userid
|
43
21
|
# The password
|
44
22
|
attr_accessor :password
|
45
23
|
# The realm for these credentials
|
@@ -63,10 +41,18 @@ module Nexpose
|
|
63
41
|
# The privacy/encryption pass phrase to use with SNMP v3 credentials
|
64
42
|
attr_accessor :privacy_password
|
65
43
|
|
44
|
+
# Permission elevation type. See Nexpose::Credential::ElevationType.
|
45
|
+
attr_accessor :privilege_type
|
46
|
+
# The User ID or Username
|
47
|
+
attr_accessor :username
|
48
|
+
alias :userid :username
|
49
|
+
alias :userid= :username=
|
50
|
+
|
51
|
+
|
66
52
|
def self.for_service(service, user, password, realm = nil, host = nil, port = nil)
|
67
53
|
cred = new
|
68
54
|
cred.service = service
|
69
|
-
cred.
|
55
|
+
cred.username = user
|
70
56
|
cred.password = password
|
71
57
|
cred.realm = realm
|
72
58
|
cred.host = host
|
@@ -80,7 +66,7 @@ module Nexpose
|
|
80
66
|
@priv_username = username
|
81
67
|
@priv_password = password
|
82
68
|
end
|
83
|
-
|
69
|
+
|
84
70
|
def add_snmpv3_credentials(auth_type, privacy_type, privacy_password)
|
85
71
|
@auth_type = auth_type
|
86
72
|
@privacy_type = privacy_type
|
@@ -102,9 +88,8 @@ module Nexpose
|
|
102
88
|
|
103
89
|
def as_xml
|
104
90
|
attributes = {}
|
105
|
-
|
106
91
|
attributes['service'] = @service
|
107
|
-
attributes['userid'] = @
|
92
|
+
attributes['userid'] = @username
|
108
93
|
attributes['password'] = @password
|
109
94
|
attributes['realm'] = @realm
|
110
95
|
attributes['host'] = @host
|
@@ -113,7 +98,7 @@ module Nexpose
|
|
113
98
|
attributes['privilegeelevationtype'] = @priv_type if @priv_type
|
114
99
|
attributes['privilegeelevationusername'] = @priv_username if @priv_username
|
115
100
|
attributes['privilegeelevationpassword'] = @priv_password if @priv_password
|
116
|
-
|
101
|
+
|
117
102
|
attributes['snmpv3authtype'] = @auth_type if @auth_type
|
118
103
|
attributes['snmpv3privtype'] = @privacy_type if @privacy_type
|
119
104
|
attributes['snmpv3privpassword'] = @privacy_password if @privacy_password
|
@@ -139,61 +124,6 @@ module Nexpose
|
|
139
124
|
to_xml.hash
|
140
125
|
end
|
141
126
|
|
142
|
-
# Credential type options.
|
143
|
-
#
|
144
|
-
module Type
|
145
|
-
|
146
|
-
# Concurrent Versioning System (CVS)
|
147
|
-
CVS = 'cvs'
|
148
|
-
# File Transfer Protocol (FTP)
|
149
|
-
FTP = 'ftp'
|
150
|
-
# Web Site HTTP Authentication
|
151
|
-
HTTP = 'http'
|
152
|
-
# IBM AS/400
|
153
|
-
AS400 = 'as400'
|
154
|
-
# Lotus Notes/Domino
|
155
|
-
NOTES = 'notes'
|
156
|
-
# Microsoft SQL Server
|
157
|
-
TDS = 'tds'
|
158
|
-
# Sybase SQL Server
|
159
|
-
SYBASE = 'sybase'
|
160
|
-
# Microsoft Windows/Samba (SMB/CIFS)
|
161
|
-
CIFS = 'cifs'
|
162
|
-
# Microsoft Windows/Samba LM/NTLM Hash (SMB/CIFS)
|
163
|
-
CIFSHASH = 'cifshash'
|
164
|
-
# Oracle
|
165
|
-
ORACLE = 'oracle'
|
166
|
-
# Post Office Protocol (POP)
|
167
|
-
POP = 'pop'
|
168
|
-
# PostgreSQL
|
169
|
-
POSTGRESQL = 'postgresql'
|
170
|
-
# Remote Execution
|
171
|
-
REMOTE_EXECUTION = 'remote execution'
|
172
|
-
# Simple Network Management Protocol
|
173
|
-
SNMP = 'snmp'
|
174
|
-
# Simple Network Management Protocol v3
|
175
|
-
SNMPV3 = 'snmpv3'
|
176
|
-
# Secure Shell (SSH)
|
177
|
-
SSH = 'ssh'
|
178
|
-
# Secure Shell (SSH) Public Key
|
179
|
-
SSH_KEY = 'ssh-key'
|
180
|
-
# TELNET
|
181
|
-
TELNET = 'telnet'
|
182
|
-
# MySQL Server
|
183
|
-
MYSQL = 'mysql'
|
184
|
-
# DB2
|
185
|
-
DB2 = 'db2'
|
186
|
-
end
|
187
|
-
|
188
|
-
# Permission Elevation Types
|
189
|
-
#
|
190
|
-
module ElevationType
|
191
|
-
|
192
|
-
NONE = 'NONE'
|
193
|
-
SUDO = 'SUDO'
|
194
|
-
SUDOSU = 'SUDOSU'
|
195
|
-
SU = 'SU'
|
196
|
-
end
|
197
127
|
end
|
198
128
|
|
199
129
|
# Object that represents Header name-value pairs, associated with Web Session Authentication.
|
data/lib/nexpose/tag.rb
CHANGED
@@ -259,7 +259,7 @@ module Nexpose
|
|
259
259
|
'tag_config' => { 'site_ids' => @site_ids,
|
260
260
|
'tag_associated_asset_ids' => @associated_asset_ids,
|
261
261
|
'asset_group_ids' => @asset_group_ids,
|
262
|
-
'search_criteria' => @search_criteria ? @search_criteria.
|
262
|
+
'search_criteria' => @search_criteria ? @search_criteria.to_hash : nil
|
263
263
|
}
|
264
264
|
}
|
265
265
|
if @type == Type::Generic::CUSTOM
|
data/lib/nexpose/util.rb
CHANGED
@@ -6,12 +6,6 @@ module Nexpose
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
module HTMLUtils
|
10
|
-
def parse_html(html)
|
11
|
-
Nokogiri::HTML(html, nil, 'UTF-8')
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
9
|
module XMLUtils
|
16
10
|
|
17
11
|
def parse_xml(xml)
|
@@ -116,4 +110,22 @@ module Nexpose
|
|
116
110
|
time.to_time.utc.strftime('%Y%m%dT%H%M%S.%LZ')
|
117
111
|
end
|
118
112
|
end
|
113
|
+
|
114
|
+
# Functions for handling attributes as understood by the API.
|
115
|
+
# In particular, the API expects a JSON object with the hash defined as:
|
116
|
+
# { "key": "key-string",
|
117
|
+
# "value": "value-string" }
|
118
|
+
#
|
119
|
+
module Attributes
|
120
|
+
module_function
|
121
|
+
|
122
|
+
# Convert an array of attributes into a hash consumable by the API.
|
123
|
+
#
|
124
|
+
# @param [Array[Hash]] arr Array of attributes to convert.
|
125
|
+
# @return [Array[Hash]] Array formatted as expected by the API.
|
126
|
+
#
|
127
|
+
def to_hash(arr)
|
128
|
+
arr.map(&:flatten).map { |p| { 'key' => p.first.to_s, 'value' => p.last.to_s } }
|
129
|
+
end
|
130
|
+
end
|
119
131
|
end
|
data/lib/nexpose/version.rb
CHANGED
data/nexpose.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'nexpose/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'nexpose'
|
8
|
+
s.version = Nexpose::VERSION
|
9
|
+
s.homepage = 'https://github.com/rapid7/nexpose-client'
|
10
|
+
s.summary = 'Ruby API for Rapid7 Nexpose'
|
11
|
+
s.description = 'This gem provides a Ruby API to the Nexpose vulnerability management product by Rapid7.'
|
12
|
+
s.license = 'BSD'
|
13
|
+
s.authors = ['HD Moore', 'Chris Lee', 'Michael Daines', 'Brandon Turner']
|
14
|
+
s.email = ['hd_moore@rapid7.com', 'christopher_lee@rapid7.com', 'michael_daines@rapid7.com', 'brandon_turner@rapid7.com' ]
|
15
|
+
s.files = Dir['[A-Z]*'] + Dir['lib/**/*']
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
s.extra_rdoc_files = ['README.markdown']
|
18
|
+
s.required_ruby_version = '>= 1.9'
|
19
|
+
s.platform = 'ruby'
|
20
|
+
|
21
|
+
s.add_runtime_dependency('rex', '~> 2.0.5', '>= 2.0.5')
|
22
|
+
|
23
|
+
s.add_development_dependency('bundler', '~> 1.3')
|
24
|
+
end
|
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.
|
4
|
+
version: 0.9.0
|
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-12-
|
14
|
+
date: 2014-12-31 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rex
|
@@ -19,40 +19,20 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 2.0.
|
22
|
+
version: 2.0.5
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: 2.0.
|
25
|
+
version: 2.0.5
|
26
26
|
type: :runtime
|
27
27
|
prerelease: false
|
28
28
|
version_requirements: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 2.0.
|
32
|
+
version: 2.0.5
|
33
33
|
- - ">="
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: 2.0.
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: nokogiri
|
38
|
-
requirement: !ruby/object:Gem::Requirement
|
39
|
-
requirements:
|
40
|
-
- - "~>"
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '1.6'
|
43
|
-
- - ">="
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 1.6.2
|
46
|
-
type: :runtime
|
47
|
-
prerelease: false
|
48
|
-
version_requirements: !ruby/object:Gem::Requirement
|
49
|
-
requirements:
|
50
|
-
- - "~>"
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: '1.6'
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: 1.6.2
|
35
|
+
version: 2.0.5
|
56
36
|
- !ruby/object:Gem::Dependency
|
57
37
|
name: bundler
|
58
38
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,7 +72,7 @@ files:
|
|
92
72
|
- lib/nexpose/common.rb
|
93
73
|
- lib/nexpose/connection.rb
|
94
74
|
- lib/nexpose/console.rb
|
95
|
-
- lib/nexpose/
|
75
|
+
- lib/nexpose/credential.rb
|
96
76
|
- lib/nexpose/dag.rb
|
97
77
|
- lib/nexpose/data_table.rb
|
98
78
|
- lib/nexpose/device.rb
|
@@ -112,10 +92,11 @@ files:
|
|
112
92
|
- lib/nexpose/role.rb
|
113
93
|
- lib/nexpose/scan.rb
|
114
94
|
- lib/nexpose/scan_template.rb
|
115
|
-
- lib/nexpose/
|
95
|
+
- lib/nexpose/shared_credential.rb
|
116
96
|
- lib/nexpose/silo.rb
|
117
97
|
- lib/nexpose/silo_profile.rb
|
118
98
|
- lib/nexpose/site.rb
|
99
|
+
- lib/nexpose/site_credential.rb
|
119
100
|
- lib/nexpose/tag.rb
|
120
101
|
- lib/nexpose/tag/criteria.rb
|
121
102
|
- lib/nexpose/ticket.rb
|
@@ -124,6 +105,7 @@ files:
|
|
124
105
|
- lib/nexpose/version.rb
|
125
106
|
- lib/nexpose/vuln.rb
|
126
107
|
- lib/nexpose/vuln_exception.rb
|
108
|
+
- nexpose.gemspec
|
127
109
|
homepage: https://github.com/rapid7/nexpose-client
|
128
110
|
licenses:
|
129
111
|
- BSD
|
@@ -144,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
126
|
version: '0'
|
145
127
|
requirements: []
|
146
128
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.4.
|
129
|
+
rubygems_version: 2.4.5
|
148
130
|
signing_key:
|
149
131
|
specification_version: 4
|
150
132
|
summary: Ruby API for Rapid7 Nexpose
|