nexpose_cyberark 0.0.8-java → 0.0.9-java
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 +4 -4
- data/bin/nx_cyberark.rb +9 -40
- data/lib/nexpose_cyberark.rb +0 -195
- data/lib/nexpose_cyberark/version.rb +10 -1
- metadata +19 -39
- data/lib/nexpose_cyberark/config/nexpose_cyberark.config +0 -30
- data/lib/nexpose_cyberark/lib/java/JavaPasswordSDK.jar +0 -0
- data/lib/nexpose_cyberark/nexpose_ops.rb +0 -100
- data/lib/nexpose_cyberark/nx_logger.rb +0 -166
- data/lib/nexpose_cyberark/password_ops.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f2c6964971a551e42241ec895f6de3358b07418
|
4
|
+
data.tar.gz: 5a3d0290c167bd34147d565273ecd75c8063bde0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b62fdd317e6e9fe7dd67479475fc9c16364fbee1a7e5287dbe13c20b038deef7baf9eeec619bec21ee2a3ee369f4099a9043d34670bba297c7b475e644ddeedc
|
7
|
+
data.tar.gz: 1804e438104685d865525f300d385a6b062bd83c1f8ceeb91e384b19a58b0f5ef1386259afb1a1005188e41090c5bde7bd1f4e73ddf5d1e2cf9e9eef4797f6b8
|
data/bin/nx_cyberark.rb
CHANGED
@@ -1,42 +1,11 @@
|
|
1
|
-
|
2
|
-
# Nexpose Cyberark Integration
|
3
|
-
# Please refer to the configuration documentation for instructions on how to run this gem
|
4
|
-
# Do NOT run this gem without proper pre-configuration.
|
5
|
-
require 'nexpose_cyberark'
|
6
|
-
require 'nexpose_cyberark/version'
|
7
|
-
require 'nexpose_cyberark/nx_logger'
|
8
|
-
require 'yaml'
|
9
|
-
|
10
|
-
CONFIG_PATH = File.join(File.dirname(__FILE__), '../lib/nexpose_cyberark/config/nexpose_cyberark.config')
|
11
|
-
|
12
|
-
# Obtain Nexpose settings from Environment Variables.
|
13
|
-
configuration_settings = begin
|
14
|
-
YAML.load_file(CONFIG_PATH)
|
15
|
-
rescue ArgumentError => e
|
16
|
-
raise "Could not parse YAML #{CONFIG_PATH} : #{e.message}"
|
17
|
-
end
|
18
|
-
|
19
|
-
raise 'Must configure nexpose settings before starting' if ENV['NEXPOSE_URL'].nil? || ENV['NEXPOSE_USERNAME'].nil? || ENV['NEXPOSE_PASSWORD'].nil?
|
20
|
-
configuration_settings[:nexpose_address] = ENV['NEXPOSE_URL']
|
21
|
-
configuration_settings[:nexpose_port] = ENV['NEXPOSE_PORT']
|
22
|
-
configuration_settings[:nexpose_username] = ENV['NEXPOSE_USERNAME']
|
23
|
-
configuration_settings[:nexpose_password] = ENV['NEXPOSE_PASSWORD']
|
1
|
+
#! /usr/bin/env ruby
|
24
2
|
|
3
|
+
###################
|
4
|
+
#
|
5
|
+
# STOP. THIS GEM HAS BEEN DEPRECATED. NO CHANGES SHOULD BE MADE TO THIS CODE ANYMORE.
|
6
|
+
#
|
7
|
+
###################
|
8
|
+
require 'nexpose_cyberark/version'
|
25
9
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
vault_options = { :app_id => configuration_settings[:ca_options][:app_id], :safe => configuration_settings[:ca_options][:safe], :folder => configuration_settings[:ca_options][:folder] }
|
30
|
-
nexpose_options = { :nxip => configuration_settings[:nexpose_address],
|
31
|
-
:nxport => configuration_settings[:nexpose_port],
|
32
|
-
:nxuser => configuration_settings[:nexpose_username],
|
33
|
-
:nxpassword => configuration_settings[:nexpose_password],
|
34
|
-
:sites => configuration_settings[:ca_options][:sites],
|
35
|
-
:windows_policy_ids => configuration_settings[:ca_options][:windows_policy_ids],
|
36
|
-
:unix_policy_ids => configuration_settings[:ca_options][:unix_policy_ids],
|
37
|
-
:logging => configuration_settings[:ca_options][:logging],
|
38
|
-
:log_level => configuration_settings[:ca_options][:log_level]}
|
39
|
-
NexposeCyberark::Vault.update_credentials(vault_options, nexpose_options)
|
40
|
-
NexposeCyberark::Vault.start_scans(nexpose_options) if configuration_settings[:ca_options][:start_scans].casecmp('y') == 0
|
41
|
-
log = NexposeCyberark::NxLogger.instance
|
42
|
-
log.log_message('Importing credentials complete. Exiting...')
|
10
|
+
puts NexposeCyberark::DEPRECATION_NOTICE
|
11
|
+
raise RuntimeError
|
data/lib/nexpose_cyberark.rb
CHANGED
@@ -1,199 +1,4 @@
|
|
1
|
-
Dir[File.dirname(__FILE__)+'/nexpose_cyberark/lib/java/*.jar'].each { |jar| require jar }
|
2
|
-
require 'nexpose_cyberark/password_ops'
|
3
|
-
require 'nexpose_cyberark/nexpose_ops'
|
4
1
|
require 'nexpose_cyberark/version'
|
5
|
-
require 'waitutil'
|
6
|
-
require 'resolv'
|
7
2
|
|
8
3
|
module NexposeCyberark
|
9
|
-
module Vault
|
10
|
-
|
11
|
-
def self.update_credentials(vault_options, nexpose_options = nil)
|
12
|
-
#Setup logger
|
13
|
-
@log = NexposeCyberark::NxLogger.instance
|
14
|
-
|
15
|
-
log_enabled = nexpose_options[:logging].downcase.start_with? 'y'
|
16
|
-
@log.setup_statistics_collection(NexposeCyberark::VENDOR,
|
17
|
-
NexposeCyberark::PRODUCT_NAME,
|
18
|
-
NexposeCyberark::VERSION)
|
19
|
-
@log.setup_logging(log_enabled, nexpose_options[:log_level] || 'info')
|
20
|
-
|
21
|
-
@nx = Ops::Nexpose.new(nexpose_options[:nxip], nexpose_options[:nxport], nexpose_options[:nxuser], nexpose_options[:nxpassword])
|
22
|
-
@log.log_message('Connection to the Nexpose console complete!')
|
23
|
-
|
24
|
-
# Parse sites from config
|
25
|
-
nexpose_options[:sites].each do |site_id|
|
26
|
-
# Get included scan targets
|
27
|
-
site_scan_target_addresses = @nx.get_site_scan_target_addresses(site_id)
|
28
|
-
|
29
|
-
|
30
|
-
# We now have all Nexpose scan targets. Defined scan targets can be IP/Host where
|
31
|
-
# devices that have been scanned before will be an IP. Get the scan targets & subtract
|
32
|
-
# the defined devices to produce a list of new devices to be scanned.
|
33
|
-
|
34
|
-
# Nexpose site credentials expect the credential to match the scan target which may not be the IP.
|
35
|
-
site_devices = @nx.get_site_devices(site_id)
|
36
|
-
|
37
|
-
all_asset_details = []
|
38
|
-
site_devices.each { |device|
|
39
|
-
# Start by getting all the details we have on current devices
|
40
|
-
asset = @nx.load_asset(device.id)
|
41
|
-
asset_details= {}
|
42
|
-
asset_details[:address] = device.address
|
43
|
-
asset_details[:host_names] = asset.host_names
|
44
|
-
asset_details[:os_name] = [asset.os_name]
|
45
|
-
|
46
|
-
|
47
|
-
# Next subtract the defined assets from the defined scan targets to get devices never scanned before.
|
48
|
-
# Also monitor the deleted identifier. We need to remember this to sync the credential to the site for scanning.
|
49
|
-
scan_target_idq = site_scan_target_addresses.delete(device.address)
|
50
|
-
asset_details[:scan_target_idq] = scan_target_idq unless scan_target_idq.nil?
|
51
|
-
asset.host_names.each do |host_name|
|
52
|
-
scan_target_idq = site_scan_target_addresses.delete(host_name)
|
53
|
-
asset_details[:scan_target_idq] = scan_target_idq unless scan_target_idq.nil?
|
54
|
-
end unless asset.host_names.nil?
|
55
|
-
# Handle the case that a device may have been scanned before but is no longer in the scan target list.
|
56
|
-
# in this case we do not add it to the list of assets to import credentials for (think old sites with many inactive devices)
|
57
|
-
# asset_details[:scan_target_idq] = asset_details[:address] if asset_details[:scan_target_idq].nil?
|
58
|
-
if asset_details[:scan_target_idq].nil?
|
59
|
-
@log.log_warn_message("Found a site device not in the scan target list. Not fetching credentials for address <#{asset_details[:address]}>")
|
60
|
-
else
|
61
|
-
all_asset_details << asset_details
|
62
|
-
end
|
63
|
-
}
|
64
|
-
|
65
|
-
#Start by trying to get credentials for defined assets.
|
66
|
-
@log.log_message('Starting to query CyberArk for defined asset credentials...')
|
67
|
-
site_credentials = []
|
68
|
-
credential_data = nil
|
69
|
-
all_asset_details.each do |asset_details|
|
70
|
-
#The address stored in the vault could be any of the values we have.. so try and find it!
|
71
|
-
vault_options[:address] = asset_details[:address]
|
72
|
-
vault_options[:nexpose_os] = asset_details[:os_name]
|
73
|
-
credential_data = PasswordOps::get_password(nexpose_options, vault_options)
|
74
|
-
|
75
|
-
if credential_data.empty?
|
76
|
-
@log.log_debug_message("Failed to fetch credential for IP <#{asset_details[:address]}>")
|
77
|
-
# No credential for the IP. Let's check if Nexpose has any hostnames and if these match credentials
|
78
|
-
# within CyberArk. If they do not then try and resolve one from the IP.
|
79
|
-
if asset_details[:host_names].nil?
|
80
|
-
asset_details[:host_names] = resolve_address(asset_details[:address])
|
81
|
-
end
|
82
|
-
|
83
|
-
@log.log_debug_message("Trying to fetch credentials for resolved addresses <#{asset_details[:address]}> instead...")
|
84
|
-
|
85
|
-
asset_details[:host_names].each do |hostname|
|
86
|
-
vault_options[:address] = hostname
|
87
|
-
vault_options[:nexpose_os] = asset_details[:os_name]
|
88
|
-
credential_data = PasswordOps::get_password(nexpose_options, vault_options)
|
89
|
-
break unless credential_data.empty?
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
if credential_data.empty?
|
94
|
-
@log.log_error_message("Failed to get credential for asset with IP <#{asset_details[:address]}> and names <#{asset_details[:host_names]}>. Please check configuration!!!")
|
95
|
-
else
|
96
|
-
credential = @nx.credential_for_service(asset_details[:scan_target_idq], nil, "Automated import for Nexpose scan target <#{asset_details[:scan_target_idq]}> and CyberArk credential <#{vault_options[:address]}>", asset_details[:scan_target_idq], nil, credential_data[:service])
|
97
|
-
credential.user_name = credential_data[:user]
|
98
|
-
credential.password = credential_data[:password]
|
99
|
-
# Only Linux SUDO support currently
|
100
|
-
credential.permission_elevation_user = credential_data[:p_e_user] unless credential_data[:p_e_user].nil?
|
101
|
-
credential.permission_elevation_password = credential_data[:password] unless credential_data[:password].nil?
|
102
|
-
credential.permission_elevation_type = credential_data[:p_e_type]
|
103
|
-
site_credentials.push(credential)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
@log.log_message('Starting to query CyberArk for new scan target credentials...')
|
108
|
-
|
109
|
-
# Now let's deal with assets that have never been scanned.
|
110
|
-
# These are more difficult as we only have the scan target address (whatever that may be).
|
111
|
-
site_scan_target_addresses.each do |address|
|
112
|
-
vault_options[:address] = address
|
113
|
-
credential_data = PasswordOps::get_password(nexpose_options, vault_options)
|
114
|
-
|
115
|
-
if credential_data.empty?
|
116
|
-
@log.log_debug_message("Failed to fetch credential for IP <#{address}>")
|
117
|
-
other_addresses = resolve_address(address)
|
118
|
-
@log.log_debug_message("Trying to fetch credentials for resolved addresses <#{other_addresses}> instead...")
|
119
|
-
other_addresses.each do |other_address|
|
120
|
-
vault_options[:address] = other_address
|
121
|
-
credential_data = PasswordOps::get_password(nexpose_options, vault_options)
|
122
|
-
break unless credential_data.empty?
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
if credential_data.empty?
|
127
|
-
@log.log_error_message("Failed to get credential for asset with IP <#{address}> and names <#{other_addresses}>. Please check configuration!!!")
|
128
|
-
else
|
129
|
-
credential = @nx.credential_for_service(address, nil, "Automated import for Nexpose scan target <#{address}> and CyberArk credential <#{vault_options[:address]}>",address, nil, credential_data[:service])
|
130
|
-
credential.user_name = credential_data[:user]
|
131
|
-
credential.password = credential_data[:password]
|
132
|
-
#Only Linux SUDO support currently
|
133
|
-
credential.permission_elevation_user = credential_data[:p_e_user] unless credential_data[:p_e_user].nil?
|
134
|
-
credential.permission_elevation_password = credential_data[:password] unless credential_data[:password].nil?
|
135
|
-
credential.permission_elevation_type = credential_data[:p_e_type]
|
136
|
-
site_credentials.push(credential)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
@log.log_message("Saving credentials for site <#{site_id}>. Number of credentials to be saved <#{site_credentials.size}>.")
|
140
|
-
# Save site
|
141
|
-
@nx.save_site(site_id, site_credentials)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.start_scans(nexpose_options = nil)
|
146
|
-
@nx = Ops::Nexpose.new(nexpose_options[:nxip], nexpose_options[:nxport], nexpose_options[:nxuser], nexpose_options[:nxpassword])
|
147
|
-
all_site_scan_details = []
|
148
|
-
nexpose_options[:sites].each do |site_id|
|
149
|
-
scan = @nx.start_scan(site_id)
|
150
|
-
if scan.nil?
|
151
|
-
@log.log_error_message("Failed to start scan for site <#{site_id}>!")
|
152
|
-
next
|
153
|
-
end
|
154
|
-
@log.log_message("Started scan for site <#{site_id}>. Scan ID is <#{scan.id}>.")
|
155
|
-
site_scan_details = {}
|
156
|
-
site_scan_details[:site_id] = site_id
|
157
|
-
site_scan_details[:scan_id] = scan.id
|
158
|
-
all_site_scan_details << site_scan_details
|
159
|
-
end
|
160
|
-
|
161
|
-
WaitUtil.wait_for_condition('wait_for_all_scans_to_finish', :timeout_sec => 10800, :delay_sec => 60) do
|
162
|
-
@completed = false
|
163
|
-
all_site_scan_details.delete_if do |site_scan_details|
|
164
|
-
status = @nx.scan_status(site_scan_details[:scan_id])
|
165
|
-
@log.log_debug_message("Scan status for scan ID <#{site_scan_details[:scan_id]}> is <#{status}>.")
|
166
|
-
if status == Scan::Status::RUNNING
|
167
|
-
@log.log_debug_message("Waiting for scan <#{site_scan_details[:scan_id]}> for site <#{site_scan_details[:site_id]}> to finish.")
|
168
|
-
false
|
169
|
-
else
|
170
|
-
@log.log_message("Scan <#{site_scan_details[:scan_id]}> for site <#{site_scan_details[:scan_id]}> finished. Removing credentials")
|
171
|
-
@nx.delete_site_credentials(site_scan_details[:site_id])
|
172
|
-
true
|
173
|
-
end
|
174
|
-
end
|
175
|
-
@completed = true if all_site_scan_details.empty?
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def self.resolve_address(address)
|
180
|
-
is_ip = !!((address =~ Resolv::IPv4::Regex) || (address =~ Resolv::IPv6::Regex))
|
181
|
-
resolved_addresses = []
|
182
|
-
@log.log_debug_message("Resolving address <#{address}>.")
|
183
|
-
begin
|
184
|
-
if is_ip
|
185
|
-
resolved_addresses = Resolv.getnames address
|
186
|
-
@log.log_debug_message("Address <#{address}> is an IP. Resolved names are <#{resolved_addresses}>.")
|
187
|
-
else
|
188
|
-
resolved_addresses = Resolv.getaddress address
|
189
|
-
@log.log_debug_message("Address <#{address}> is a name. Resolved IPs are <#{resolved_addresses}>.")
|
190
|
-
end
|
191
|
-
resolved_addresses = [resolved_addresses] unless resolved_addresses.kind_of?(Array)
|
192
|
-
rescue Resolv::ResolvError => e
|
193
|
-
@log.log_error_message("Unable to resolve address <#{address}>. Error was <#{e}>")
|
194
|
-
end
|
195
|
-
return resolved_addresses
|
196
|
-
end
|
197
|
-
|
198
|
-
end
|
199
4
|
end
|
@@ -1,5 +1,14 @@
|
|
1
1
|
module NexposeCyberark
|
2
|
-
VERSION = "0.0.
|
2
|
+
VERSION = "0.0.9"
|
3
3
|
VENDOR = "Cyberark"
|
4
4
|
PRODUCT_NAME = "nexpose_cyberark"
|
5
|
+
DEPRECATION_NOTICE = <<-DEPRECATION
|
6
|
+
As of March 4th, 2019, the CyberArk Ruby Gem has been deprecated and is no longer
|
7
|
+
available for use. An updated integration is currently available in product,
|
8
|
+
the setup instructions of which can be found here:
|
9
|
+
https://insightvm.help.rapid7.com/docs/creating-and-managing-cyberark-credentials
|
10
|
+
|
11
|
+
For more information please see our announcement which can be found here:
|
12
|
+
https://kb.help.rapid7.com/v1.1/docs/legacy-cyberark-ruby-gem-end-of-life-announcement
|
13
|
+
DEPRECATION
|
5
14
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexpose_cyberark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Damian Finol
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-03-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -53,36 +53,14 @@ dependencies:
|
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '2.1'
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - "~>"
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '2.1'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: waitutil
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - "~>"
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0.2'
|
77
|
-
type: :runtime
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - "~>"
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '0.2'
|
84
|
-
description: Nexpose Cyberark integration provides credentials for authenticated scans
|
85
|
-
in Nexpose.
|
56
|
+
description: |
|
57
|
+
As of March 4th, 2019, the CyberArk Ruby Gem has been deprecated and is no longer
|
58
|
+
available for use. An updated integration is currently available in product,
|
59
|
+
the setup instructions of which can be found here:
|
60
|
+
https://insightvm.help.rapid7.com/docs/creating-and-managing-cyberark-credentials
|
61
|
+
|
62
|
+
For more information please see our announcement which can be found here:
|
63
|
+
https://kb.help.rapid7.com/v1.1/docs/legacy-cyberark-ruby-gem-end-of-life-announcement
|
86
64
|
email:
|
87
65
|
- support@rapid7.com
|
88
66
|
executables:
|
@@ -96,17 +74,19 @@ files:
|
|
96
74
|
- Rakefile
|
97
75
|
- bin/nx_cyberark.rb
|
98
76
|
- lib/nexpose_cyberark.rb
|
99
|
-
- lib/nexpose_cyberark/config/nexpose_cyberark.config
|
100
|
-
- lib/nexpose_cyberark/lib/java/JavaPasswordSDK.jar
|
101
|
-
- lib/nexpose_cyberark/nexpose_ops.rb
|
102
|
-
- lib/nexpose_cyberark/nx_logger.rb
|
103
|
-
- lib/nexpose_cyberark/password_ops.rb
|
104
77
|
- lib/nexpose_cyberark/version.rb
|
105
78
|
homepage: http://www.rapid7.com/
|
106
79
|
licenses:
|
107
80
|
- MIT
|
108
81
|
metadata: {}
|
109
|
-
post_install_message:
|
82
|
+
post_install_message: |
|
83
|
+
As of March 4th, 2019, the CyberArk Ruby Gem has been deprecated and is no longer
|
84
|
+
available for use. An updated integration is currently available in product,
|
85
|
+
the setup instructions of which can be found here:
|
86
|
+
https://insightvm.help.rapid7.com/docs/creating-and-managing-cyberark-credentials
|
87
|
+
|
88
|
+
For more information please see our announcement which can be found here:
|
89
|
+
https://kb.help.rapid7.com/v1.1/docs/legacy-cyberark-ruby-gem-end-of-life-announcement
|
110
90
|
rdoc_options: []
|
111
91
|
require_paths:
|
112
92
|
- lib
|
@@ -122,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
102
|
version: '0'
|
123
103
|
requirements: []
|
124
104
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.5.
|
105
|
+
rubygems_version: 2.5.2.3
|
126
106
|
signing_key:
|
127
107
|
specification_version: 4
|
128
108
|
summary: Nexpose Cyberark integration.
|
@@ -1,30 +0,0 @@
|
|
1
|
-
---
|
2
|
-
# This configuration file defines all the particular options necessary to run the service.
|
3
|
-
# Fields marked (M) are mandatory.
|
4
|
-
#
|
5
|
-
# Service options:
|
6
|
-
:ca_options:
|
7
|
-
# Vault Options
|
8
|
-
# App ID
|
9
|
-
:app_id: my_app_id
|
10
|
-
# Safe
|
11
|
-
:safe: my_safe
|
12
|
-
# Folder
|
13
|
-
:folder: my_folder
|
14
|
-
# This setting will start scans on those sites, wait for the site to complete and then remove the credentials
|
15
|
-
# If you prefer to let the scans run on schedule, set this to 'N', otherwise set to 'Y'.
|
16
|
-
:start_scans: 'Y'
|
17
|
-
# CyberArk policy IDs that apply to assets that will require a CIFS connection for authenticated scanning
|
18
|
-
:windows_policy_ids:
|
19
|
-
- 'WinServerLocal'
|
20
|
-
# CyberArk policy IDs that apply to assets that will require an SSH connection for authenticated scanning
|
21
|
-
:unix_policy_ids:
|
22
|
-
- 'UnixSSH'
|
23
|
-
# Nexpose sites to import CyberArk credentials for.
|
24
|
-
:sites:
|
25
|
-
- '1'
|
26
|
-
# - '2'
|
27
|
-
# Enable or disable logging ('N' or 'Y'.)
|
28
|
-
:logging: 'Y'
|
29
|
-
#Support version are 'info' and 'debug'
|
30
|
-
:log_level: 'info'
|
Binary file
|
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'nexpose'
|
2
|
-
include Nexpose
|
3
|
-
|
4
|
-
module Ops
|
5
|
-
class Nexpose
|
6
|
-
attr_accessor :nsc
|
7
|
-
def initialize(nxip, nxport, nxuser, nxpasword)
|
8
|
-
@log = NexposeCyberark::NxLogger.instance
|
9
|
-
@log.log_message('Connecting to the Nexpose console..')
|
10
|
-
@nsc = Connection.new(nxip, nxuser, nxpasword, nxport)
|
11
|
-
@nsc.login
|
12
|
-
@log.on_connect(nxip, nxport, @nsc.session_id, '{}')
|
13
|
-
end
|
14
|
-
|
15
|
-
def get_site_scan_targets(site_id)
|
16
|
-
@log.log_debug_message("Fetching list of scan targets for site <#{site_id}> from console")
|
17
|
-
site = Site.load(@nsc, site_id)
|
18
|
-
site.included_addresses
|
19
|
-
end
|
20
|
-
|
21
|
-
def get_site_scan_target_addresses(site_id)
|
22
|
-
@log.log_debug_message("Fetching list of scan targets addresses for site <#{site_id}>")
|
23
|
-
site_scan_targets = get_site_scan_targets(site_id)
|
24
|
-
@log.log_message('Console returned scan targets!')
|
25
|
-
|
26
|
-
site_scan_target_addresses = []
|
27
|
-
#Convert this to a list of only addresses
|
28
|
-
site_scan_targets.each do |scan_target|
|
29
|
-
host = scan_target.host if scan_target.is_a?(HostName)
|
30
|
-
host = scan_target.from if scan_target.is_a?(IPRange)
|
31
|
-
|
32
|
-
range_scenario = false
|
33
|
-
range_scenario = true if scan_target.is_a?(IPRange)
|
34
|
-
|
35
|
-
if range_scenario
|
36
|
-
start_ip = IPAddr.new(scan_target.from)
|
37
|
-
end_ip = IPAddr.new(scan_target.to) unless scan_target.to.nil?
|
38
|
-
end_ip = IPAddr.new(scan_target.from) if scan_target.to.nil?
|
39
|
-
site_scan_target_addresses.concat (start_ip..end_ip).map(&:to_s)
|
40
|
-
else
|
41
|
-
site_scan_target_addresses << host
|
42
|
-
end
|
43
|
-
end
|
44
|
-
@log.log_debug_message('Processed scan targets. Returning addresses.')
|
45
|
-
return site_scan_target_addresses
|
46
|
-
end
|
47
|
-
|
48
|
-
def get_site_devices(site_id)
|
49
|
-
@log.log_debug_message("Fetching list of devices for site <#{site_id}>")
|
50
|
-
@nsc.list_site_devices(site_id)
|
51
|
-
end
|
52
|
-
|
53
|
-
def load_asset(device_id)
|
54
|
-
@log.log_debug_message("Fetching asset details for asset <#{device_id}>")
|
55
|
-
Asset.load(@nsc, device_id)
|
56
|
-
end
|
57
|
-
|
58
|
-
def credential_for_service(address, id, description, host, port, service)
|
59
|
-
@log.log_debug_message("Generating credential for address <#{address}>")
|
60
|
-
SiteCredentials.for_service(address, id, description, host, port, service)
|
61
|
-
end
|
62
|
-
|
63
|
-
def save_site(site_id, credentials)
|
64
|
-
@log.log_debug_message("Saving <#{credentials.size}> credentials for site <#{site_id}>")
|
65
|
-
site = Site.load(@nsc, site_id)
|
66
|
-
site.site_credentials = credentials
|
67
|
-
site.save(@nsc)
|
68
|
-
end
|
69
|
-
|
70
|
-
def delete_site_credentials(site_id)
|
71
|
-
@log.log_debug_message("Deleting existing credentials for site <#{site_id}>")
|
72
|
-
site = Site.load(@nsc, site_id)
|
73
|
-
site.site_credentials.clear
|
74
|
-
site.save(@nsc)
|
75
|
-
end
|
76
|
-
|
77
|
-
def load_site(site_id)
|
78
|
-
@log.log_debug_message("Fetching details for site <#{site_id}>")
|
79
|
-
Site.load(@nsc, site_id)
|
80
|
-
end
|
81
|
-
|
82
|
-
def start_scan(site_id)
|
83
|
-
@log.log_debug_message("Starting for site <#{site_id}>")
|
84
|
-
scan_details = nil
|
85
|
-
begin
|
86
|
-
site = load_site(site_id)
|
87
|
-
scan_details = site.scan(@nsc)
|
88
|
-
rescue Exception => e
|
89
|
-
@log.log_error_message("Failed to start scan for site <#{site_id}>. Error is <#{e}>")
|
90
|
-
end
|
91
|
-
scan_details
|
92
|
-
end
|
93
|
-
|
94
|
-
def scan_status(scan_id)
|
95
|
-
status = @nsc.scan_status(scan_id)
|
96
|
-
@log.log_debug_message("Scan status for scan ID <#{scan_id}> is <#{status}>.")
|
97
|
-
status
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,166 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'json'
|
3
|
-
require 'net/http'
|
4
|
-
require 'singleton'
|
5
|
-
|
6
|
-
module NexposeCyberark
|
7
|
-
class NxLogger
|
8
|
-
include Singleton
|
9
|
-
LOG_PATH = "./logs/rapid7_%s.log"
|
10
|
-
KEY_FORMAT = "external.integration.%s"
|
11
|
-
PRODUCT_FORMAT = "%s_%s"
|
12
|
-
|
13
|
-
DEFAULT_LOG = 'integration'
|
14
|
-
PRODUCT_RANGE = 4..30
|
15
|
-
KEY_RANGE = 3..15
|
16
|
-
|
17
|
-
ENDPOINT = '/data/external/statistic/'
|
18
|
-
|
19
|
-
def initialize()
|
20
|
-
create_calls
|
21
|
-
@logger_file = get_log_path @product
|
22
|
-
setup_logging(true, 'info')
|
23
|
-
end
|
24
|
-
|
25
|
-
def setup_statistics_collection(vendor, product_name, gem_version)
|
26
|
-
begin
|
27
|
-
@statistic_key = get_statistic_key vendor
|
28
|
-
@product = get_product product_name, gem_version
|
29
|
-
rescue => e
|
30
|
-
#Continue
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def setup_logging(enabled, log_level = 'info', stdout=false)
|
35
|
-
@stdout = stdout
|
36
|
-
|
37
|
-
log_message('Logging disabled.') unless enabled || @log.nil?
|
38
|
-
@enabled = enabled
|
39
|
-
return unless @enabled
|
40
|
-
|
41
|
-
@logger_file = get_log_path @product
|
42
|
-
|
43
|
-
require 'logger'
|
44
|
-
directory = File.dirname(@logger_file)
|
45
|
-
FileUtils.mkdir_p(directory) unless File.directory?(directory)
|
46
|
-
io = IO.for_fd(IO.sysopen(@logger_file, 'a'), 'a')
|
47
|
-
io.autoclose = false
|
48
|
-
io.sync = true
|
49
|
-
@log = Logger.new(io, 'weekly')
|
50
|
-
@log.level = if log_level.to_s.casecmp('info') == 0
|
51
|
-
Logger::INFO
|
52
|
-
else
|
53
|
-
Logger::DEBUG
|
54
|
-
end
|
55
|
-
log_message("Logging enabled at level <#{log_level}>")
|
56
|
-
end
|
57
|
-
|
58
|
-
def create_calls
|
59
|
-
levels = [:info, :debug, :error, :warn]
|
60
|
-
levels.each do |level|
|
61
|
-
method_name =
|
62
|
-
define_singleton_method("log_#{level.to_s}_message") do |message|
|
63
|
-
puts message if @stdout
|
64
|
-
@log.send(level, message) unless !@enabled || @log.nil?
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def log_message(message)
|
70
|
-
log_info_message message
|
71
|
-
end
|
72
|
-
|
73
|
-
def log_stat_message(message)
|
74
|
-
end
|
75
|
-
|
76
|
-
def get_log_path(product)
|
77
|
-
product.downcase! unless product.nil?
|
78
|
-
File.join(File.dirname(__FILE__), LOG_PATH % (product || DEFAULT_LOG))
|
79
|
-
end
|
80
|
-
|
81
|
-
def get_statistic_key(vendor)
|
82
|
-
if vendor.nil? || vendor.length < KEY_RANGE.min
|
83
|
-
log_stat_message("Vendor length is below minimum of <#{KEY_RANGE}>")
|
84
|
-
return nil
|
85
|
-
end
|
86
|
-
|
87
|
-
vendor.gsub!('-', '_')
|
88
|
-
vendor.slice! vendor.rindex('_') until vendor.count('_') <= 1
|
89
|
-
|
90
|
-
vendor.delete! "^A-Za-z0-9\_"
|
91
|
-
|
92
|
-
KEY_FORMAT % vendor[0...KEY_RANGE.max].downcase
|
93
|
-
end
|
94
|
-
|
95
|
-
def get_product(product, version)
|
96
|
-
return nil if ((product.nil? || product.empty?) ||
|
97
|
-
(version.nil? || version.empty?))
|
98
|
-
|
99
|
-
product.gsub!('-', '_')
|
100
|
-
product.slice! product.rindex('_') until product.count('_') <= 1
|
101
|
-
|
102
|
-
product.delete! "^A-Za-z0-9\_"
|
103
|
-
version.delete! "^A-Za-z0-9\.\-"
|
104
|
-
|
105
|
-
product = (PRODUCT_FORMAT % [product, version])[0...PRODUCT_RANGE.max]
|
106
|
-
|
107
|
-
product.slice! product.rindex(/[A-Z0-9]/i)+1..-1
|
108
|
-
|
109
|
-
if product.length < PRODUCT_RANGE.min
|
110
|
-
log_stat_message("Product length below minimum <#{PRODUCT_RANGE.min}>.")
|
111
|
-
return nil
|
112
|
-
end
|
113
|
-
product.downcase
|
114
|
-
end
|
115
|
-
|
116
|
-
def generate_payload(statistic_value='')
|
117
|
-
product_name, separator, version = @product.to_s.rpartition('_')
|
118
|
-
payload_value = {'version' => version}.to_json
|
119
|
-
|
120
|
-
payload = {'statistic-key' => @statistic_key.to_s,
|
121
|
-
'statistic-value' => payload_value,
|
122
|
-
'product' => product_name}
|
123
|
-
JSON.generate(payload)
|
124
|
-
end
|
125
|
-
|
126
|
-
def send(nexpose_address, nexpose_port, session_id, payload)
|
127
|
-
header = {'Content-Type' => 'application/json',
|
128
|
-
'nexposeCCSessionID' => session_id,
|
129
|
-
'Cookie' => "nexposeCCSessionID=#{session_id}"}
|
130
|
-
req = Net::HTTP::Put.new(ENDPOINT, header)
|
131
|
-
req.body = payload
|
132
|
-
http_instance = Net::HTTP.new(nexpose_address, nexpose_port)
|
133
|
-
http_instance.use_ssl = true
|
134
|
-
http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
135
|
-
response = http_instance.start { |http| http.request(req) }
|
136
|
-
log_stat_message "Received code #{response.code} from Nexpose console."
|
137
|
-
log_stat_message "Received message #{response.msg} from Nexpose console."
|
138
|
-
log_stat_message 'Finished sending statistics data to Nexpose.'
|
139
|
-
|
140
|
-
response.code
|
141
|
-
end
|
142
|
-
|
143
|
-
def on_connect(nexpose_address, nexpose_port, session_id, value)
|
144
|
-
log_stat_message 'Sending statistics data to Nexpose'
|
145
|
-
|
146
|
-
if @product.nil? || @statistic_key.nil?
|
147
|
-
log_stat_message('Invalid product name and/or statistics key.')
|
148
|
-
log_stat_message('Statistics collection not enabled.')
|
149
|
-
return
|
150
|
-
end
|
151
|
-
|
152
|
-
begin
|
153
|
-
payload = generate_payload value
|
154
|
-
send(nexpose_address, nexpose_port, session_id, payload)
|
155
|
-
rescue => e
|
156
|
-
#Let the program continue
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
#Used by net library for debugging
|
161
|
-
def <<(value)
|
162
|
-
log_debug_message(value)
|
163
|
-
end
|
164
|
-
|
165
|
-
end
|
166
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module PasswordOps
|
2
|
-
require 'nexpose'
|
3
|
-
include Nexpose
|
4
|
-
def self.cyberark
|
5
|
-
Java::javapasswordsdk
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.get_password(nexpose_options = {}, vault_options = {}, password_req_sdk = nil, password_sdk = nil )
|
9
|
-
@log = NexposeCyberark::NxLogger.instance
|
10
|
-
password_req_sdk = cyberark.PSDKPasswordRequest.new if password_req_sdk.nil?
|
11
|
-
asset_data = {}
|
12
|
-
begin
|
13
|
-
password_req_sdk.set_app_id(vault_options[:app_id])
|
14
|
-
password_req_sdk.set_safe(vault_options[:safe])
|
15
|
-
password_req_sdk.set_folder(vault_options[:folder])
|
16
|
-
password_req_sdk.set_address(vault_options[:address])
|
17
|
-
password_sdk = cyberark.PasswordSDK if password_sdk.nil?
|
18
|
-
password_result = password_sdk.getPassword(password_req_sdk)
|
19
|
-
if nexpose_options[:windows_policy_ids].any?{ |policy| policy.casecmp(password_result.get_policy_id)==0 }
|
20
|
-
if nexpose_options[:unix_policy_ids].any?{ |policy| policy.casecmp(password_result.get_policy_id)==0 }
|
21
|
-
# Has both Windows and Unix policies. Check Nexpose to see if we have an OS listing
|
22
|
-
@log.log_error_message("Asset with credential address <#{vault_options[:address]}> has a conflicting policy configuration! Checking Nexpose fingerprint.. ")
|
23
|
-
if vault_options[:nexpose_os].downcase.include? 'windows'
|
24
|
-
@log.log_debug_message('Nexpose fingerprinting estimates the system is Windows.')
|
25
|
-
asset_data[:service] = Credential::Service::CIFS
|
26
|
-
else
|
27
|
-
@log.log_debug_message('Nexpose fingerprinting estimates the system is Unix based.')
|
28
|
-
asset_data[:service] = Credential::Service::SSH
|
29
|
-
asset_data[:p_e_user] = 'root'
|
30
|
-
asset_data[:p_e_type] = Nexpose::Credential::ElevationType::SUDO
|
31
|
-
end
|
32
|
-
end
|
33
|
-
@log.log_debug_message('Policy ID indicates the system is Windows based.')
|
34
|
-
asset_data[:service] = Credential::Service::CIFS
|
35
|
-
else
|
36
|
-
@log.log_debug_message('Policy ID indicates the system is Unix based.')
|
37
|
-
asset_data[:service] = Credential::Service::SSH
|
38
|
-
asset_data[:p_e_user] = 'root'
|
39
|
-
asset_data[:p_e_type] = Nexpose::Credential::ElevationType::SUDO
|
40
|
-
end
|
41
|
-
asset_data[:password] = password_result.get_content
|
42
|
-
asset_data[:user] = password_result.get_user_name
|
43
|
-
rescue Exception => e
|
44
|
-
@log.log_debug_message("Error fetching credential for address <#{vault_options[:address]}>. Error was <#{e}>")
|
45
|
-
end
|
46
|
-
asset_data
|
47
|
-
end
|
48
|
-
end
|