nexpose 0.8.8 → 0.8.9
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 +1 -0
- data/lib/nexpose/global_settings.rb +117 -0
- data/lib/nexpose/settings.xml +14 -0
- data/lib/nexpose/site.rb +2 -11
- data/lib/nexpose/util.rb +57 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6698a2821faefa7c1822f324cc1bfd355869ad7f
|
4
|
+
data.tar.gz: 3a14efb354cbc7036cf829f60088ceeaa0f7a80b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 219848942e56f658d1a3f43e8411ded2c12e693d5f258106196ddca5121c3434be50c17dffd45fe61504d5d76050bd77c123ea3d844e5f07a65656a353b03ea2
|
7
|
+
data.tar.gz: 89ae18299c87ef71a2805038ef3f1e3c7ab7a53cf87e0c66f799dbaa83e024f7714dc4198854d509156646472aea80d344f215c2de7b4fcfa6d71535ca87ef97
|
data/lib/nexpose.rb
CHANGED
@@ -0,0 +1,117 @@
|
|
1
|
+
module Nexpose
|
2
|
+
# Object used to manage the global settings of a Nexpose console.
|
3
|
+
#
|
4
|
+
class GlobalSettings
|
5
|
+
# IP addresses and/or host names that will be excluded from scanning across
|
6
|
+
# all sites.
|
7
|
+
attr_accessor :asset_exclusions
|
8
|
+
|
9
|
+
# Whether control scanning in enabled. A feature tied to ControlsInsight
|
10
|
+
# integration.
|
11
|
+
attr_accessor :control_scanning
|
12
|
+
|
13
|
+
# XML document representing the entire configuration.
|
14
|
+
attr_reader :xml
|
15
|
+
|
16
|
+
# Private constructor. See #load method for retrieving a settings object.
|
17
|
+
#
|
18
|
+
def initialize(xml)
|
19
|
+
@xml = xml
|
20
|
+
|
21
|
+
@asset_exclusions = HostOrIP.parse(xml)
|
22
|
+
@control_scanning = _get_control_scanning(xml)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns true if controls scanning is enabled.
|
26
|
+
def control_scanning?
|
27
|
+
control_scanning
|
28
|
+
end
|
29
|
+
|
30
|
+
# Save any updates to this settings object to the Nexpose console.
|
31
|
+
#
|
32
|
+
# @param [Connection] nsc Connection to a Nexpose console.
|
33
|
+
# @return [Boolean] Whether saving was successful.
|
34
|
+
#
|
35
|
+
def save(nsc)
|
36
|
+
# load method can return XML missing this required attribute.
|
37
|
+
unless REXML::XPath.first(xml, '//*[@recalculation_duration]')
|
38
|
+
risk_model = REXML::XPath.first(xml, '//riskModel')
|
39
|
+
risk_model.add_attribute('recalculation_duration', 'do_not_recalculate')
|
40
|
+
end
|
41
|
+
|
42
|
+
_replace_exclusions(xml, asset_exclusions)
|
43
|
+
_set_control_scanning(xml, control_scanning)
|
44
|
+
|
45
|
+
response = AJAX.post(nsc, '/data/admin/global-settings', xml)
|
46
|
+
XMLUtils.success? response
|
47
|
+
end
|
48
|
+
|
49
|
+
# Add an asset exclusion setting.
|
50
|
+
#
|
51
|
+
# @param [IPRange|HostName|String] host_or_ip Host or IP (range) to exclude
|
52
|
+
# from scanning by the Nexpose console.
|
53
|
+
#
|
54
|
+
def add_exclusion(host_or_ip)
|
55
|
+
asset = host_or_ip
|
56
|
+
unless host_or_ip.respond_to?(:host) || host_or_ip.respond_to?(:from)
|
57
|
+
asset = HostOrIP.convert(host_or_ip)
|
58
|
+
end
|
59
|
+
@asset_exclusions << asset
|
60
|
+
end
|
61
|
+
|
62
|
+
# Remove an asset exclusion setting.
|
63
|
+
# If you need to remove a range of IPs, be sure to explicitly supply an
|
64
|
+
# IPRange object to the method.
|
65
|
+
#
|
66
|
+
# @param [IPRange|HostName|String] host_or_ip Host or IP (range) to remove
|
67
|
+
# from the exclusion list.
|
68
|
+
#
|
69
|
+
def remove_exclusion(host_or_ip)
|
70
|
+
asset = host_or_ip
|
71
|
+
unless host_or_ip.respond_to?(:host) || host_or_ip.respond_to?(:from)
|
72
|
+
# Attept to convert String to appropriate object.
|
73
|
+
asset = HostOrIP.convert(host_or_ip)
|
74
|
+
end
|
75
|
+
@asset_exclusions = asset_exclusions.reject { |a| a.eql? asset }
|
76
|
+
end
|
77
|
+
|
78
|
+
# Load the global settings from a Nexpose console.
|
79
|
+
#
|
80
|
+
# @param [Connection] nsc Connection to a Nexpose console.
|
81
|
+
# @return [GlobalSettings] Settings object for the console.
|
82
|
+
#
|
83
|
+
def self.load(nsc)
|
84
|
+
response = AJAX.get(nsc, '/data/admin/global-settings')
|
85
|
+
new(REXML::Document.new(response))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Internal method for updating exclusions before saving.
|
89
|
+
def _replace_exclusions(xml, exclusions)
|
90
|
+
xml.elements.delete('//ExcludedHosts')
|
91
|
+
elem = xml.root.add_element('ExcludedHosts')
|
92
|
+
exclusions.each do |exclusion|
|
93
|
+
elem.add_element(exclusion.as_xml)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Internal method for parsing XML for whether control scanning in enabled.
|
98
|
+
def _get_control_scanning(xml)
|
99
|
+
enabled = false
|
100
|
+
if elem = REXML::XPath.first(xml, '//enableControlsScan[@enabled]')
|
101
|
+
enabled = elem.attribute('enabled').value.to_i == 1
|
102
|
+
end
|
103
|
+
enabled
|
104
|
+
end
|
105
|
+
|
106
|
+
# Internal method for updating control scanning before saving.
|
107
|
+
def _set_control_scanning(xml, enabled)
|
108
|
+
if elem = REXML::XPath.first(xml, '//enableControlsScan')
|
109
|
+
elem.attributes['enabled'] = enabled ? '1' : '0'
|
110
|
+
else
|
111
|
+
elem = REXML::Element.new('ControlsScan', xml.root)
|
112
|
+
elem.add_element('enableControlsScan',
|
113
|
+
'enabled' => enabled ? '1' : '0')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<GlobalSettings>
|
2
|
+
<riskModel id="real_risk" recalculation_duration="do_not_recalculate"></riskModel>
|
3
|
+
<RiskConfig includeRiskModifiers="false">
|
4
|
+
<RiskModifiers veryHigh="2" high="1.5" medium="1" low="0.75" veryLow="0.5"></RiskModifiers>
|
5
|
+
</RiskConfig>
|
6
|
+
<ControlsScan>
|
7
|
+
<enableControlsScan enabled="0"></enableControlsScan>
|
8
|
+
</ControlsScan>
|
9
|
+
<ExcludedHosts>
|
10
|
+
<range from="10.4.18.219"></range>
|
11
|
+
<range from="10.4.25.117"></range>
|
12
|
+
</ExcludedHosts>
|
13
|
+
</GlobalSettings>
|
14
|
+
|
data/lib/nexpose/site.rb
CHANGED
@@ -217,17 +217,8 @@ module Nexpose
|
|
217
217
|
# @param [String] asset Identifier of an asset, either IP or host name.
|
218
218
|
#
|
219
219
|
def add_asset(asset)
|
220
|
-
|
221
|
-
|
222
|
-
ip = IPAddr.new(asset)
|
223
|
-
add_ip(asset)
|
224
|
-
rescue ArgumentError => e
|
225
|
-
if e.message == 'invalid address'
|
226
|
-
add_host(asset)
|
227
|
-
else
|
228
|
-
raise "Unable to parse asset: '#{asset}'. #{e.message}"
|
229
|
-
end
|
230
|
-
end
|
220
|
+
obj = HostOrIP.convert(asset)
|
221
|
+
@assets << obj
|
231
222
|
end
|
232
223
|
|
233
224
|
# Remove an asset to this site, resolving whether an IP or hostname is
|
data/lib/nexpose/util.rb
CHANGED
@@ -34,5 +34,62 @@ module Nexpose
|
|
34
34
|
|
35
35
|
xml
|
36
36
|
end
|
37
|
+
|
38
|
+
# Check a typical Nexpose XML response for success.
|
39
|
+
# Typically, the root element has a 'success' attribute, and its value is
|
40
|
+
# '1' if the call succeeded.
|
41
|
+
#
|
42
|
+
def self.success?(xml_string)
|
43
|
+
xml = ::REXML::Document.new(xml_string.to_s)
|
44
|
+
success = ::REXML::XPath.first(xml, '//@success')
|
45
|
+
!success.nil? && success.value.to_i == 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Function module for dealing with String to HostName|IPRange conversions.
|
50
|
+
#
|
51
|
+
module HostOrIP
|
52
|
+
module_function
|
53
|
+
|
54
|
+
# Convert a host or IP address to the corresponding HostName or IPRange
|
55
|
+
# class.
|
56
|
+
#
|
57
|
+
# If the String cannot be converted, it will raise an error.
|
58
|
+
#
|
59
|
+
# @param [String] asset String representation of an IP or host name.
|
60
|
+
# @return [IPRange|HostName] Valid class, if it can be converted.
|
61
|
+
#
|
62
|
+
def convert(asset)
|
63
|
+
begin
|
64
|
+
# Use IPAddr construtor validation to see if it's an IP.
|
65
|
+
IPAddr.new(asset)
|
66
|
+
IPRange.new(asset)
|
67
|
+
rescue ArgumentError => e
|
68
|
+
if e.message == 'invalid address'
|
69
|
+
HostName.new(asset)
|
70
|
+
else
|
71
|
+
raise "Unable to parse asset: '#{asset}'. #{e.message}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Parse a REXML::Document or REXML::Element for any hosts listed and convert
|
77
|
+
# them to HostName and IPRange objects.
|
78
|
+
#
|
79
|
+
# @param [REXML::Document|REXML::Element] xml REXML class potentially
|
80
|
+
# containing host references.
|
81
|
+
# @return [Array[HostName|IPRange]] Collection of parsed hosts.
|
82
|
+
#
|
83
|
+
def parse(xml)
|
84
|
+
coll = []
|
85
|
+
xml.elements.each('//range') do |elem|
|
86
|
+
to = elem.attribute('to').nil? ? nil : elem.attribute('to').value
|
87
|
+
coll << IPRange.new(elem.attribute('from').value, to)
|
88
|
+
end
|
89
|
+
xml.elements.each('//host') do |elem|
|
90
|
+
coll << HostName.new(elem.text)
|
91
|
+
end
|
92
|
+
coll
|
93
|
+
end
|
37
94
|
end
|
38
95
|
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.8.
|
4
|
+
version: 0.8.9
|
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-10-
|
14
|
+
date: 2014-10-20 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rex
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- lib/nexpose/engine.rb
|
86
86
|
- lib/nexpose/error.rb
|
87
87
|
- lib/nexpose/filter.rb
|
88
|
+
- lib/nexpose/global_settings.rb
|
88
89
|
- lib/nexpose/group.rb
|
89
90
|
- lib/nexpose/maint.rb
|
90
91
|
- lib/nexpose/manage.rb
|
@@ -95,6 +96,7 @@ files:
|
|
95
96
|
- lib/nexpose/role.rb
|
96
97
|
- lib/nexpose/scan.rb
|
97
98
|
- lib/nexpose/scan_template.rb
|
99
|
+
- lib/nexpose/settings.xml
|
98
100
|
- lib/nexpose/shared_cred.rb
|
99
101
|
- lib/nexpose/silo.rb
|
100
102
|
- lib/nexpose/silo_profile.rb
|