nexpose 0.8.17 → 0.8.18

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: 2d53af256a38fa293d1ba3a20353ed46605b067c
4
- data.tar.gz: e8564b802c313c0bfb983b714da40f4a9a18bdaa
3
+ metadata.gz: 24b07c5aa9671577da0a19a249babd2c0fce5ff6
4
+ data.tar.gz: 30f364953ab62ff807f82deffb848b2ceef80636
5
5
  SHA512:
6
- metadata.gz: 8c820282edb3efbc36521c21edc6389a820fd91e035671cd2f2b6abff147d2757afb812065b86c54d8cadf1d384e18442602204eb057a32a0495454534b2776c
7
- data.tar.gz: f283f2f236f7ebc5cd66c4c6f7c613a450ca365dce683c7bcb5097ec979ef995bf4ebe8ee356c34db5d2134cc8e872fdd564bc028c777b3ca586ce652bc26aa3
6
+ metadata.gz: fca1a54493ded6d695c2668c53c3ced413c7c82b181367bf3af666cf9cab10ad7209c1a7e6a67f059e6ba7b03f03ba5a783d9aa7ed0706754e7413e847e89d20
7
+ data.tar.gz: 9f30a2887a5b7f7064b1bf8c5dd7482e7762cb0b7b25e5d91a22dadab2e6577590bc374f76323372394bda48db48526a4663058ae7a356a8148bcec10f1e6764
data/lib/nexpose.rb CHANGED
@@ -48,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48
48
  #
49
49
 
50
50
  require 'date'
51
+ require 'time'
51
52
  require 'rexml/document'
52
53
  require 'nokogiri'
53
54
  require 'net/https'
@@ -61,6 +62,7 @@ require 'nexpose/error'
61
62
  require 'nexpose/util'
62
63
  require 'nexpose/alert'
63
64
  require 'nexpose/ajax'
65
+ require 'nexpose/api'
64
66
  require 'nexpose/api_request'
65
67
  require 'nexpose/common'
66
68
  require 'nexpose/console'
@@ -0,0 +1,77 @@
1
+ module Nexpose
2
+ # Base class for all API 2.0 objects which are derived from JSON
3
+ # representations.
4
+ #
5
+ # This class is not intended to be used by customers, but to extend
6
+ # functionality in the gem itself.
7
+ #
8
+ # To use this class, do the following:
9
+ # * Subclass APIObject
10
+ # * Do NOT provide a constructor method, or it must take no arguments.
11
+ # * Clearly document all attributes which the customer can expect to see.
12
+ # * Clearly document those attributes which are lazily loaded.
13
+ # * If applicable, implement a load method which calls new.object_from_hash
14
+ #
15
+ class APIObject
16
+ # Populate object methods and attributes from a JSON-derived hash.
17
+ #
18
+ # @param [Nexpose::Connection] nsc Active connection to a console.
19
+ # @param [Hash] hash Result of running JSON#parse with the
20
+ # symbolize_names parameter to a 2.0 API response.
21
+ # Pass hash[:resources] if the response is pageable.
22
+ #
23
+ def object_from_hash(nsc, hash)
24
+ hash.each do |k, v|
25
+ next if k == :url # Do not store self-referential URL.
26
+ # Store resource URLs separately and create lazy accessors.
27
+ if v.is_a?(Hash) && v.key?(:url)
28
+ instance_variable_set("@#{k}_url", v[:url].gsub(/.*\/api/, '/api'))
29
+ self.class.send(:define_method, k, proc { |conn = nsc| load_resource(conn, k, instance_variable_get("@#{k}_url")) })
30
+ else
31
+ # Convert timestamps.
32
+ if v.is_a?(String) && v.match(/^\d{8}T\d{6}\.\d{3}/)
33
+ instance_variable_set("@#{k}", ISO8601.to_time(v))
34
+ else
35
+ instance_variable_set("@#{k}", v)
36
+ end
37
+ self.class.send(:define_method, k, proc { instance_variable_get("@#{k}") })
38
+ end
39
+ end
40
+ self
41
+ end
42
+
43
+ private
44
+
45
+ # Load a resource from the security console. Once loaded, the value is
46
+ # cached so that it need not be loaded again.
47
+ #
48
+ # @param [Connection] nsc Active connection to the console.
49
+ # @param [Symbol] k Original key name, used to identify the class to load.
50
+ # @param [String] url Truncated URL to use to retrieve the resource.
51
+ # @return [Array[?]] Collection of "k" marshalled object.
52
+ #
53
+ def load_resource(nsc, k, url)
54
+ obj = class_from_string(k)
55
+ resp = AJAX.get(nsc, url, AJAX::CONTENT_TYPE::JSON)
56
+ hash = JSON.parse(resp, symbolize_names: true)
57
+ resources = hash[:resources].map { |e| obj.method(:new).call.object_from_hash(nsc, e) }
58
+ instance_variable_set("@#{k}", resources)
59
+ self.class.send(:define_method, k, proc { instance_variable_get("@#{k}") })
60
+ resources
61
+ end
62
+
63
+ # Get the class referred to by a field name.
64
+ #
65
+ # For example, this method will translate a field name like "malware_kits"
66
+ # into to corresponding MalwareKit class.
67
+ #
68
+ # @param [String] field Snake-case name of a field.
69
+ # @return [Class] Class associated with the provided field.
70
+ #
71
+ def class_from_string(field)
72
+ str = field.to_s.split('_').map(&:capitalize!).join
73
+ str.chop! if str.end_with?('s')
74
+ Object.const_get('Nexpose').const_get(str)
75
+ end
76
+ end
77
+ end
@@ -65,14 +65,14 @@ module Nexpose
65
65
  # Get a list of all assets currently associated with a group.
66
66
  #
67
67
  # @param [Fixnum] dev_id Unique identifier of a device (asset).
68
- # @return [Array[Asset]] List of group assets.
68
+ # @return [Array[FilteredAsset]] List of group assets.
69
69
  #
70
70
  def group_assets(group_id)
71
71
  payload = { 'sort' => 'assetName',
72
72
  'table-id' => 'group-assets',
73
73
  'groupID' => group_id }
74
74
  results = DataTable._get_json_table(self, '/data/asset/group', payload)
75
- results.map { |a| Asset.new(a) }
75
+ results.map { |a| FilteredAsset.new(a) }
76
76
  end
77
77
 
78
78
  # List the vulnerability findings for a given device ID.
@@ -11,7 +11,7 @@ module Nexpose
11
11
  # @param [String] field Constant from Search::Field
12
12
  # @param [String] operator Constant from Search::Operator
13
13
  # @param [String] value Search term or constant from Search::Value
14
- # @return [Array[Asset]] List of matching assets.
14
+ # @return [Array[FilteredAsset]] List of matching assets.
15
15
  #
16
16
  def filter(field, operator, value = '')
17
17
  criterion = Criterion.new(field, operator, value)
@@ -32,17 +32,17 @@ module Nexpose
32
32
  # results = nsc.search(criteria)
33
33
  #
34
34
  # @param [Criteria] criteria Criteria search object.
35
- # @return [Array[Asset]] List of matching assets.
35
+ # @return [Array[FilteredAsset]] List of matching assets.
36
36
  #
37
37
  def search(criteria)
38
38
  results = DataTable._get_json_table(self,
39
39
  '/data/asset/filterAssets',
40
40
  criteria._to_payload)
41
- results.map { |a| Asset.new(a) }
41
+ results.map { |a| FilteredAsset.new(a) }
42
42
  end
43
43
  end
44
44
 
45
- # Constans for performing Asset Filter searches and generating Dynamic Asset
45
+ # Constants for performing Asset Filter searches and generating Dynamic Asset
46
46
  # Groups.
47
47
  #
48
48
  module Search
@@ -349,7 +349,7 @@ module Nexpose
349
349
 
350
350
  # Asset data as returned by an Asset Filter search.
351
351
  #
352
- class Asset
352
+ class FilteredAsset
353
353
 
354
354
  # Unique identifier of this asset. Also known as device ID.
355
355
  attr_reader :id
data/lib/nexpose/util.rb CHANGED
@@ -104,7 +104,7 @@ module Nexpose
104
104
  # @return [Time] Time, if it can be converted.
105
105
  #
106
106
  def to_time(time_string)
107
- Time.strptime(time_string.to_s, '%Y%m%dT%H%M%S.%LZ')
107
+ Time.strptime(time_string.to_s, '%Y%m%dT%H%M%S.%L%Z')
108
108
  end
109
109
 
110
110
  # Convert a time object into a UTC ISO 8601 basic date-time format.
@@ -1,4 +1,4 @@
1
1
  module Nexpose
2
2
  # The latest version of the Nexpose gem
3
- VERSION = '0.8.17'
3
+ VERSION = '0.8.18'
4
4
  end
data/lib/nexpose/vuln.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module Nexpose
2
-
3
2
  class Connection
4
3
  include XMLUtils
5
4
 
@@ -18,9 +17,9 @@ module Nexpose
18
17
  if response.success
19
18
  response.res.elements.each('VulnerabilityListingResponse/VulnerabilitySummary') do |vuln|
20
19
  if full
21
- vulns << VulnerabilitySummary.parse(vuln)
20
+ vulns << XML::VulnerabilitySummary.parse(vuln)
22
21
  else
23
- vulns << Vulnerability.new(vuln.attributes['id'],
22
+ vulns << XML::Vulnerability.new(vuln.attributes['id'],
24
23
  vuln.attributes['title'],
25
24
  vuln.attributes['severity'].to_i)
26
25
  end
@@ -63,7 +62,7 @@ module Nexpose
63
62
  response = execute(xml, '1.2')
64
63
  if response.success
65
64
  response.res.elements.each('VulnerabilityDetailsResponse/Vulnerability') do |vuln|
66
- return VulnerabilityDetail.parse(vuln)
65
+ return XML::VulnerabilityDetail.parse(vuln)
67
66
  end
68
67
  end
69
68
  end
@@ -79,7 +78,7 @@ module Nexpose
79
78
  uri = "/data/vulnerability/vulnerabilities/dyntable.xml?tableID=VulnCheckSynopsis&phrase=#{URI.encode(search_term)}&allWords=#{all_words}"
80
79
  data = DataTable._get_dyn_table(self, uri)
81
80
  data.map do |vuln|
82
- VulnCheck.new(vuln)
81
+ XML::VulnCheck.new(vuln)
83
82
  end
84
83
  end
85
84
 
@@ -99,142 +98,130 @@ module Nexpose
99
98
  end
100
99
  end
101
100
 
102
- # Basic vulnerability information. Only includes ID, title, and severity.
101
+ # Object definitions which are derived from XML values.
103
102
  #
104
- class Vulnerability
105
-
106
- # The unique ID string for this vulnerability
107
- attr_reader :id
108
-
109
- # The title of this vulnerability
110
- attr_reader :title
111
-
112
- # How critical the vulnerability is on a scale of 1 to 10.
113
- attr_reader :severity
114
-
115
- def initialize(id, title, severity)
116
- @id, @title, @severity = id, title, severity.to_i
103
+ module XML
104
+ # Basic vulnerability information. Only includes ID, title, and severity.
105
+ #
106
+ class Vulnerability
107
+ # The unique ID string for this vulnerability
108
+ attr_reader :id
109
+ # The title of this vulnerability
110
+ attr_reader :title
111
+ # How critical the vulnerability is on a scale of 1 to 10.
112
+ attr_reader :severity
113
+
114
+ def initialize(id, title, severity)
115
+ @id, @title, @severity = id, title, severity.to_i
116
+ end
117
117
  end
118
- end
119
-
120
- # Vulnerability Check information.
121
- #
122
- class VulnCheck < Vulnerability
123
118
 
124
- attr_reader :check_id
125
- # @return [Array[String]] Categories that this check is a member of.
126
- # Note that this is note the same as the categories from #list_vuln_categories.
127
- attr_reader :categories
128
- # @return [String] Check type. @see #list_vuln_types
129
- attr_reader :check_type
130
-
131
- def initialize(json)
132
- @id = json['Vuln ID']
133
- @check_id = json['Vuln Check ID']
134
- @title = json['Vulnerability']
135
- @severity = json['Severity'].to_i
136
- @check_type = json['Check Type']
137
- @categories = json['Category'].split(/, */)
119
+ # Vulnerability Check information.
120
+ #
121
+ class VulnCheck < Vulnerability
122
+ attr_reader :check_id
123
+ # @return [Array[String]] Categories that this check is a member of.
124
+ # Note that this is note the same as the categories from #list_vuln_categories.
125
+ attr_reader :categories
126
+ # @return [String] Check type. @see #list_vuln_types
127
+ attr_reader :check_type
128
+
129
+ def initialize(json)
130
+ @id = json['Vuln ID']
131
+ @check_id = json['Vuln Check ID']
132
+ @title = json['Vulnerability']
133
+ @severity = json['Severity'].to_i
134
+ @check_type = json['Check Type']
135
+ @categories = json['Category'].split(/, */)
136
+ end
138
137
  end
139
- end
140
-
141
- # Summary of a vulnerability.
142
- #
143
- class VulnerabilitySummary < Vulnerability
144
-
145
- # PCI severity value for the vulnerability on a scale of 1 to 5.
146
- attr_accessor :pci_severity
147
-
148
- # Whether all checks for the vulnerability are safe.
149
- # Unsafe checks may cause denial of service or otherwise disrupt system performance.
150
- attr_accessor :safe
151
-
152
- # A vulnerability is considered "credentialed" when all of its checks
153
- # require credentials or if the check depends on previous authentication
154
- # during a scan.
155
- attr_accessor :credentials
156
-
157
- # When this vulnerability was first included in the application.
158
- attr_accessor :added
159
-
160
- # The last date the vulnerability was modified.
161
- attr_accessor :modified
162
-
163
- # The date when the information about the vulnerability was first released.
164
- attr_accessor :published
165
138
 
166
- # How the vulnerability is exploited according to PCI standards.
167
- attr_accessor :cvss_vector
168
-
169
- # The computation of the Common Vulnerability Scoring System indicating
170
- # compliance with PCI standards on a scale from 0 to 10.0.
171
- attr_accessor :cvss_score
172
-
173
- def self.parse_attributes(xml)
174
- vuln = new(xml.attributes['id'],
175
- xml.attributes['title'],
176
- xml.attributes['severity'].to_i)
177
-
178
- vuln.pci_severity = xml.attributes['pciSeverity'].to_i
179
- vuln.safe = xml.attributes['safe'] == 'true' # or xml.attributes['safe'] == '1'
180
- vuln.added = Date.parse(xml.attributes['added'])
181
- vuln.modified = Date.parse(xml.attributes['modified'])
182
- vuln.credentials = xml.attributes['requiresCredentials'] == 'true'
183
-
184
- # These three fields are optional in the XSD.
185
- vuln.published = Date.parse(xml.attributes['published']) if xml.attributes['published']
186
- vuln.cvss_vector = xml.attributes['cvssVector'] if xml.attributes['cvssVector']
187
- vuln.cvss_score = xml.attributes['cvssScore'].to_f if xml.attributes['cvssScore']
188
- vuln
189
- end
139
+ # Summary of a vulnerability.
140
+ #
141
+ class VulnerabilitySummary < Vulnerability
142
+ # PCI severity value for the vulnerability on a scale of 1 to 5.
143
+ attr_accessor :pci_severity
144
+ # Whether all checks for the vulnerability are safe.
145
+ # Unsafe checks may cause denial of service or otherwise disrupt system performance.
146
+ attr_accessor :safe
147
+ # A vulnerability is considered "credentialed" when all of its checks
148
+ # require credentials or if the check depends on previous authentication
149
+ # during a scan.
150
+ attr_accessor :credentials
151
+ # When this vulnerability was first included in the application.
152
+ attr_accessor :added
153
+ # The last date the vulnerability was modified.
154
+ attr_accessor :modified
155
+ # The date when the information about the vulnerability was first released.
156
+ attr_accessor :published
157
+ # How the vulnerability is exploited according to PCI standards.
158
+ attr_accessor :cvss_vector
159
+ # The computation of the Common Vulnerability Scoring System indicating
160
+ # compliance with PCI standards on a scale from 0 to 10.0.
161
+ attr_accessor :cvss_score
162
+
163
+ def self.parse_attributes(xml)
164
+ vuln = new(xml.attributes['id'],
165
+ xml.attributes['title'],
166
+ xml.attributes['severity'].to_i)
167
+
168
+ vuln.pci_severity = xml.attributes['pciSeverity'].to_i
169
+ vuln.safe = xml.attributes['safe'] == 'true' # or xml.attributes['safe'] == '1'
170
+ vuln.added = Date.parse(xml.attributes['added'])
171
+ vuln.modified = Date.parse(xml.attributes['modified'])
172
+ vuln.credentials = xml.attributes['requiresCredentials'] == 'true'
173
+
174
+ # These three fields are optional in the XSD.
175
+ vuln.published = Date.parse(xml.attributes['published']) if xml.attributes['published']
176
+ vuln.cvss_vector = xml.attributes['cvssVector'] if xml.attributes['cvssVector']
177
+ vuln.cvss_score = xml.attributes['cvssScore'].to_f if xml.attributes['cvssScore']
178
+ vuln
179
+ end
190
180
 
191
- def self.parse(xml)
192
- parse_attributes(xml)
181
+ def self.parse(xml)
182
+ parse_attributes(xml)
183
+ end
193
184
  end
194
- end
195
-
196
- # Details for a vulnerability.
197
- #
198
- class VulnerabilityDetail < VulnerabilitySummary
199
-
200
- # The HTML Description of this vulnerability.
201
- attr_accessor :description
202
-
203
- # External References for this vulnerability.
204
- # Array containing (Reference)
205
- attr_accessor :references
206
185
 
207
- # The HTML Solution for this vulnerability.
208
- attr_accessor :solution
209
-
210
- def initialize(id, title, severity)
211
- @id, @title, @severity = id, title, severity
212
- @references = []
213
- end
186
+ # Details for a vulnerability.
187
+ #
188
+ class VulnerabilityDetail < VulnerabilitySummary
189
+ # The HTML Description of this vulnerability.
190
+ attr_accessor :description
191
+ # External References for this vulnerability.
192
+ # Array containing (Reference)
193
+ attr_accessor :references
194
+ # The HTML Solution for this vulnerability.
195
+ attr_accessor :solution
196
+
197
+ def initialize(id, title, severity)
198
+ @id, @title, @severity = id, title, severity
199
+ @references = []
200
+ end
214
201
 
215
- def self.parse(xml)
216
- vuln = parse_attributes(xml)
202
+ def self.parse(xml)
203
+ vuln = parse_attributes(xml)
217
204
 
218
- vuln.description = REXML::XPath.first(xml, 'description').text
219
- vuln.solution = REXML::XPath.first(xml, 'solution').text
205
+ vuln.description = REXML::XPath.first(xml, 'description').text
206
+ vuln.solution = REXML::XPath.first(xml, 'solution').text
220
207
 
221
- xml.elements.each('references/reference') do |ref|
222
- vuln.references << Reference.new(ref.attributes['source'], ref.text)
208
+ xml.elements.each('references/reference') do |ref|
209
+ vuln.references << Reference.new(ref.attributes['source'], ref.text)
210
+ end
211
+ vuln
223
212
  end
224
- vuln
225
213
  end
226
- end
227
214
 
228
- # Reference information for a Vulnerability.
229
- #
230
- class Reference
231
-
232
- attr_reader :source
233
- attr_reader :reference
215
+ # Reference information for a Vulnerability.
216
+ #
217
+ class Reference
218
+ attr_reader :source
219
+ attr_reader :reference
234
220
 
235
- def initialize(source, reference)
236
- @source = source
237
- @reference = reference
221
+ def initialize(source, reference)
222
+ @source = source
223
+ @reference = reference
224
+ end
238
225
  end
239
226
  end
240
227
 
@@ -243,7 +230,6 @@ module Nexpose
243
230
  # cross-referenced to the String ID to be used elsewhere.
244
231
  #
245
232
  class VulnFinding
246
-
247
233
  # Unique identifier of the vulnerability.
248
234
  attr_reader :id
249
235
  # Unique, console-specific identifier of the vulnerability.
@@ -286,7 +272,6 @@ module Nexpose
286
272
  # cross-referenced to the String ID to be used elsewhere.
287
273
  #
288
274
  class VulnSynopsis < VulnFinding
289
-
290
275
  def initialize(hash)
291
276
  @id = hash['Vuln ID'].to_i
292
277
  @title = hash['Vulnerability']
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.17
4
+ version: 0.8.18
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-12-11 00:00:00.000000000 Z
14
+ date: 2014-12-15 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rex
@@ -87,6 +87,7 @@ files:
87
87
  - lib/nexpose.rb
88
88
  - lib/nexpose/ajax.rb
89
89
  - lib/nexpose/alert.rb
90
+ - lib/nexpose/api.rb
90
91
  - lib/nexpose/api_request.rb
91
92
  - lib/nexpose/common.rb
92
93
  - lib/nexpose/connection.rb