NexposeRunner 0.0.11 → 0.0.15

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: 036c8b0ba1228ba901aa9a2d6dd9761b8a3954e2
4
- data.tar.gz: 88734251626b998de84494f389dc177a19ef018f
3
+ metadata.gz: 5928523f9cb26228648a7bd116e26bee432b2992
4
+ data.tar.gz: 427bc4fd6579b8ca6c60eaa698cf014f955f5fd9
5
5
  SHA512:
6
- metadata.gz: 29f09e4ba6ed8da21f755ed0a390afbe243c5b195eb34fbc7b04f3a4699b9596aa3f0c2244f5ca6d25edd4e3efe1bb24a6d8fb41c02274696f49a04f6d4c2ab1
7
- data.tar.gz: 04ef634b585bb3f3a554e7f107d841d7db3c2d67b7fe94008ec11a5682fc768d7587dca393c05b77786c51c393a39c9cf4f93b4389277868451994fc7174a435
6
+ metadata.gz: cc462110f837f49d1620371315ec578cbcac2e9c6fbf3d6f9bb3dabcbfe2571e1f0b3b8b8cdb5d32e3ff178974a87c0f6a8598fd3e4f1f51a5e978a0df23e89c
7
+ data.tar.gz: 7f88846124ca3500a757b50759cb4de40bf0a02c9349794f97246ca02ceb401f2e91a18733e5c9889787582d80856f2cc8dcd7449dcb9931e9005db2b6671371
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
data/.travis.yml CHANGED
@@ -2,9 +2,8 @@ language: ruby
2
2
  rvm:
3
3
  - 2.2.4
4
4
  - 2.2.2
5
- - 2.0.0
5
+ - 2.1.0
6
6
  - jruby-19mode
7
- - rbx-2
8
7
  deploy:
9
8
  provider: rubygems
10
9
  api_key:
data/Exclusions.txt ADDED
@@ -0,0 +1,3 @@
1
+ vuln1
2
+ Vuln2
3
+ vuln3
data/README.md CHANGED
@@ -6,7 +6,7 @@ This gem will make a nexpose server connection, create a new site, initiate a sc
6
6
 
7
7
  Basically this gem allows you to attach Nexpose to your Continuous Delivery/Continuous Integration pipeline. Though it can be used for other purposes.
8
8
 
9
- At the end of the scan it will generate 3 csv reports and save them in the directory where the script was executed from. It will also raise an exception if a vulnerbaility is detected. This is used to break the Continuous Delivery/Continuous integration build.
9
+ At the end of the scan it will generate 3 csv reports and save them in the directory where the script was executed from. It will also raise an exception if a vulnerability is detected. This is used to break the Continuous Delivery/Continuous integration build. You may add an exception list URL to prevent breaking the build.
10
10
 
11
11
  ## Installation
12
12
 
@@ -24,15 +24,14 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
- This gem allows you to specify the Nexpose Server URL, Nexpose Username, Nexpose Password, Nexpose Server Port (optional, defaults to 3780), Site Name, Target IP Address, Scan Template, and Engine Number (optional).
27
+ This gem allows you to specify the Nexpose Server URL, Exceptions URL (optional), Nexpose Username, Nexpose Password, Nexpose Server Port (optional, defaults to 3780), Site Name, Target IP Address, Scan Template, and Engine Number (optional).
28
28
 
29
+ *NOTE:* If you use the "exceptions_list_url" parameter, please ensure you have proper authentication in place.
29
30
 
30
- $ scan "connection_url" "username" "password" "port" "site_name" "ip_address" "scan_template" "engine_number"
31
-
32
31
  EXAMPLE:
33
32
 
34
- $ scan "http://test.connection" "rapid7" "password" "3780" "my_cool_software_build-28" "10.5.0.15" "full-audit-widget-corp"
35
-
33
+ $ scan --connection test.com --exceptions_list_url raw.github.com/exceptions.txt --username username1 --password password1 --port 443 --site-name myfirstsite --ip-addresses 192.168.1.10 --scan-template full-audit --Engine 2
34
+
36
35
  It is possible to use a YAML file to drive the configuration of this module. An example configuration file is provided in config/scan.yml.example. Simply copy it to config/scan.yml and modify it to work with your environment.
37
36
 
38
37
  ## Contributing
@@ -1,4 +1,4 @@
1
1
  module NexposeRunner
2
- VERSION = '0.0.11'
2
+ VERSION = '0.0.15'
3
3
  end
4
4
 
@@ -4,6 +4,7 @@ class CommandLineArgumentParser
4
4
  def self.parse(args)
5
5
  options = {}
6
6
  options['connection_url'] = ''
7
+ options['exceptions_list_url'] = ''
7
8
  options['username'] = ''
8
9
  options['password'] = ''
9
10
  options['port'] = 0
@@ -22,6 +23,9 @@ class CommandLineArgumentParser
22
23
  options['connection_url'] = url
23
24
  end
24
25
 
26
+ opts.on('--exceptions_list_url eURL', 'Vulnerability list URL') do |exceptions_list_url|
27
+ options['exceptions_list_url'] = exceptions_list_url
28
+ end
25
29
  opts.on('--username USERNAME', 'Nexpose Login Username') do |username|
26
30
  options['username'] = username
27
31
  end
@@ -49,6 +53,8 @@ class CommandLineArgumentParser
49
53
  opts.on('--engine ENGINE', 'Nexpose scan engine to use') do |engine|
50
54
  options['engine'] = engine
51
55
  end
56
+
57
+
52
58
 
53
59
  end
54
60
 
@@ -1,5 +1,6 @@
1
1
  module CONSTANTS
2
2
  REQUIRED_CONNECTION_URL_MESSAGE = 'OOPS! Looks like you forgot to give me the URL/IP address to your Nexpose Server'
3
+ DEFAULT_EXCEPTIONS_URL = ''
3
4
  REQUIRED_USERNAME_MESSAGE = 'OOPS! Looks like you forgot to give me a username to login to Nexpose with'
4
5
  REQUIRED_PASSWORD_MESSAGE = 'OOPS! Looks like you forgot to give me a password to login to Nexpose with'
5
6
  REQUIRED_SITE_NAME_MESSAGE = 'OOPS! Looks like you forgot to give me a Nexpose Site Name'
@@ -1,11 +1,43 @@
1
- require 'nexpose'
1
+ require 'net/http'
2
2
  require 'csv'
3
+ require 'nexpose'
4
+ require 'open-uri'
3
5
  require 'json'
4
6
  require 'nexpose-runner/constants'
5
7
  require 'nexpose-runner/scan_run_description'
6
8
 
7
9
  module NexposeRunner
8
10
  module Scan
11
+
12
+ def self.allow_vulnerabilities?(vulnerabilities, run_details)
13
+ vuln_array = []
14
+ exceptions_array = get_exceptions(run_details)
15
+ titles = vulnerabilities.map{ |v| v[1] }[1..-1]
16
+ for vuln in titles
17
+ if !exceptions_array.include?(vuln)
18
+ puts "#{vuln} not found in Exceptions list"
19
+ vuln_array << [vuln]
20
+ end
21
+ end
22
+
23
+ if vuln_array.count > 0
24
+ File.open('No_Exceptions_Found.txt', 'w+') do |f|
25
+ vuln_array.each { |element| f.puts(element) }
26
+ return false
27
+ end
28
+
29
+ else
30
+ puts "All exceptions passed!"
31
+ return true
32
+ end
33
+ end
34
+
35
+ def self.get_exceptions(run_details)
36
+ uri = URI("#{run_details.exceptions_list_url}")
37
+ ex = Net::HTTP.get(uri).split("\n")
38
+ ex
39
+ end
40
+
9
41
  def Scan.start(options)
10
42
 
11
43
  run_details = ScanRunDescription.new(options)
@@ -19,13 +51,13 @@ module NexposeRunner
19
51
 
20
52
  reports = generate_reports(nsc, site, run_details)
21
53
 
22
- verify_run(reports[0])
54
+ verify_run(reports[0], run_details)
23
55
  end
24
56
 
25
57
  def self.generate_reports(nsc, site, run_details)
26
58
  puts "Scan complete for #{run_details.site_name}, Generating Vulnerability Report"
27
- vulnerbilities = generate_report(CONSTANTS::VULNERABILITY_REPORT_QUERY, site.id, nsc)
28
- generate_csv(vulnerbilities, CONSTANTS::VULNERABILITY_REPORT_NAME)
59
+ vulnerabilities = generate_report(CONSTANTS::VULNERABILITY_REPORT_QUERY, site.id, nsc)
60
+ generate_csv(vulnerabilities, CONSTANTS::VULNERABILITY_REPORT_NAME)
29
61
 
30
62
  puts "Scan complete for #{run_details.site_name}, Generating Vulnerability Detail Report"
31
63
  vuln_details = generate_report(CONSTANTS:: VULNERABILITY_DETAIL_REPORT_QUERY, site.id, nsc)
@@ -45,13 +77,21 @@ module NexposeRunner
45
77
  puts "Scan complete for #{run_details.site_name}, Generating Xml Report"
46
78
  generate_template_report(nsc, site.id, CONSTANTS::XML_REPORT_FILE_NAME, CONSTANTS::XML_REPORT_NAME, CONSTANTS::XML_REPORT_FORMAT)
47
79
 
48
- [vulnerbilities, software, policies]
80
+ [vulnerabilities, software, policies]
49
81
  end
50
82
 
51
- def self.verify_run(vulnerabilities)
83
+ def self.verify_run(vulnerabilities, run_details)
84
+
85
+ if run_details.exceptions_list_url.to_s.empty? and vulnerabilities.count > 0
86
+ raise StandardError, CONSTANTS::VULNERABILITY_FOUND_MESSAGE
52
87
 
53
- raise StandardError, CONSTANTS::VULNERABILITY_FOUND_MESSAGE if vulnerabilities.count > 0
88
+ elsif vulnerabilities.count == 0
89
+ puts "No vulnerabilities found!"
90
+ return true
54
91
 
92
+ elsif allow_vulnerabilities?(vulnerabilities, run_details) == false
93
+ raise StandardError, CONSTANTS::VULNERABILITY_FOUND_MESSAGE
94
+ end
55
95
  end
56
96
 
57
97
  def self.start_scan(nsc, site, run_details)
@@ -62,7 +102,7 @@ module NexposeRunner
62
102
  begin
63
103
  sleep(3)
64
104
  stats = nsc.scan_statistics(scan.id)
65
- status = stats.status
105
+ status = stats.status
66
106
  puts "Current #{run_details.site_name} scan status: #{status.to_s} -- PENDING: #{stats.tasks.pending.to_s} ACTIVE: #{stats.tasks.active.to_s} COMPLETED #{stats.tasks.completed.to_s}"
67
107
  end while status == Nexpose::Scan::Status::RUNNING
68
108
  end
@@ -85,7 +125,7 @@ module NexposeRunner
85
125
  def self.get_new_nexpose_connection(run_details)
86
126
  nsc = Nexpose::Connection.new run_details.connection_url, run_details.username, run_details.password, run_details.port
87
127
  nsc.login
88
- puts 'Successfully logged into the Nexpose Server'
128
+ puts 'Successfully logged into the Nexpose Server!'
89
129
  nsc
90
130
  end
91
131
 
@@ -2,9 +2,10 @@ require 'yaml'
2
2
  require 'nexpose-runner/command_line_arg_parser'
3
3
 
4
4
  class ScanRunDescription
5
- attr_accessor :connection_url, :username, :password, :port, :site_name, :ip_addresses, :scan_template, :engine
5
+ attr_accessor :connection_url, :exceptions_list_url, :username, :password, :port, :site_name, :ip_addresses, :scan_template, :engine
6
6
  @@port_value = ''
7
7
  @@ip_addresses = []
8
+ exceptions_list_url_value = ''
8
9
 
9
10
  def initialize(options)
10
11
  if File.file?('config/scan.yml')
@@ -14,6 +15,7 @@ class ScanRunDescription
14
15
  end
15
16
 
16
17
  self.connection_url = options['connection_url']
18
+ @@exceptions_list_url_value = options['exceptions_list_url']
17
19
  self.username = options['username']
18
20
  self.password = options['password']
19
21
  @@port_value = options['port']
@@ -30,6 +32,7 @@ class ScanRunDescription
30
32
  raise StandardError, CONSTANTS::REQUIRED_SITE_NAME_MESSAGE if site_name.nil? || site_name.empty?
31
33
  raise StandardError, CONSTANTS::REQUIRED_IP_ADDRESS_MESSAGE if ip_addresses.length == 0
32
34
  raise StandardError, CONSTANTS::REQUIRED_SCAN_TEMPLATE_MESSAGE if scan_template.nil? || scan_template.empty?
35
+
33
36
  end
34
37
 
35
38
  def port=(value)
@@ -40,6 +43,14 @@ class ScanRunDescription
40
43
  get_value(@@port_value, CONSTANTS::DEFAULT_PORT)
41
44
  end
42
45
 
46
+ def exceptions_list_url=(value)
47
+ @@exceptions_list_url_value = value
48
+ end
49
+
50
+ def exceptions_list_url
51
+ get_value(@@exceptions_list_url_value, CONSTANTS::DEFAULT_EXCEPTIONS_URL)
52
+ end
53
+
43
54
  def ip_addresses=(value)
44
55
  @@ip_addresses = value.split(',') unless value.nil?
45
56
  end
data/spec/scan_spec.rb CHANGED
@@ -29,7 +29,8 @@ describe 'nexpose-runner' do
29
29
  @mock_vuln_report = 'ip_address,title,date_published,severity,summary,fix
30
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>
31
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
-
32
+ @mock_exceptions = "Database Open Access\nMySQL Obsolete Version"
33
+
33
34
  @mock_vuln_detail_report = 'stuff'.chomp
34
35
 
35
36
  @mock_software_report = 'name,ip_address,host_name,description,description,vendor,name,version
@@ -62,7 +63,6 @@ describe 'nexpose-runner' do
62
63
  'site_name' => @expected_site_name,
63
64
  'ip_addresses' => @expected_ips,
64
65
  'scan_template' => @expected_scan_template,
65
- 'exception_file' => @expected_exception_file
66
66
  }
67
67
 
68
68
  end
@@ -246,6 +246,17 @@ describe 'nexpose-runner' do
246
246
  NexposeRunner::Scan.start(@options)
247
247
  }.to raise_error(StandardError, CONSTANTS::VULNERABILITY_FOUND_MESSAGE)
248
248
  end
249
+
250
+ it 'should not throw exception if exceptions exist for all vulnerabilities' do
251
+ expect_report_to_be_called_with(CONSTANTS::VULNERABILITY_REPORT_NAME, CONSTANTS::VULNERABILITY_REPORT_QUERY, @mock_vuln_report)
252
+
253
+ options = @options.clone
254
+ options['exceptions_list_url'] = 'http://google.com'
255
+
256
+ expect_exceptions_to_be_called_with(options['exceptions_list_url'])
257
+
258
+ NexposeRunner::Scan.start(options)
259
+ end
249
260
  end
250
261
 
251
262
  if File.file?('config/exploit.yml.bak')
@@ -253,6 +264,12 @@ describe 'nexpose-runner' do
253
264
  end
254
265
  end
255
266
 
267
+ def expect_exceptions_to_be_called_with(exceptions_list_url)
268
+ uri = URI(exceptions_list_url)
269
+ expect(Net::HTTP).to receive(:get)
270
+ .with(uri).and_return(@mock_exceptions)
271
+ end
272
+
256
273
  def expect_report_to_be_called_with(report_name, report_query, report_response)
257
274
  expect(@mock_report).to receive(:add_filter)
258
275
  .with('version', '1.3.0')
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.11
4
+ version: 0.0.15
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-03-14 00:00:00.000000000 Z
11
+ date: 2017-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nexpose
@@ -77,6 +77,7 @@ files:
77
77
  - ".gitignore"
78
78
  - ".rspec"
79
79
  - ".travis.yml"
80
+ - Exclusions.txt
80
81
  - Gemfile
81
82
  - LICENSE.txt
82
83
  - NexposeRunner.gemspec
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  version: '0'
114
115
  requirements: []
115
116
  rubyforge_project:
116
- rubygems_version: 2.4.8
117
+ rubygems_version: 2.5.2
117
118
  signing_key:
118
119
  specification_version: 4
119
120
  summary: This is a gem that provides the ability to create a new site, add an IP to