NexposeRunner 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/NexposeRunner.gemspec +1 -1
- data/bin/scan +15 -10
- data/lib/NexposeRunner/version.rb +1 -1
- data/lib/nexpose-runner/command_line_arg_parser.rb +58 -0
- data/lib/nexpose-runner/constants.rb +14 -0
- data/lib/nexpose-runner/scan.rb +6 -1
- data/lib/nexpose-runner/scan_run_description.rb +5 -2
- data/spec/scan_spec.rb +33 -2
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df40a00a8781da6369dc8747aa6c43326d23e86a
|
4
|
+
data.tar.gz: fad5354e24b58e807648123f4a9e71751732256c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9e28ff3ef5d613251c92c934ec01a5bc25cbb77c962145329135315a6bcce25861b7de39db822c2e48793385f3f630e68637b188cc2b74d255267616f8b8957
|
7
|
+
data.tar.gz: fd2a32764de13f24f2f616f46b41dd0f2a977c29c70bb7984864df7ca4e85455c3296bab8c8699699852f343ac614fc5580ca17d90cd0cbdff12cb3ef7454579
|
data/.gitignore
CHANGED
data/NexposeRunner.gemspec
CHANGED
@@ -21,6 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency 'nexpose', '0.8.3'
|
22
22
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
24
|
-
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rake', '< 11.0'
|
25
25
|
spec.add_development_dependency 'rspec', '3.0.0'
|
26
26
|
end
|
data/bin/scan
CHANGED
@@ -3,13 +3,18 @@
|
|
3
3
|
require 'nexpose-runner/scan'
|
4
4
|
|
5
5
|
$stdout.sync = true
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
|
7
|
+
if ARGV.grep(/^--/).empty?
|
8
|
+
NexposeRunner::Scan.start({
|
9
|
+
'connection_url' => ARGV[0],
|
10
|
+
'username' => ARGV[1],
|
11
|
+
'password' => ARGV[2],
|
12
|
+
'port' => ARGV[3],
|
13
|
+
'site_name' => ARGV[4],
|
14
|
+
'ip_addresses' => ARGV[5],
|
15
|
+
'scan_template' => ARGV[6],
|
16
|
+
'engine' => ARGV[7]
|
17
|
+
})
|
18
|
+
else
|
19
|
+
NexposeRunner::Scan.start(ARGV)
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class CommandLineArgumentParser
|
4
|
+
def self.parse(args)
|
5
|
+
options = {}
|
6
|
+
options['connection_url'] = ''
|
7
|
+
options['username'] = ''
|
8
|
+
options['password'] = ''
|
9
|
+
options['port'] = 0
|
10
|
+
options['site_name'] = ''
|
11
|
+
options['ip_addresses'] = ''
|
12
|
+
options['scan_template'] = ''
|
13
|
+
options['engine'] = ''
|
14
|
+
|
15
|
+
opt_parser = OptionParser.new do |opts|
|
16
|
+
opts.banner = 'Usage: scan [options]'
|
17
|
+
|
18
|
+
opts.separator ''
|
19
|
+
opts.separator 'Specific options:'
|
20
|
+
|
21
|
+
opts.on('--connection-url URL', 'Nexpose Url') do |url|
|
22
|
+
options['connection_url'] = url
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('--username USERNAME', 'Nexpose Login Username') do |username|
|
26
|
+
options['username'] = username
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('--password PASSWORD', 'Nexpose Login Password') do |password|
|
30
|
+
options['password'] = password
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on('--port PORT', 'Nexpose port') do |port|
|
34
|
+
options['port'] = port
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on('--site-name NAME', 'Nexpose site name') do |sitename|
|
38
|
+
options['site_name'] = sitename
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on('--ip-addresses IPS', 'Comma separated list of IP Addresses to scan') do |ips|
|
42
|
+
options['ip_addresses'] = ips
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on('--scan-template TEMPLATE', 'Nexpose scan template to use') do |template|
|
46
|
+
options['scan_template'] = template
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('--engine ENGINE', 'Nexpose scan engine to use') do |engine|
|
50
|
+
options['engine'] = engine
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
opt_parser.parse!(args)
|
56
|
+
options
|
57
|
+
end
|
58
|
+
end
|
@@ -8,6 +8,7 @@ module CONSTANTS
|
|
8
8
|
VULNERABILITY_FOUND_MESSAGE = '---------All YOUR BASE ARE BELONG TO US---------------\nVulnerabilities were found, breaking build'
|
9
9
|
DEFAULT_PORT = '3780'
|
10
10
|
VULNERABILITY_REPORT_NAME = 'nexpose-vulnerability-report.csv'
|
11
|
+
VULNERABILITY_DETAIL_REPORT_NAME = 'nexpose-vulnerability-detail-report.csv'
|
11
12
|
SOFTWARE_REPORT_NAME = 'nexpose-software-report.csv'
|
12
13
|
POLICY_REPORT_NAME = 'nexpose-policy-report.csv'
|
13
14
|
|
@@ -32,6 +33,19 @@ module CONSTANTS
|
|
32
33
|
JOIN dim_vulnerability_solution USING (vulnerability_id)
|
33
34
|
JOIN dim_solution_highest_supercedence USING (solution_id)
|
34
35
|
JOIN dim_solution ds ON superceding_solution_id = ds.solution_id'
|
36
|
+
|
37
|
+
VULNERABILITY_DETAIL_REPORT_QUERY = 'SELECT DISTINCT
|
38
|
+
fasvi.vulnerability_id,
|
39
|
+
da.ip_address,
|
40
|
+
CASE WHEN fasvi.port = -1 THEN NULL ELSE fasvi.port END,
|
41
|
+
dv.title,
|
42
|
+
dv.description,
|
43
|
+
ds.fix
|
44
|
+
FROM fact_asset_scan_vulnerability_instance fasvi
|
45
|
+
JOIN dim_asset da USING (asset_id)
|
46
|
+
JOIN dim_vulnerability dv USING (vulnerability_id)
|
47
|
+
JOIN dim_vulnerability_solution dvs USING (vulnerability_id)
|
48
|
+
JOIN dim_solution ds USING (solution_id)'
|
35
49
|
|
36
50
|
SOFTWARE_REPORT_QUERY = 'SELECT
|
37
51
|
dsi.name,
|
data/lib/nexpose-runner/scan.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'nexpose'
|
2
2
|
require 'csv'
|
3
|
+
require 'json'
|
3
4
|
require 'nexpose-runner/constants'
|
4
5
|
require 'nexpose-runner/scan_run_description'
|
5
6
|
|
6
|
-
|
7
7
|
module NexposeRunner
|
8
8
|
module Scan
|
9
9
|
def Scan.start(options)
|
@@ -26,6 +26,10 @@ module NexposeRunner
|
|
26
26
|
puts "Scan complete for #{run_details.site_name}, Generating Vulnerability Report"
|
27
27
|
vulnerbilities = generate_report(CONSTANTS::VULNERABILITY_REPORT_QUERY, site.id, nsc)
|
28
28
|
generate_csv(vulnerbilities, CONSTANTS::VULNERABILITY_REPORT_NAME)
|
29
|
+
|
30
|
+
puts "Scan complete for #{run_details.site_name}, Generating Vulnerability Detail Report"
|
31
|
+
vuln_details = generate_report(CONSTANTS:: VULNERABILITY_DETAIL_REPORT_QUERY, site.id, nsc)
|
32
|
+
generate_csv(vulnerbilities, CONSTANTS::VULNERABILITY_DETAIL_REPORT_NAME)
|
29
33
|
|
30
34
|
puts "Scan complete for #{run_details.site_name}, Generating Software Report"
|
31
35
|
software = generate_report(CONSTANTS::SOFTWARE_REPORT_QUERY, site.id, nsc)
|
@@ -74,6 +78,7 @@ module NexposeRunner
|
|
74
78
|
end
|
75
79
|
site.save nsc
|
76
80
|
puts "Created site #{run_details.site_name} successfully with the following host(s) #{run_details.ip_addresses.join(', ')}"
|
81
|
+
|
77
82
|
site
|
78
83
|
end
|
79
84
|
|
@@ -1,13 +1,16 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'nexpose-runner/command_line_arg_parser'
|
2
3
|
|
3
4
|
class ScanRunDescription
|
4
5
|
attr_accessor :connection_url, :username, :password, :port, :site_name, :ip_addresses, :scan_template, :engine
|
5
6
|
@@port_value = ''
|
6
|
-
@@ip_addresses =
|
7
|
+
@@ip_addresses = []
|
7
8
|
|
8
9
|
def initialize(options)
|
9
10
|
if File.file?('config/scan.yml')
|
10
11
|
options = YAML.load_file('config/scan.yml')
|
12
|
+
elsif options.instance_of? Array
|
13
|
+
options = CommandLineArgumentParser.parse(options)
|
11
14
|
end
|
12
15
|
|
13
16
|
self.connection_url = options['connection_url']
|
@@ -38,7 +41,7 @@ class ScanRunDescription
|
|
38
41
|
end
|
39
42
|
|
40
43
|
def ip_addresses=(value)
|
41
|
-
@@ip_addresses = value.split(',')
|
44
|
+
@@ip_addresses = value.split(',') unless value.nil?
|
42
45
|
end
|
43
46
|
|
44
47
|
def ip_addresses
|
data/spec/scan_spec.rb
CHANGED
@@ -21,6 +21,7 @@ describe 'nexpose-runner' do
|
|
21
21
|
@expected_site_name = 'my_cool_software_build-28'
|
22
22
|
@expected_ips = '10.5.0.15,10.5.0.20,10.5.0.35'
|
23
23
|
@expected_scan_template = 'full-audit-widget-corp'
|
24
|
+
|
24
25
|
@mock_scan_id = '12'
|
25
26
|
@mock_site_id = '1'
|
26
27
|
|
@@ -28,6 +29,8 @@ describe 'nexpose-runner' do
|
|
28
29
|
@mock_vuln_report = 'ip_address,title,date_published,severity,summary,fix
|
29
30
|
10.5.0.15,Database Open Access,2010-01-01,Severe,Restrict database access,<p><p>Configure the database server to only allow access to trusted systems. For example, the PCI DSS standard requires you to place the database in an internal network zone, segregated from the DMZ </p></p>
|
30
31
|
10.5.0.15.180,MySQL Obsolete Version,2007-07-25,Critical,Upgrade to the latest version of Oracle MySQL,<p>Download and apply the upgrade from: <a href=http://dev.mysql.com/downloads/mysql>http://dev.mysql.com/downloads/mysql</a></p>'.chomp
|
32
|
+
|
33
|
+
@mock_vuln_detail_report = 'stuff'.chomp
|
31
34
|
|
32
35
|
@mock_software_report = 'name,ip_address,host_name,description,description,vendor,name,version
|
33
36
|
my_cool_software_build-28,10.5.0.15,,CentOS Linux 6.5,Virtual Machine,Linux,MAKEDEV,3.24-6.el6
|
@@ -58,7 +61,8 @@ describe 'nexpose-runner' do
|
|
58
61
|
'port' => @expected_port,
|
59
62
|
'site_name' => @expected_site_name,
|
60
63
|
'ip_addresses' => @expected_ips,
|
61
|
-
'scan_template' => @expected_scan_template
|
64
|
+
'scan_template' => @expected_scan_template,
|
65
|
+
'exception_file' => @expected_exception_file
|
62
66
|
}
|
63
67
|
|
64
68
|
end
|
@@ -214,6 +218,7 @@ describe 'nexpose-runner' do
|
|
214
218
|
.and_return(@mock_report)
|
215
219
|
|
216
220
|
expect_report_to_be_called_with(CONSTANTS::VULNERABILITY_REPORT_NAME, CONSTANTS::VULNERABILITY_REPORT_QUERY, @mock_vuln_report)
|
221
|
+
expect_report_to_be_called_with(CONSTANTS::VULNERABILITY_DETAIL_REPORT_NAME, CONSTANTS::VULNERABILITY_DETAIL_REPORT_QUERY, @mock_vuln_detail_report)
|
217
222
|
expect_report_to_be_called_with(CONSTANTS::SOFTWARE_REPORT_NAME, CONSTANTS::SOFTWARE_REPORT_QUERY, @mock_software_report)
|
218
223
|
expect_report_to_be_called_with(CONSTANTS::POLICY_REPORT_NAME, CONSTANTS::POLICY_REPORT_QUERY, @mock_policy_report)
|
219
224
|
|
@@ -270,6 +275,8 @@ end
|
|
270
275
|
|
271
276
|
def get_mock_nexpose_client
|
272
277
|
mock_nexpose_client = double(Nexpose::Connection)
|
278
|
+
xml = REXML::Element.new('test')
|
279
|
+
mock_api_request = double(Nexpose::APIRequest)
|
273
280
|
|
274
281
|
allow(mock_nexpose_client).to receive(:call).with(any_args).and_return({})
|
275
282
|
|
@@ -282,10 +289,33 @@ def get_mock_nexpose_client
|
|
282
289
|
|
283
290
|
allow(Nexpose::Connection).to receive(:new)
|
284
291
|
.and_return(mock_nexpose_client)
|
285
|
-
|
292
|
+
|
293
|
+
allow(mock_nexpose_client).to receive(:make_xml)
|
294
|
+
.with(any_args)
|
295
|
+
.and_return(xml)
|
296
|
+
|
297
|
+
allow(mock_nexpose_client).to receive(:make_xml)
|
298
|
+
.with(any_args)
|
299
|
+
.and_return(xml)
|
300
|
+
|
301
|
+
allow(mock_nexpose_client).to receive(:filter)
|
302
|
+
.with(any_args)
|
303
|
+
.and_return({})
|
304
|
+
|
305
|
+
allow(mock_nexpose_client).to receive(:execute)
|
306
|
+
.with(any_args)
|
307
|
+
.and_return(mock_api_request)
|
308
|
+
|
309
|
+
allow(mock_api_request).to receive(:success)
|
310
|
+
.and_return(false) #this is just to shut up the underlying api.
|
311
|
+
|
312
|
+
allow(mock_api_request).to receive(:attributes)
|
313
|
+
.and_return(xml)
|
314
|
+
|
286
315
|
mock_nexpose_client
|
287
316
|
end
|
288
317
|
|
318
|
+
|
289
319
|
def get_mock_scan_summary
|
290
320
|
mock_scan_summary = double(Nexpose::ScanSummary)
|
291
321
|
|
@@ -359,3 +389,4 @@ def get_mock_scan
|
|
359
389
|
allow(mock_scan).to receive(:id).and_return(@mock_scan_id)
|
360
390
|
mock_scan
|
361
391
|
end
|
392
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: NexposeRunner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Gibson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nexpose
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "<"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '11.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "<"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '11.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- config/scan.yml.example
|
87
87
|
- lib/NexposeRunner.rb
|
88
88
|
- lib/NexposeRunner/version.rb
|
89
|
+
- lib/nexpose-runner/command_line_arg_parser.rb
|
89
90
|
- lib/nexpose-runner/constants.rb
|
90
91
|
- lib/nexpose-runner/scan.rb
|
91
92
|
- lib/nexpose-runner/scan_run_description.rb
|