nexpose 0.8.8 → 0.8.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0895452fa39e68f031ad27edc40a94cef8337730
4
- data.tar.gz: 051981f1f5ef5a0e04977c3a7f5bc1447b2cee3c
3
+ metadata.gz: 6698a2821faefa7c1822f324cc1bfd355869ad7f
4
+ data.tar.gz: 3a14efb354cbc7036cf829f60088ceeaa0f7a80b
5
5
  SHA512:
6
- metadata.gz: 9ebb703fbacc51a22fc0d60e18b1ac063fe853406b22c6ee2b7b3d77b0f9feda1e2441f07d0cb8b5dfeb8cb96937451cc94a5088e24485a34a7e078a98d37187
7
- data.tar.gz: 4f7c7f467df77177e2762f5bf927548fe67e70c641855e7108a0219e1761bb9f1996664862edaaeb2a017ebd3df252bccfaf71163ba80053a9147dd609b030b9
6
+ metadata.gz: 219848942e56f658d1a3f43e8411ded2c12e693d5f258106196ddca5121c3434be50c17dffd45fe61504d5d76050bd77c123ea3d844e5f07a65656a353b03ea2
7
+ data.tar.gz: 89ae18299c87ef71a2805038ef3f1e3c7ab7a53cf87e0c66f799dbaa83e024f7714dc4198854d509156646472aea80d344f215c2de7b4fcfa6d71535ca87ef97
@@ -72,6 +72,7 @@ require 'nexpose/discovery'
72
72
  require 'nexpose/discovery/filter'
73
73
  require 'nexpose/engine'
74
74
  require 'nexpose/filter'
75
+ require 'nexpose/global_settings'
75
76
  require 'nexpose/group'
76
77
  require 'nexpose/dag'
77
78
  require 'nexpose/manage'
@@ -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
+
@@ -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
- begin
221
- # If the asset registers as a valid IP, store as IP.
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
@@ -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.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-17 00:00:00.000000000 Z
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