nexpose 0.9.3 → 0.9.4
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 +4 -4
- data/CONTRIBUTING.md +91 -0
- data/README.markdown +1 -1
- data/lib/nexpose.rb +3 -1
- data/lib/nexpose/asset.rb +276 -0
- data/lib/nexpose/common.rb +40 -1
- data/lib/nexpose/external.rb +205 -0
- data/lib/nexpose/shared_credential.rb +1 -1
- data/lib/nexpose/site.rb +8 -3
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/vuln.rb +46 -5
- data/lib/nexpose/vuln_def.rb +174 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65b6a8c8e5b9a22b4554cad85898b6e54a4f9c87
|
4
|
+
data.tar.gz: 4f75da07def218ce18d31559225d7598ceb07828
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7dff42cc42cc00d08077832ecb896db3fa13b12ae97c2fe2e93b3165d8a0e5597c0ae56d4dd83a00b60dcd3a4083dfd04dc6f80eab9765437b6afc6df6d5e760
|
7
|
+
data.tar.gz: b6564635a8abf0ee9a3231809e938c2b9d189099ad96360a36b59ac690e7e171803caf819235a3b2d0a875fd40a2b520c59497fe3effb6d226f1f55330fea42b
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Contributing to nexpose-client
|
2
|
+
|
3
|
+
The users and maintainers of nexpose-client would greatly appreciate any contributions
|
4
|
+
you can make to the project. These contributions typically come in the form of
|
5
|
+
filed bugs/issues or pull requests (PRs). These contributions routinely result
|
6
|
+
in new versions of the [nexpose-client
|
7
|
+
gem](https://rubygems.org/gems/nexpose-client) and the
|
8
|
+
[nexpose-client release](https://github.com/rapid7/nexpose-client/releases) to be released. The
|
9
|
+
process for each is outlined below.
|
10
|
+
|
11
|
+
## Contributing Issues / Bug Reports
|
12
|
+
|
13
|
+
If you encounter any bugs or problems with nexpose-client, please file them
|
14
|
+
[here](https://github.com/rapid7/nexpose-client/issues/new), providing as much detail as
|
15
|
+
possible. If the bug is straight-forward enough and you understand the fix for
|
16
|
+
the bug well enough, you may take the simpler, less-paperwork route and simply
|
17
|
+
file a PR with the fix and the necessary details.
|
18
|
+
|
19
|
+
## Contributing Code
|
20
|
+
|
21
|
+
nexpose-client uses a model nearly identical to that of
|
22
|
+
[Metasploit](https://github.com/rapid7/metasploit-framework) as outlined
|
23
|
+
[here](https://github.com/rapid7/metasploit-framework/wiki/Setting-Up-a-Metasploit-Development-Environment),
|
24
|
+
at least from a ```git``` perspective. If you've been through that process
|
25
|
+
(or, even better, you've been through it many times with many people), you can
|
26
|
+
do exactly what you did for Metasploit but with nexpose-client and ignore the rest of
|
27
|
+
this document.
|
28
|
+
|
29
|
+
On the other hand, if you haven't, read on!
|
30
|
+
|
31
|
+
### Fork and Clone
|
32
|
+
|
33
|
+
Generally, this should only need to be done once, or if you need to start over.
|
34
|
+
|
35
|
+
1. Fork nexpose-client: Visit https://github.com/rapid7/nexpose-client and click Fork,
|
36
|
+
selecting your github account if prompted
|
37
|
+
2. Clone ```git@github.com:<your-github-username>/nexpose-client.git```, replacing
|
38
|
+
```<your-github-username>``` with, you guessed it, your Github username.
|
39
|
+
3. Add the master nexpose-client repository as your upstream:
|
40
|
+
```
|
41
|
+
git remote add upstream git://github.com/rapid7/nexpose-client.git
|
42
|
+
git fetch --all
|
43
|
+
```
|
44
|
+
|
45
|
+
### Branch and Improve
|
46
|
+
|
47
|
+
If you have a contribution to make, first create a branch to contain your
|
48
|
+
work. The name is yours to choose, however generally it should roughly
|
49
|
+
describe what you are doing. In this example, and from here on out, the
|
50
|
+
branch will be wow, but you should change this.
|
51
|
+
|
52
|
+
```
|
53
|
+
git fetch --all
|
54
|
+
git checkout master
|
55
|
+
git rebase upstream/master
|
56
|
+
git checkout -b wow
|
57
|
+
```
|
58
|
+
|
59
|
+
Now, make your changes, committing as necessary, using useful commit messages:
|
60
|
+
|
61
|
+
```
|
62
|
+
vim CONTRIBUTING.md
|
63
|
+
git add CONTRIBUTING.md
|
64
|
+
git commit -m "Adds a document on how to contribute to nexpose-client." -a
|
65
|
+
```
|
66
|
+
|
67
|
+
Please note that changes to [lib/nexpose/version.rb](https://github.com/rapid7/nexpose-client/blob/master/lib/nexpose/version.rb) in PRs are almost never necessary.
|
68
|
+
|
69
|
+
Now push your changes to your fork:
|
70
|
+
|
71
|
+
```
|
72
|
+
git push origin wow
|
73
|
+
```
|
74
|
+
|
75
|
+
Finally, submit the PR. Navigate to ```https://github.com/<your-github-username>/nexpose-client/compare/wow```, fill in the details, and submit.
|
76
|
+
|
77
|
+
## Releasing New Versions
|
78
|
+
|
79
|
+
Typically this process is reserved for contributors with push permissions to
|
80
|
+
nexpose-client:
|
81
|
+
|
82
|
+
### Release New Gem
|
83
|
+
|
84
|
+
1. Get an account on [Rubygems](https://rubygems.org)
|
85
|
+
2. Contact one of the nexpose-client project contributors and have them add you to the nexpose-client gem
|
86
|
+
3. Edit [lib/nexpose/version.rb](https://github.com/rapid7/nexpose-client/blob/master/lib/nexpose/version.rb) and increment ```VERSION```. Commit and push to origin/upstream master.
|
87
|
+
4. Run ```rake release```
|
88
|
+
|
89
|
+
### Github Release
|
90
|
+
|
91
|
+
Some users may prefer to consume nexpose-client in a manner other than using git itself. For that reason, Github offers [Releases](https://github.com/blog/1547-release-your-software). Whenever a new version of the software is to be released, be kind and also create a new [Release](https://github.com/rapid7/nexpose-client/releases), using a versioning scheme identical to that used for the gem.
|
data/README.markdown
CHANGED
@@ -11,7 +11,7 @@ This gem is heavily used for internal, automated testing of the Nexpose product.
|
|
11
11
|
|
12
12
|
## Contributions
|
13
13
|
|
14
|
-
We welcome contributions to this package.
|
14
|
+
We welcome contributions to this package. Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
|
15
15
|
|
16
16
|
Our coding standards include:
|
17
17
|
|
data/lib/nexpose.rb
CHANGED
@@ -50,7 +50,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
50
50
|
require 'date'
|
51
51
|
require 'time'
|
52
52
|
require 'rexml/document'
|
53
|
-
require 'nokogiri'
|
54
53
|
require 'net/https'
|
55
54
|
require 'net/http'
|
56
55
|
require 'uri'
|
@@ -64,6 +63,7 @@ require 'nexpose/alert'
|
|
64
63
|
require 'nexpose/ajax'
|
65
64
|
require 'nexpose/api'
|
66
65
|
require 'nexpose/api_request'
|
66
|
+
require 'nexpose/asset'
|
67
67
|
require 'nexpose/common'
|
68
68
|
require 'nexpose/console'
|
69
69
|
require 'nexpose/credential'
|
@@ -74,6 +74,7 @@ require 'nexpose/device'
|
|
74
74
|
require 'nexpose/discovery'
|
75
75
|
require 'nexpose/discovery/filter'
|
76
76
|
require 'nexpose/engine'
|
77
|
+
require 'nexpose/external'
|
77
78
|
require 'nexpose/filter'
|
78
79
|
require 'nexpose/global_settings'
|
79
80
|
require 'nexpose/group'
|
@@ -94,6 +95,7 @@ require 'nexpose/tag/criteria'
|
|
94
95
|
require 'nexpose/ticket'
|
95
96
|
require 'nexpose/user'
|
96
97
|
require 'nexpose/vuln'
|
98
|
+
require 'nexpose/vuln_def'
|
97
99
|
require 'nexpose/vuln_exception'
|
98
100
|
require 'nexpose/connection'
|
99
101
|
require 'nexpose/maint'
|
@@ -0,0 +1,276 @@
|
|
1
|
+
module Nexpose
|
2
|
+
# Asset object as return from the 2.1 API.
|
3
|
+
#
|
4
|
+
class Asset < APIObject
|
5
|
+
# Unique identifier of the asset on the Nexpose console.
|
6
|
+
attr_reader :id
|
7
|
+
# Primary IP address of the asset.
|
8
|
+
attr_reader :ip
|
9
|
+
# MAC address of the asset.
|
10
|
+
attr_reader :mac
|
11
|
+
# Known host names found for the asset.
|
12
|
+
attr_reader :host_names
|
13
|
+
# Operating system name.
|
14
|
+
attr_reader :os_name
|
15
|
+
# The CPE for the asset's operating system.
|
16
|
+
attr_reader :os_cpe
|
17
|
+
# The host type of the asset. One of: GUEST, HYPERVISOR, PHYSICAL, MOBILE.
|
18
|
+
attr_reader :host_type
|
19
|
+
|
20
|
+
# Assessment summary of the asset, including most recent scan info. [Lazy]
|
21
|
+
attr_reader :assessment
|
22
|
+
# Service endpoints enumerated on the asset. [Lazy]
|
23
|
+
attr_reader :services
|
24
|
+
# Software enumerated on the asset. [Lazy]
|
25
|
+
attr_reader :software
|
26
|
+
# Vulnerabilities detected on the asset. [Lazy]
|
27
|
+
attr_reader :vulnerabilities
|
28
|
+
# Vulnerability instances detected on the asset. [Lazy]
|
29
|
+
attr_reader :vulnerability_instances
|
30
|
+
# Vulnerability exploits to which this asset is susceptible. [Lazy]
|
31
|
+
attr_reader :exploits
|
32
|
+
# Malware kits to which this asset is susceptible. [Lazy]
|
33
|
+
attr_reader :malware_kits
|
34
|
+
|
35
|
+
# User accounts enumerated on the asset. [Lazy]
|
36
|
+
attr_reader :user_accounts
|
37
|
+
# Group accounts enumerated on the asset. [Lazy]
|
38
|
+
attr_reader :group_accounts
|
39
|
+
# Files and directories that have been enumerated on the asset. [Lazy]
|
40
|
+
attr_reader :files
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
@addresses = []
|
44
|
+
@host_names = []
|
45
|
+
end
|
46
|
+
|
47
|
+
# Load an asset from the provided console.
|
48
|
+
#
|
49
|
+
# @param [Connection] nsc Active connection to a Nexpose console.
|
50
|
+
# @param [String] id Unique identifier of an asset.
|
51
|
+
# @return [Asset] The requested asset, if found.
|
52
|
+
#
|
53
|
+
def self.load(nsc, id)
|
54
|
+
uri = "/api/2.1/assets/#{id}"
|
55
|
+
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
56
|
+
hash = JSON.parse(resp, symbolize_names: true)
|
57
|
+
new.object_from_hash(nsc, hash)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Software found on an asset.
|
62
|
+
#
|
63
|
+
class Software < APIObject
|
64
|
+
# The software product name.
|
65
|
+
attr_reader :product
|
66
|
+
# The version of software detected.
|
67
|
+
attr_reader :version
|
68
|
+
# Name of the vendor publishing the software.
|
69
|
+
attr_reader :vendor
|
70
|
+
# The family of software.
|
71
|
+
attr_reader :family
|
72
|
+
# Type of software.
|
73
|
+
attr_reader :type
|
74
|
+
end
|
75
|
+
|
76
|
+
# A service endpoint on an asset.
|
77
|
+
#
|
78
|
+
class Service < APIObject
|
79
|
+
# Name of the service. [Optional]
|
80
|
+
attr_reader :name
|
81
|
+
# Port on which the service is running.
|
82
|
+
attr_reader :port
|
83
|
+
# Protocol used to communicate to the port. @see Service::Protocol.
|
84
|
+
attr_reader :protocol
|
85
|
+
|
86
|
+
def initialize(port = 0, protocol = Protocol::RAW, name = nil)
|
87
|
+
@port, @protocol, @name = port, protocol, name
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_h
|
91
|
+
{ name: name,
|
92
|
+
port: port,
|
93
|
+
protocol: protocol }
|
94
|
+
end
|
95
|
+
|
96
|
+
def <=>(other)
|
97
|
+
c = port <=> other.port
|
98
|
+
return c unless c == 0
|
99
|
+
c = protocol <=> other.protocol
|
100
|
+
return c unless c == 0
|
101
|
+
name <=> other.name
|
102
|
+
end
|
103
|
+
|
104
|
+
def ==(other)
|
105
|
+
eql?(other)
|
106
|
+
end
|
107
|
+
|
108
|
+
def eql?(other)
|
109
|
+
port.eql?(other.port) && protocol.eql?(other.protocol) && name.eql?(other.name)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Valid protocol values for a service endpoint.
|
113
|
+
module Protocol
|
114
|
+
# Internet Protocol
|
115
|
+
IP = 'IP'
|
116
|
+
# Internet Control Message Protocol
|
117
|
+
ICMP = 'ICMP'
|
118
|
+
# Internet Group Management Protocol
|
119
|
+
IGMP = 'IGMP'
|
120
|
+
# Gateway-to-Gateway Protocol
|
121
|
+
GGP = 'GGP'
|
122
|
+
# Transmission Control Protocol
|
123
|
+
TCP = 'TCP'
|
124
|
+
# PARC Universal Protocol
|
125
|
+
PUP = 'PUP'
|
126
|
+
# User Datagram Protocol
|
127
|
+
UDP = 'UDP'
|
128
|
+
# Internet Datagram Protocol
|
129
|
+
IDP = 'IDP'
|
130
|
+
# Encapsulating Security Payload
|
131
|
+
ESP = 'ESP'
|
132
|
+
# Network Disk Protocol
|
133
|
+
ND = 'ND'
|
134
|
+
# Raw Packet (or unknown)
|
135
|
+
RAW = 'RAW'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# User accounts on an asset.
|
140
|
+
#
|
141
|
+
class UserAccount < APIObject
|
142
|
+
# User account name.
|
143
|
+
attr_reader :name
|
144
|
+
# Unique identifier of the user as determined by the asset (not Nexpose).
|
145
|
+
attr_reader :id
|
146
|
+
# Full name of the user.
|
147
|
+
attr_reader :full_name
|
148
|
+
# Account attributes.
|
149
|
+
attr_reader :attributes
|
150
|
+
|
151
|
+
def initialize(name = nil, id = 0, full_name = nil, attributes = [])
|
152
|
+
@id, @name, @full_name, @attributes = id, name, full_name, attributes
|
153
|
+
end
|
154
|
+
|
155
|
+
def to_h
|
156
|
+
{ name: name,
|
157
|
+
id: id,
|
158
|
+
full_name: full_name,
|
159
|
+
attributes: Attributes.to_hash(attributes) }
|
160
|
+
end
|
161
|
+
|
162
|
+
def <=>(other)
|
163
|
+
c = name <=> other.name
|
164
|
+
return c unless c == 0
|
165
|
+
c = id <=> other.id
|
166
|
+
return c unless c == 0
|
167
|
+
c = full_name <=> other.full_name
|
168
|
+
return c unless c == 0
|
169
|
+
attributes <=> other.attributes
|
170
|
+
end
|
171
|
+
|
172
|
+
def ==(other)
|
173
|
+
eql?(other)
|
174
|
+
end
|
175
|
+
|
176
|
+
def eql?(other)
|
177
|
+
name.eql?(other.name) && id.eql?(other.id) && full_name.eql?(other.full_name) && attributes.eql?(other.attributes)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Group accounts on an asset.
|
182
|
+
#
|
183
|
+
class GroupAccount < APIObject
|
184
|
+
# Group account name.
|
185
|
+
attr_reader :name
|
186
|
+
# Unique identifier of the group as determined by the asset (not Nexpose).
|
187
|
+
attr_reader :id
|
188
|
+
# Group attributes.
|
189
|
+
attr_reader :attributes
|
190
|
+
|
191
|
+
def initialize(name = nil, id = 0, attributes = [])
|
192
|
+
@name = name
|
193
|
+
@id = id
|
194
|
+
@attributes = attributes
|
195
|
+
end
|
196
|
+
|
197
|
+
def to_h
|
198
|
+
{ name: name,
|
199
|
+
id: id,
|
200
|
+
attributes: Attributes.to_hash(attributes) }
|
201
|
+
end
|
202
|
+
|
203
|
+
def <=>(other)
|
204
|
+
c = name <=> other.name
|
205
|
+
return c unless c == 0
|
206
|
+
c = id <=> other.id
|
207
|
+
return c unless c == 0
|
208
|
+
attributes <=> other.attributes
|
209
|
+
end
|
210
|
+
|
211
|
+
def ==(other)
|
212
|
+
eql?(other)
|
213
|
+
end
|
214
|
+
|
215
|
+
def eql?(other)
|
216
|
+
name.eql?(other.name) && id.eql?(other.id) && attributes.eql?(other.attributes)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# File or directory on an asset.
|
221
|
+
#
|
222
|
+
class File < APIObject
|
223
|
+
# Name of the file.
|
224
|
+
attr_reader :name
|
225
|
+
# Size of the file.
|
226
|
+
attr_reader :size
|
227
|
+
# File attributes.
|
228
|
+
attr_reader :attributes
|
229
|
+
# Whether the file is a directory.
|
230
|
+
attr_reader :directory
|
231
|
+
|
232
|
+
def initialize(name = nil, size = 0, directory = false, attributes = [])
|
233
|
+
@name, @size, @directory, @attributes = name, size, directory, attributes
|
234
|
+
end
|
235
|
+
|
236
|
+
def directory?
|
237
|
+
directory
|
238
|
+
end
|
239
|
+
|
240
|
+
def to_h
|
241
|
+
{ name: name,
|
242
|
+
size: size,
|
243
|
+
directory: directory,
|
244
|
+
attributes: Attributes.to_hash(attributes) }
|
245
|
+
end
|
246
|
+
|
247
|
+
def <=>(other)
|
248
|
+
c = name <=> other.name
|
249
|
+
return c unless c == 0
|
250
|
+
c = size <=> other.size
|
251
|
+
return c unless c == 0
|
252
|
+
c = directory <=> other.directory
|
253
|
+
return c unless c == 0
|
254
|
+
attributes <=> other.attributes
|
255
|
+
end
|
256
|
+
|
257
|
+
def ==(other)
|
258
|
+
eql?(other)
|
259
|
+
end
|
260
|
+
|
261
|
+
def eql?(other)
|
262
|
+
name.eql?(other.name) && size.eql?(other.size) && directory.eql?(other.directory) && attributes.eql?(other.attributes)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Assessment statistics for an asset.
|
267
|
+
#
|
268
|
+
class Assessment < APIObject
|
269
|
+
# The date an asset was last scanned.
|
270
|
+
attr_reader :last_scan_date
|
271
|
+
# The ID of the scan which last assessed the asset.
|
272
|
+
attr_reader :last_scan_id
|
273
|
+
# The current risk score of the asset.
|
274
|
+
attr_reader :risk_score
|
275
|
+
end
|
276
|
+
end
|
data/lib/nexpose/common.rb
CHANGED
@@ -110,6 +110,18 @@ module Nexpose
|
|
110
110
|
attr_accessor :incremental
|
111
111
|
attr_accessor :repeater_type
|
112
112
|
|
113
|
+
# Extended attributes added with the new scheduler implementation
|
114
|
+
attr_accessor :is_extended
|
115
|
+
attr_accessor :hour
|
116
|
+
attr_accessor :minute
|
117
|
+
attr_accessor :date
|
118
|
+
attr_accessor :day
|
119
|
+
attr_accessor :occurrence
|
120
|
+
attr_accessor :start_month
|
121
|
+
attr_accessor :timezone
|
122
|
+
attr_accessor :next_run_time
|
123
|
+
attr_accessor :template
|
124
|
+
|
113
125
|
def initialize(type, interval, start, enabled = true)
|
114
126
|
@type = type
|
115
127
|
@interval = interval
|
@@ -117,16 +129,33 @@ module Nexpose
|
|
117
129
|
@enabled = enabled
|
118
130
|
end
|
119
131
|
|
132
|
+
def self.from_hash(hash)
|
133
|
+
schedule = new(hash[:type], hash[:interval], hash[:start])
|
134
|
+
hash.each do |k, v|
|
135
|
+
schedule.instance_variable_set("@#{k}", v)
|
136
|
+
end
|
137
|
+
schedule
|
138
|
+
end
|
139
|
+
|
120
140
|
def as_xml
|
121
141
|
xml = REXML::Element.new('Schedule')
|
122
142
|
xml.attributes['enabled'] = @enabled ? 1 : 0
|
123
143
|
xml.attributes['type'] = @type
|
124
144
|
xml.attributes['interval'] = @interval
|
125
|
-
xml.attributes['start'] = @start
|
145
|
+
xml.attributes['start'] = @start if @start
|
126
146
|
xml.attributes['maxDuration'] = @max_duration if @max_duration
|
127
147
|
xml.attributes['notValidAfter'] = @not_valid_after if @not_valid_after
|
128
148
|
xml.attributes['incremental'] = @incremental ? 1 : 0 if @incremental
|
129
149
|
xml.attributes['repeaterType'] = @repeater_type if @repeater_type
|
150
|
+
xml.attributes['is_extended'] = @is_extended if @is_extended
|
151
|
+
xml.attributes['hour'] = @hour if @hour
|
152
|
+
xml.attributes['minute'] = @minute if @minute
|
153
|
+
xml.attributes['date'] = @date if @date
|
154
|
+
xml.attributes['day'] = @day if @day
|
155
|
+
xml.attributes['occurrence'] = @occurrence if @occurrence
|
156
|
+
xml.attributes['start_month'] = @start_month if @start_month
|
157
|
+
xml.attributes['timezone'] = @timezone if @timezone
|
158
|
+
xml.attributes['template'] = @template if @template
|
130
159
|
xml
|
131
160
|
end
|
132
161
|
|
@@ -145,6 +174,16 @@ module Nexpose
|
|
145
174
|
schedule.not_valid_after = xml.attributes['notValidAfter'] if xml.attributes['notValidAfter']
|
146
175
|
schedule.incremental = (xml.attributes['incremental'] && xml.attributes['incremental'] == '1')
|
147
176
|
schedule.repeater_type = xml.attributes['repeaterType'] if xml.attributes['repeaterType']
|
177
|
+
schedule.is_extended = xml.attributes['is_extended'] if xml.attributes['is_extended']
|
178
|
+
schedule.hour = xml.attributes['hour'] if xml.attributes['hour']
|
179
|
+
schedule.minute = xml.attributes['minute'] if xml.attributes['minute']
|
180
|
+
schedule.date = xml.attributes['date'] if xml.attributes['date']
|
181
|
+
schedule.day = xml.attributes['day'] if xml.attributes['day']
|
182
|
+
schedule.occurrence = xml.attributes['occurrence'] if xml.attributes['occurrence']
|
183
|
+
schedule.start_month = xml.attributes['start_month'] if xml.attributes['start_month']
|
184
|
+
schedule.timezone = xml.attributes['timezone'] if xml.attributes['timezone']
|
185
|
+
schedule.next_run_time = xml.attributes['next_run_time'] if xml.attributes['next_run_time']
|
186
|
+
schedule.template = xml.attributes['template'] if xml.attributes['template']
|
148
187
|
schedule
|
149
188
|
end
|
150
189
|
|
@@ -0,0 +1,205 @@
|
|
1
|
+
module Nexpose
|
2
|
+
class Connection
|
3
|
+
# Import external assets into a Nexpose console.
|
4
|
+
#
|
5
|
+
# This method will synchronously import a collection of assets into the
|
6
|
+
# console. Each call to this method will be treated as a single event.
|
7
|
+
#
|
8
|
+
# This method should only be used against "static" sites, i.e., those not
|
9
|
+
# tied to a dynamic population service like vSphere, AWS, etc.
|
10
|
+
#
|
11
|
+
# If a paused scan exists on the site at the time of import, the newly
|
12
|
+
# imported assets will not be included in the scan when it resumes.
|
13
|
+
#
|
14
|
+
# @param [Fixnum] site_id Existing site to import assets into.
|
15
|
+
# @param [Array[External::Asset]] assets External assets to import.
|
16
|
+
# @return [Array[ImportResult]] collection of import results.
|
17
|
+
#
|
18
|
+
def import_assets(site_id, assets)
|
19
|
+
json = JSON.generate(Array(assets).map(&:to_h))
|
20
|
+
import_assets_from_json(site_id, json)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Import external assets into a Nexpose console.
|
24
|
+
#
|
25
|
+
# @param [Fixnum] site_id Existing site to import assets into.
|
26
|
+
# @param [String] json JSON representation of assets to import.
|
27
|
+
# @return [Array[ImportResult]] collection of import results.
|
28
|
+
#
|
29
|
+
def import_assets_from_json(site_id, json)
|
30
|
+
uri = "/api/2.1/sites/#{site_id}/assets"
|
31
|
+
# Wait up to 5 minutes for a response.
|
32
|
+
resp = AJAX.post(self, uri, json, AJAX::CONTENT_TYPE::JSON, 300)
|
33
|
+
arr = JSON.parse(resp, symbolize_names: true)
|
34
|
+
arr.map { |e| External::ImportResult.new.object_from_hash(self, e) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Namespace for functionality around importing external assets into Nexpose.
|
39
|
+
#
|
40
|
+
module External
|
41
|
+
# Object for importing assets from external sources into a Nexpose console.
|
42
|
+
# This exists primarily as a convenience for marshalling the data into the
|
43
|
+
# proper JSON format.
|
44
|
+
#
|
45
|
+
# In order to successfully import an asset, it must contain at least one
|
46
|
+
# scannable identifier: IP address, fully qualified domain name, or NetBIOS
|
47
|
+
# name. This ensures that once an asset is imported to the console, it can
|
48
|
+
# be scanned.
|
49
|
+
#
|
50
|
+
# Besides a scannable identifier, all other fields are optional.
|
51
|
+
#
|
52
|
+
class Asset
|
53
|
+
# IPv4 or IPv6 that is the primary identifier of the asset.
|
54
|
+
attr_accessor :ip
|
55
|
+
# A fully qualified domain name of the asset.
|
56
|
+
attr_accessor :fqdn
|
57
|
+
# A NetBIOS name of the asset.
|
58
|
+
attr_accessor :net_bios
|
59
|
+
# The MAC address of the asset.
|
60
|
+
attr_accessor :mac
|
61
|
+
# The host type of the asset. One of: GUEST, HYPERVISOR, PHYSICAL, MOBILE.
|
62
|
+
attr_accessor :host_type
|
63
|
+
# A list of alternate identifiers of the asset. This can include additional
|
64
|
+
# IP addresses and host names.
|
65
|
+
attr_accessor :aliases
|
66
|
+
# The date the asset was scanned. If left blank, the current time will be
|
67
|
+
# used by the console. Use the ISO 8601 basic date-time format.
|
68
|
+
# For example: 20141211T100614.526Z
|
69
|
+
attr_accessor :scan_date
|
70
|
+
# The CPE for the operating system on the asset.
|
71
|
+
attr_accessor :os
|
72
|
+
# A list of CPEs identifying software installed on the asset.
|
73
|
+
attr_accessor :software
|
74
|
+
# A list of service endpoints on the asset.
|
75
|
+
attr_accessor :services
|
76
|
+
# A list of user accounts on the asset.
|
77
|
+
attr_accessor :users
|
78
|
+
# A list of group accounts on the asset.
|
79
|
+
attr_accessor :groups
|
80
|
+
# Files and directories on the asset.
|
81
|
+
attr_accessor :files
|
82
|
+
# A list of key-value attributes associated with the asset.
|
83
|
+
attr_accessor :attributes
|
84
|
+
# Asset-level vulnerabilities.
|
85
|
+
attr_accessor :vulnerabilities
|
86
|
+
|
87
|
+
def initialize
|
88
|
+
@aliases = []
|
89
|
+
@software = []
|
90
|
+
@services = []
|
91
|
+
@attributes = []
|
92
|
+
@users = []
|
93
|
+
@groups = []
|
94
|
+
@files = []
|
95
|
+
@vulnerabilities = []
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_json
|
99
|
+
JSON.generate(to_h)
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_h
|
103
|
+
{ ip: ip,
|
104
|
+
fqdn: fqdn,
|
105
|
+
net_bios: net_bios,
|
106
|
+
mac: mac,
|
107
|
+
host_type: host_type,
|
108
|
+
aliases: aliases,
|
109
|
+
scan_date: scan_date,
|
110
|
+
os: os,
|
111
|
+
software: software,
|
112
|
+
services: services.map(&:to_h),
|
113
|
+
users: users.map(&:to_h),
|
114
|
+
groups: groups.map(&:to_h),
|
115
|
+
files: files.map(&:to_h),
|
116
|
+
vulnerabilities: vulnerabilities.map(&:to_h),
|
117
|
+
attributes: Attributes.to_hash(attributes) }
|
118
|
+
end
|
119
|
+
|
120
|
+
# Valid host types for an asset.
|
121
|
+
module HostType
|
122
|
+
GUEST = 'GUEST'
|
123
|
+
HYPERVISOR = 'HYPERVISOR'
|
124
|
+
PHYSICAL = 'PHYSICAL'
|
125
|
+
MOBILE = 'MOBILE'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# A service endpoint on an asset.
|
130
|
+
#
|
131
|
+
class Service
|
132
|
+
# Name of the service. [Optional]
|
133
|
+
attr_accessor :name
|
134
|
+
# Port on which the service is running.
|
135
|
+
attr_accessor :port
|
136
|
+
# Protocol used to communicate to the port. @see Service::Protocol.
|
137
|
+
attr_accessor :protocol
|
138
|
+
# Vulnerabilities specific to this service endpoint.
|
139
|
+
attr_accessor :vulnerabilities
|
140
|
+
|
141
|
+
def initialize(port, protocol = Protocol::RAW, name = nil)
|
142
|
+
@port, @protocol, @name = port, protocol, name
|
143
|
+
@vulnerabilities = []
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_h
|
147
|
+
{ name: name,
|
148
|
+
port: port,
|
149
|
+
protocol: protocol,
|
150
|
+
vulnerabilities: vulnerabilities.map(&:to_h) }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Vulnerability check object for importing vulnerabilities into Nexpose.
|
155
|
+
#
|
156
|
+
class VulnerabilityCheck
|
157
|
+
# Unique identifier of a vulnerability in Nexpose.
|
158
|
+
attr_accessor :vuln_id
|
159
|
+
# Status of the vulnerability. @see VulnerabilityCheck::Status
|
160
|
+
attr_accessor :status
|
161
|
+
# Unique identifier of a vulnerability instance, typically used for spider
|
162
|
+
# vulns or when multiple instances of a vuln exist on the same service.
|
163
|
+
attr_accessor :key
|
164
|
+
# Explanation of what proves that an asset or service is vulnerable.
|
165
|
+
attr_accessor :proof
|
166
|
+
|
167
|
+
def initialize(vuln_id, status = Status::EXPLOITED, proof = nil, key = nil)
|
168
|
+
@vuln_id, @status, @proof, @key = vuln_id, status, proof, key
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_h
|
172
|
+
{ vuln_id: vuln_id,
|
173
|
+
status: status,
|
174
|
+
key: key,
|
175
|
+
proof: proof }
|
176
|
+
end
|
177
|
+
|
178
|
+
# Valid vulnerability status for import into Nexpose.
|
179
|
+
module Status
|
180
|
+
# Vulnerability verified by exploit.
|
181
|
+
EXPLOITED = 'vulnerable-exploited'
|
182
|
+
# Vulnerable because the service or software version is associated with
|
183
|
+
# a known vulnerability.
|
184
|
+
VERSION = 'vulnerable-version'
|
185
|
+
# A potential vulnerability.
|
186
|
+
POTENTIAL = 'potential'
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Result object returned from an import_assets call, used to correlate the
|
191
|
+
# supplied scannable identifier with the resulting asset ID or any error
|
192
|
+
# messages from a problematic import.
|
193
|
+
#
|
194
|
+
class ImportResult < APIObject
|
195
|
+
# IP or hostname provided during import.
|
196
|
+
attr_reader :name
|
197
|
+
# Resulting asset ID of the created asset, if any.
|
198
|
+
attr_reader :asset_id
|
199
|
+
# The asset created by the import. [Lazy]
|
200
|
+
attr_reader :asset
|
201
|
+
# Any error messages associated with the import of the asset.
|
202
|
+
attr_reader :error_message
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -127,7 +127,7 @@ module Nexpose
|
|
127
127
|
desc = xml.add_element('Description').add_text(@description)
|
128
128
|
|
129
129
|
services = xml.add_element('Services')
|
130
|
-
service = services.add_element('Service').add_attribute('type', @
|
130
|
+
service = services.add_element('Service').add_attribute('type', @service)
|
131
131
|
|
132
132
|
(account = xml.add_element('Account')).add_attribute('type', 'nexpose')
|
133
133
|
account.add_element('Field', { 'name' => 'database' }).add_text(@database)
|
data/lib/nexpose/site.rb
CHANGED
@@ -257,9 +257,14 @@ module Nexpose
|
|
257
257
|
# @param [Fixnum] id Site ID of an existing site.
|
258
258
|
# @return [Site] Site configuration loaded from a Nexpose console.
|
259
259
|
#
|
260
|
-
def self.load(connection, id)
|
261
|
-
|
262
|
-
|
260
|
+
def self.load(connection, id, is_extended = false)
|
261
|
+
if is_extended
|
262
|
+
r = APIRequest.execute(connection.url,
|
263
|
+
%(<SiteConfigRequest session-id="#{connection.session_id}" site-id="#{id}" is_extended="true"/>))
|
264
|
+
else
|
265
|
+
r = APIRequest.execute(connection.url,
|
266
|
+
%(<SiteConfigRequest session-id="#{connection.session_id}" site-id="#{id}"/>))
|
267
|
+
end
|
263
268
|
site = parse(r.res)
|
264
269
|
site.load_dynamic_attributes(connection) if site.dynamic?
|
265
270
|
site
|
data/lib/nexpose/version.rb
CHANGED
data/lib/nexpose/vuln.rb
CHANGED
@@ -45,12 +45,11 @@ module Nexpose
|
|
45
45
|
#
|
46
46
|
# @return [Array[String]] Array of currently valid check types.
|
47
47
|
#
|
48
|
-
def
|
49
|
-
data = DataTable._get_dyn_table(self, '/
|
48
|
+
def vuln_types
|
49
|
+
data = DataTable._get_dyn_table(self, '/data/vulnerability/checktypes/dyntable.xml?tableID=VulnCheckCategorySynopsis')
|
50
50
|
data.map { |c| c['Category'] }
|
51
51
|
end
|
52
|
-
|
53
|
-
alias_method :vuln_types, :list_vuln_types
|
52
|
+
alias_method :list_vuln_types, :vuln_types
|
54
53
|
|
55
54
|
# Retrieve details for a vulnerability.
|
56
55
|
#
|
@@ -92,7 +91,7 @@ module Nexpose
|
|
92
91
|
# Nexpose between the provided dates.
|
93
92
|
#
|
94
93
|
def find_vulns_by_date(from, to = nil)
|
95
|
-
uri = "/
|
94
|
+
uri = "/data/vulnerability/synopsis/dyntable.xml?addedMin=#{from}"
|
96
95
|
uri += "&addedMax=#{to}" if to
|
97
96
|
DataTable._get_dyn_table(self, uri).map { |v| VulnSynopsis.new(v) }
|
98
97
|
end
|
@@ -285,4 +284,46 @@ module Nexpose
|
|
285
284
|
@malware = hash['MalwareSource'] == 'true'
|
286
285
|
end
|
287
286
|
end
|
287
|
+
|
288
|
+
# A vulnerability discovered on an asset.
|
289
|
+
#
|
290
|
+
class Vulnerability < APIObject
|
291
|
+
# Unique identifier of the vulnerability.
|
292
|
+
attr_reader :id
|
293
|
+
# Vulnerability title.
|
294
|
+
attr_reader :title
|
295
|
+
# Full vulnerability definition. [Lazy]
|
296
|
+
attr_reader :vulnerability_definition
|
297
|
+
end
|
298
|
+
|
299
|
+
# An instance of a vulnerability discovered on an asset.
|
300
|
+
#
|
301
|
+
class VulnerabilityInstance < APIObject
|
302
|
+
# ID of the asset where the vulnerability instance was detected.
|
303
|
+
attr_reader :asset_id
|
304
|
+
# IP Address of the asset where the vulnerability instance was detected.
|
305
|
+
attr_reader :asset_ip_address
|
306
|
+
# ID of the scan where the vulnerability instance was detected.
|
307
|
+
attr_reader :scan_id
|
308
|
+
# The ID (natural key) of the vulnerability.
|
309
|
+
attr_reader :vulnerability_id
|
310
|
+
# The time at which the vulnerability test was performed.
|
311
|
+
attr_reader :date
|
312
|
+
# The vulnerable status of the vulnerability.
|
313
|
+
attr_reader :status
|
314
|
+
# The proof which explains why the vulnerability is present on the asset.
|
315
|
+
# The value is often HTML-formatted text.
|
316
|
+
attr_reader :proof
|
317
|
+
# Key that can distinguish the instances of the same type on the system.
|
318
|
+
# For spider vulnerabilities, this is typically the relative URI where the
|
319
|
+
# vuln was discovered.
|
320
|
+
attr_reader :key
|
321
|
+
# The service that the vulnerability test was performed against.
|
322
|
+
attr_reader :service
|
323
|
+
# The port on which the service was running if the vulnerability was found
|
324
|
+
# through a network service, -1 if not defined.
|
325
|
+
attr_reader :port
|
326
|
+
# Protocol the service was providing on which the vulnerability was found.
|
327
|
+
attr_reader :protocol
|
328
|
+
end
|
288
329
|
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Nexpose
|
2
|
+
class Connection
|
3
|
+
# Retrieve all vulnerability definitions currently in a Nexpose console.
|
4
|
+
#
|
5
|
+
# Note, this can easily take 30 seconds to complete and will load over
|
6
|
+
# 55,000 vulnerability definitions.
|
7
|
+
#
|
8
|
+
# @return [Array[VulnerabilityDefinition]] Collection of vulnerability definitions.
|
9
|
+
#
|
10
|
+
def all_vulns
|
11
|
+
uri = '/api/2.0/vulnerability_definitions'
|
12
|
+
resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, per_page: 2_147_483_647)
|
13
|
+
json = JSON.parse(resp, symbolize_names: true)
|
14
|
+
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Search for any vulnerability definitions which refer to a given CVE.
|
18
|
+
#
|
19
|
+
# @param [String] cve A valid CVE.
|
20
|
+
# @return [Array[VulnerabilityDefinition]] A list of vuln definitions which check the CVE.
|
21
|
+
#
|
22
|
+
def find_vulns_by_cve(cve)
|
23
|
+
uri = '/api/2.0/vulnerability_definitions'
|
24
|
+
resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, cve: cve)
|
25
|
+
json = JSON.parse(resp, symbolize_names: true)
|
26
|
+
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Search for any vulnerability definitions which refer to a given reference
|
30
|
+
# ID.
|
31
|
+
#
|
32
|
+
# Examples:
|
33
|
+
# find_vulns_by_ref('oval', 'OVAL10476')
|
34
|
+
# find_vulns_by_ref('bid', 35067)
|
35
|
+
# find_vulns_by_ref('secunia', 35188)
|
36
|
+
#
|
37
|
+
# @param [String] source External vulnerability reference source.
|
38
|
+
# @param [String] id Unique vulnerability reference ID.
|
39
|
+
# @return [Array[VulnerabilityDefinition]] A list of vuln definitions which
|
40
|
+
# check the vulnerability.
|
41
|
+
#
|
42
|
+
def find_vulns_by_ref(source, id)
|
43
|
+
uri = '/api/2.0/vulnerability_definitions'
|
44
|
+
resp = AJAX.get(self,
|
45
|
+
uri,
|
46
|
+
AJAX::CONTENT_TYPE::JSON,
|
47
|
+
source: source, id: id)
|
48
|
+
json = JSON.parse(resp, symbolize_names: true)
|
49
|
+
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Search for any vulnerability definitions which refer to a given title.
|
53
|
+
#
|
54
|
+
# Note: This method will return a maximum of 500 results. If the search
|
55
|
+
# yields a high number of results, consider add more specific words to
|
56
|
+
# the title.
|
57
|
+
#
|
58
|
+
# @param [String] title A (partial) title to search for.
|
59
|
+
# @param [Boolean] all_words Whether to include all words from the search
|
60
|
+
# phrase in the search.
|
61
|
+
# @return [Array[VulnerabilityDefinition]] A list of vuln definitions with titles matching
|
62
|
+
# the provided value.
|
63
|
+
#
|
64
|
+
def find_vulns_by_title(title, all_words = true)
|
65
|
+
uri = '/api/2.0/vulnerability_definitions'
|
66
|
+
params = { title: title, all_words: all_words }
|
67
|
+
resp = AJAX.get(self, uri, AJAX::CONTENT_TYPE::JSON, params)
|
68
|
+
json = JSON.parse(resp, symbolize_names: true)
|
69
|
+
json[:resources].map { |e| VulnerabilityDefinition.new.object_from_hash(self, e) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Vulnerability definition object. Represents a known vulnerability on a given
|
74
|
+
# Nexpose console.
|
75
|
+
#
|
76
|
+
class VulnerabilityDefinition < APIObject
|
77
|
+
# Unique identifier of a vulnerability definition.
|
78
|
+
attr_reader :id
|
79
|
+
# Vulnerability title.
|
80
|
+
attr_reader :title
|
81
|
+
# Vulnerability description, usually formated in HTML.
|
82
|
+
attr_reader :description
|
83
|
+
# The CVEs for the vulnerability.
|
84
|
+
attr_reader :cves
|
85
|
+
# Date the vulnerability was publicized by the third-party, vendor, or another
|
86
|
+
# authoring source.
|
87
|
+
attr_reader :date_published
|
88
|
+
# Date the vulnerability was first checked by Nexpose.
|
89
|
+
attr_reader :date_added
|
90
|
+
# Severity category. One of: Critical, Severe, Moderate.
|
91
|
+
attr_reader :severity
|
92
|
+
# Severity score, in the range of 0.0 to 10.0.
|
93
|
+
attr_reader :severity_score
|
94
|
+
# Risk score associated with vulnerability.
|
95
|
+
attr_reader :riskscore
|
96
|
+
|
97
|
+
# Whether the presence of the vulnerability can cause PCI failure.
|
98
|
+
# One of: Pass, Fail.
|
99
|
+
attr_reader :pci_status
|
100
|
+
# PCI severity score of the vulnerability, measured on a scale of 1 to 5.
|
101
|
+
attr_reader :pci_severity_score
|
102
|
+
|
103
|
+
# CVSS score of the vulnerability. Value between 0.0 and 10.0.
|
104
|
+
attr_reader :cvss_score
|
105
|
+
# Full CVSS vector in CVSS Version 2.0 notation.
|
106
|
+
attr_reader :cvss_vector
|
107
|
+
# Base score for the exploitability of a vulnerability that is used to compute
|
108
|
+
# the overall CVSS score.
|
109
|
+
attr_reader :cvss_exploit_score
|
110
|
+
# Base score for the impact of a vulnerability that is used to compute the
|
111
|
+
# overall CVSS score.
|
112
|
+
attr_reader :cvss_impact_score
|
113
|
+
|
114
|
+
# Whether the vulnerability is classified as a denial-of-service vuln.
|
115
|
+
attr_reader :denial_of_service
|
116
|
+
|
117
|
+
# Load a vulnerability definition from the provided console.
|
118
|
+
#
|
119
|
+
# @param [Connection] nsc Active connection to a Nexpose console.
|
120
|
+
# @param [String] id Unique identifier of a vulnerability definition.
|
121
|
+
# @return [VulnerabilityDefinition] The requested vulnerability definition, if found.
|
122
|
+
#
|
123
|
+
def self.load(nsc, id)
|
124
|
+
uri = "/api/2.0/vulnerability_definitions/#{id}"
|
125
|
+
resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON)
|
126
|
+
hash = JSON.parse(resp, symbolize_names: true)
|
127
|
+
new.object_from_hash(nsc, hash)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Known malware kits that can target a vulnerability.
|
132
|
+
#
|
133
|
+
class MalwareKit < APIObject
|
134
|
+
# Internal Nexpose identifier of the malware kit.
|
135
|
+
attr_reader :id
|
136
|
+
# Malware kit name.
|
137
|
+
attr_reader :name
|
138
|
+
# Malware kit description, if available.
|
139
|
+
attr_reader :description
|
140
|
+
# Popularity of the malware kit, which identifies how common or accessible
|
141
|
+
# it is. Values include: rare, uncommon, common, popular, occasional.
|
142
|
+
attr_reader :popularity
|
143
|
+
end
|
144
|
+
|
145
|
+
# Known exploits of a vulnerability.
|
146
|
+
#
|
147
|
+
class Exploit < APIObject
|
148
|
+
# Internal Nexpose identifier of the exploit.
|
149
|
+
attr_reader :id
|
150
|
+
# Exploit title.
|
151
|
+
attr_reader :title
|
152
|
+
# A description of the exploit, if available.
|
153
|
+
attr_reader :description
|
154
|
+
# Skill level required to use the exploit. One of: Expert, Intermediate,
|
155
|
+
# Novice.
|
156
|
+
attr_reader :skill_level
|
157
|
+
# Source which defined and published the exploit, such as Metasploit or
|
158
|
+
# Exploit Database.
|
159
|
+
attr_reader :source
|
160
|
+
# Reference key used by the publishing source to identify the exploit.
|
161
|
+
attr_reader :source_key
|
162
|
+
end
|
163
|
+
|
164
|
+
# External vulnerability reference.
|
165
|
+
#
|
166
|
+
class Reference < APIObject
|
167
|
+
# Internal Nexpose identifier of the reference.
|
168
|
+
attr_reader :id
|
169
|
+
# Reference value, such as the full CVE identifier.
|
170
|
+
attr_reader :reference
|
171
|
+
# Reference source, such as CVE, MS, RedHat, etc.
|
172
|
+
attr_reader :source
|
173
|
+
end
|
174
|
+
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.9.
|
4
|
+
version: 0.9.4
|
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: 2015-01-
|
14
|
+
date: 2015-01-28 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rex
|
@@ -59,6 +59,7 @@ extensions: []
|
|
59
59
|
extra_rdoc_files:
|
60
60
|
- README.markdown
|
61
61
|
files:
|
62
|
+
- CONTRIBUTING.md
|
62
63
|
- COPYING
|
63
64
|
- Gemfile
|
64
65
|
- README.markdown
|
@@ -69,6 +70,7 @@ files:
|
|
69
70
|
- lib/nexpose/alert.rb
|
70
71
|
- lib/nexpose/api.rb
|
71
72
|
- lib/nexpose/api_request.rb
|
73
|
+
- lib/nexpose/asset.rb
|
72
74
|
- lib/nexpose/common.rb
|
73
75
|
- lib/nexpose/connection.rb
|
74
76
|
- lib/nexpose/console.rb
|
@@ -80,6 +82,7 @@ files:
|
|
80
82
|
- lib/nexpose/discovery/filter.rb
|
81
83
|
- lib/nexpose/engine.rb
|
82
84
|
- lib/nexpose/error.rb
|
85
|
+
- lib/nexpose/external.rb
|
83
86
|
- lib/nexpose/filter.rb
|
84
87
|
- lib/nexpose/global_settings.rb
|
85
88
|
- lib/nexpose/group.rb
|
@@ -104,6 +107,7 @@ files:
|
|
104
107
|
- lib/nexpose/util.rb
|
105
108
|
- lib/nexpose/version.rb
|
106
109
|
- lib/nexpose/vuln.rb
|
110
|
+
- lib/nexpose/vuln_def.rb
|
107
111
|
- lib/nexpose/vuln_exception.rb
|
108
112
|
- nexpose.gemspec
|
109
113
|
homepage: https://github.com/rapid7/nexpose-client
|