excl_site_asset_scan 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/nexpose_api_util +51 -0
- data/lib/api-options.rb +41 -0
- data/lib/extended-api.rb +117 -0
- data/lib/util.rb +33 -0
- metadata +75 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../lib/extended-api.rb'))
|
4
|
+
|
5
|
+
#------------------------------------------------------------------------------------------------------
|
6
|
+
# == Synopsis
|
7
|
+
# Main script to execute specified API commands against a specified NSC
|
8
|
+
#
|
9
|
+
# == Usage
|
10
|
+
# ruby nexpose_api_util.rb --help
|
11
|
+
#
|
12
|
+
# == Author
|
13
|
+
# Christopher Lee, Rapid7 LLC
|
14
|
+
#------------------------------------------------------------------------------------------------------
|
15
|
+
|
16
|
+
begin
|
17
|
+
if ARGV.length > 0
|
18
|
+
$is_command_line = false
|
19
|
+
begin
|
20
|
+
options = Options.parse ARGV
|
21
|
+
extended_api = ::ExtendedAPI.new options.user, options.password, options.host
|
22
|
+
extended_api.do_login
|
23
|
+
case options.key
|
24
|
+
when 1 then
|
25
|
+
extended_api.print_asset_groups
|
26
|
+
when 2 then
|
27
|
+
extended_api.print_asset_group_info options.args
|
28
|
+
when 3 then
|
29
|
+
extended_api.start_excluded_scan options.args
|
30
|
+
else
|
31
|
+
puts "Invalid Input!"
|
32
|
+
end
|
33
|
+
|
34
|
+
rescue Exception => e
|
35
|
+
puts e
|
36
|
+
ensure
|
37
|
+
begin
|
38
|
+
if extended_api
|
39
|
+
extended_api.do_logout
|
40
|
+
end
|
41
|
+
rescue Nexpose::APIError => e
|
42
|
+
# Don't care, maybe session already dead
|
43
|
+
end
|
44
|
+
end
|
45
|
+
exit 0
|
46
|
+
else
|
47
|
+
puts 'Input required'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
data/lib/api-options.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
#------------------------------------------------------------------------------------------------------
|
5
|
+
# Defines options to be executed against the NeXpose API
|
6
|
+
#------------------------------------------------------------------------------------------------------
|
7
|
+
class Options
|
8
|
+
def self.parse(args)
|
9
|
+
options = OpenStruct.new
|
10
|
+
options.verbose = false
|
11
|
+
|
12
|
+
option_parser = OptionParser.new do |option_parser|
|
13
|
+
option_parser.on("-h HOST", "The network address of the NeXpose instance - Required") {|arg| options.host=arg}
|
14
|
+
option_parser.on("-u USER", "The user name - Required") {|arg| options.user=arg}
|
15
|
+
option_parser.on("-p PASSWORD", "The password - Required") {|arg| options.password=arg}
|
16
|
+
option_parser.on("--n1", "List all the asset groups") {|arg| options.key=1}
|
17
|
+
option_parser.on("--n2 GI", "List an asset groups config. The GI (group id or group name is required)") do |arg|
|
18
|
+
options.key=2
|
19
|
+
options.args=arg
|
20
|
+
end
|
21
|
+
option_parser.on("--ses params", "Start an asset group excluded scan where params are a comma separated list of the site-id to scan followed by
|
22
|
+
asset group id(s) to exclude") do |arg|
|
23
|
+
options.key=3
|
24
|
+
options.args=arg.chomp
|
25
|
+
end
|
26
|
+
option_parser.on_tail("--help", "Help") do
|
27
|
+
puts option_parser
|
28
|
+
exit 0
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
option_parser.parse!(args)
|
34
|
+
rescue OptionParser::ParseError => e
|
35
|
+
puts "#{e}\n\n#{option_parser}"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
options
|
40
|
+
end
|
41
|
+
end
|
data/lib/extended-api.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'util.rb'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'api-options.rb'))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'hirb'
|
6
|
+
require 'nexpose'
|
7
|
+
|
8
|
+
#------------------------------------------------------------------------------------------------------
|
9
|
+
# Extends the base API functionality by combining common API commands to produce a simplified
|
10
|
+
# user command.
|
11
|
+
#------------------------------------------------------------------------------------------------------
|
12
|
+
class ExtendedAPI
|
13
|
+
attr_accessor :user_name, :password, :host, :nexpose_api, :scan_manager
|
14
|
+
@@connected = false
|
15
|
+
|
16
|
+
def initialize user_name, password, host
|
17
|
+
@user_name = user_name
|
18
|
+
@password = password
|
19
|
+
@host = host
|
20
|
+
@nexpose_api = Nexpose::Connection.new @host, @user_name, @password
|
21
|
+
end
|
22
|
+
|
23
|
+
#-------------------------------------------------------------------
|
24
|
+
# Logs in to NeXpose and sets a session key on the connector object.
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
def do_login
|
27
|
+
if not @@connected
|
28
|
+
begin
|
29
|
+
if @nexpose_api.login
|
30
|
+
@@connected = true
|
31
|
+
end
|
32
|
+
rescue Exception => e
|
33
|
+
puts e.message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#------------------------------------------------------
|
39
|
+
# Prints all asset group information in tabular format:
|
40
|
+
# | site_id | device_id | address | riskfactor |
|
41
|
+
#------------------------------------------------------
|
42
|
+
def print_asset_group_info group_id
|
43
|
+
group_configs = @nexpose_api.asset_group_config group_id
|
44
|
+
puts "\nASSET GROUP INFO (id: #{group_id})"
|
45
|
+
puts Hirb::Helpers::AutoTable.render group_configs, :fields => [:site_id, :device_id, :address, :riskfactor]
|
46
|
+
rescue Exception => e
|
47
|
+
if e.message =~ /Invalid groupID/
|
48
|
+
puts 'Group ID does not exist'
|
49
|
+
else
|
50
|
+
puts e.message
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#----------------------------------------------------------------
|
55
|
+
# Prints asset group configuration information in tabular format:
|
56
|
+
# | site_id | device_id | address | riskfactor |
|
57
|
+
#----------------------------------------------------------------
|
58
|
+
def print_asset_groups
|
59
|
+
res = @nexpose_api.asset_groups_listing
|
60
|
+
puts "\nASSET GROUPS:"
|
61
|
+
puts Hirb::Helpers::AutoTable.render res, :fields => [:asset_group_id, :name, :description, :risk_score]
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
#
|
66
|
+
#
|
67
|
+
def start_excluded_scan scan_info
|
68
|
+
# Parse the scan_info object to get site
|
69
|
+
# to be scanned and the asset group(s) to exclude
|
70
|
+
parsed_string = scan_info.to_s.split ','
|
71
|
+
site_id = parsed_string[0]
|
72
|
+
unless Util.is_number? site_id
|
73
|
+
raise ArgumentError.new 'The site-id must be a number'
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get all the device_ids for the site
|
77
|
+
device_listing_hash = @nexpose_api.site_device_listing site_id
|
78
|
+
device_ids = []
|
79
|
+
device_listing_hash.each do |device_listing|
|
80
|
+
device_ids << device_listing[:device_id].to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get all the devices associated with the group(s)
|
84
|
+
device_ids_excluded = []
|
85
|
+
parsed_string.delete_at(0)
|
86
|
+
parsed_string.each do |group_id|
|
87
|
+
group_infos = @nexpose_api.asset_group_config group_id
|
88
|
+
group_infos.each do |group_info|
|
89
|
+
device_ids_excluded << group_info[:device_id].to_i
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Remove all the devices in the group
|
94
|
+
devices_to_scan = device_ids - device_ids_excluded
|
95
|
+
|
96
|
+
# Hopefully this is not an empty set
|
97
|
+
if not devices_to_scan or devices_to_scan.empty?
|
98
|
+
raise "There are no devices left to scan after devices in groups: #{parsed_string.inspect} are removed from site: #{site_id}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Start an ad-hoc scan.
|
102
|
+
res = @nexpose_api.site_device_scan_start site_id, devices_to_scan, nil
|
103
|
+
if res
|
104
|
+
puts "Scan started scan ID: #{res[:scan_id]}, on engine ID: #{res[:engine_id]}"
|
105
|
+
else
|
106
|
+
put "Scan start failed for site #{site}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
#
|
112
|
+
#
|
113
|
+
def do_logout
|
114
|
+
@nexpose_api.logout
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
data/lib/util.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class Util
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------------------------------
|
4
|
+
# Checks if the input is a number
|
5
|
+
#
|
6
|
+
# input: The object that will be tested
|
7
|
+
#------------------------------------------------------------------------------------------------------
|
8
|
+
def self.is_number? input
|
9
|
+
true if Float input rescue false
|
10
|
+
end
|
11
|
+
|
12
|
+
#------------------------------------------------------------------------------------------------------
|
13
|
+
# Retrieves numeric input only from the command line
|
14
|
+
#
|
15
|
+
# mssg: The message to display that requests the input
|
16
|
+
#------------------------------------------------------------------------------------------------------
|
17
|
+
def self.get_numeric_input mssg
|
18
|
+
begin
|
19
|
+
while true
|
20
|
+
print mssg
|
21
|
+
input = gets().chomp()
|
22
|
+
if Util.is_number? input
|
23
|
+
return input.to_i
|
24
|
+
else
|
25
|
+
puts "Input is not a number"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
rescue Exception => e
|
29
|
+
puts e.message
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: excl_site_asset_scan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Christopher Lee
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-07-20 00:00:00.000000000 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nexpose
|
17
|
+
requirement: &23552100 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.3
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *23552100
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: hirb
|
28
|
+
requirement: &23551800 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.4.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *23551800
|
37
|
+
description: ! " \tList asset groups, list information about certain asset groups,
|
38
|
+
start a site scan with certain asset groups excluded.\n"
|
39
|
+
email: christopher_lee@rapid7.com
|
40
|
+
executables:
|
41
|
+
- nexpose_api_util
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- lib/api-options.rb
|
46
|
+
- lib/extended-api.rb
|
47
|
+
- lib/util.rb
|
48
|
+
- bin/nexpose_api_util
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: https://github.com/chrlee/NeXpose-ScanManager-Interface/tree/master/examples/excluded_asset_scan
|
51
|
+
licenses: []
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.5.2
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: List asset groups, list information about certain asset groups, start a site
|
74
|
+
scan with certain asset groups excluded.
|
75
|
+
test_files: []
|