moj-nessus-automation 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf73193651160ed38be74d9296150fc56d39ba07
4
+ data.tar.gz: d28ec9c8d573df1c2f7e89d528e5b4cb145fd63c
5
+ SHA512:
6
+ metadata.gz: be194d067c703bcba38afa28bce1ec3959bf1ac75114c722bcdee9f64f4ad845105cae223f959a883933a1783f789f81a2e523a51c99447f699e7726a624884c
7
+ data.tar.gz: 023fb8f527c1ad80de4d7b2fda71ff8d3af206495b24c5bac2533454b869ed7c9963a76d9076713127fa9a7ce3de36dcefc8616e3698b46b70a8402708b194c8
@@ -0,0 +1,2 @@
1
+ env.sh
2
+ *.gem
@@ -0,0 +1,2 @@
1
+ ## Nessus Automation - Ruby Client
2
+
@@ -0,0 +1,31 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require_relative 'nessus.rb'
4
+
5
+ # Create a new scan instance
6
+ scan = Nessus::Scan.new(
7
+ 'webapp',
8
+ 'https://preprod-prisonvisits.dsd.io/prisoner'
9
+ )
10
+
11
+ # Check details of scan created
12
+ scan.details
13
+
14
+ # Launch the scan
15
+ scan.launch!
16
+
17
+ # View scan result
18
+ scan.view
19
+
20
+ # Convenience methods for vulnerability management
21
+ scan.result.critical?
22
+ scan.result.high?
23
+ scan.result.medium?
24
+
25
+ # Export the scan as csv
26
+ scan.export_csv('/tmp/nessus.csv')
27
+
28
+
29
+
30
+
31
+
@@ -0,0 +1,9 @@
1
+ require_relative 'nessus/xmlrpc.rb'
2
+ require_relative 'nessus/settings.rb'
3
+ require_relative 'nessus/scan.rb'
4
+ #
5
+ # Namespace for classes and modules that handle interacting
6
+ # with Nessus XMLRPC interface
7
+ #
8
+ module Nessus
9
+ end
@@ -0,0 +1,125 @@
1
+ require_relative './xmlrpc.rb'
2
+ require_relative './settings.rb'
3
+
4
+ module Nessus
5
+ class Scan
6
+ #
7
+ # Wrapper for XMLRPC client
8
+ #
9
+ # @attr_reader [String] uuid of scan template
10
+ # @attr_reader [Fixnum] scan id
11
+ # @attr_reader [Hash] full scan details
12
+ # @attr_reader [Result] full scan result
13
+ #
14
+ attr_reader :uuid, :id, :details, :result
15
+ #
16
+ # Create a new scan instance
17
+ #
18
+ # @param [String] nessus scan template name
19
+ # @param [Array<String>] target addresses e.g http://localhost:3000
20
+ #
21
+ # @return [Scan]
22
+ #
23
+ def initialize(name, targets)
24
+ set_uuid(name)
25
+ setup_scan(targets)
26
+ end
27
+ #
28
+ # Launches the scan
29
+ #
30
+ # @return [Result] the result hash from the scan
31
+ #
32
+ def launch!
33
+ client.scan_launch(@id)
34
+
35
+ loop do
36
+ raw = client.scan_details(@id)
37
+ status = raw['info']['status']
38
+
39
+ if status != 'running'
40
+ @result = Result.new(raw)
41
+ break
42
+ end
43
+
44
+ sleep Nessus::Settings.refresh_interval
45
+ end
46
+ end
47
+ #
48
+ # View the result of a finished scan
49
+ #
50
+ # @return [Hash] the raw result hash from the scan
51
+ #
52
+ def view
53
+ result && result.raw
54
+ end
55
+ #
56
+ # Export scan to csv file
57
+ #
58
+ # @param [String] output filepath
59
+ #
60
+ # @return [Fixnum] bytes written to file
61
+ #
62
+ def export_csv(filepath)
63
+ csv_id = client.scan_export(@id, 'csv')
64
+ csv_data = client.report_download(@id, csv_id['file'])
65
+
66
+ File.write(filepath, csv_data)
67
+ end
68
+
69
+ private
70
+
71
+ def set_uuid(name)
72
+ @uuid = client
73
+ .list_template('scan')
74
+ .fetch('templates', [])
75
+ .find { |t| t['name'] == name }
76
+ .fetch('uuid')
77
+ end
78
+
79
+ def setup_scan(targets)
80
+ @details = client.scan_create(
81
+ @uuid,
82
+ "Automated Scan #{Time.now}",
83
+ "This scan was created by the Nessus ruby client as part of automated testing",
84
+ targets
85
+ )
86
+
87
+ @id = @details['scan']['id']
88
+ end
89
+
90
+ def client
91
+ @client ||= Nessus::Client.new(
92
+ Nessus::Settings.host,
93
+ Nessus::Settings.username,
94
+ Nessus::Settings.password,
95
+ Nessus::Settings.ssl_verify
96
+ )
97
+ end
98
+
99
+ class Result
100
+ attr_reader :raw
101
+
102
+ def initialize(raw)
103
+ @raw = raw
104
+ end
105
+
106
+ def critical?
107
+ check('critical')
108
+ end
109
+
110
+ def high?
111
+ check('high')
112
+ end
113
+
114
+ def medium?
115
+ check('medium')
116
+ end
117
+
118
+ private
119
+
120
+ def check(severity)
121
+ raw['hosts'].any? { |h| h.fetch(severity) > 0 }
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # Define static scan settings
3
+ #
4
+ module Nessus
5
+ module Settings
6
+ extend self
7
+ #
8
+ # Host for Nessus instance
9
+ #
10
+ # @return [String]
11
+ #
12
+ def host
13
+ ENV.fetch('NESSUS_HOST', 'http://localhost:8834')
14
+ end
15
+ #
16
+ # Nessus username
17
+ #
18
+ # @return [String]
19
+ #
20
+ def username
21
+ ENV.fetch('NESSUS_USER', 'test_user')
22
+ end
23
+ #
24
+ # Nessus password
25
+ #
26
+ # @return [String]
27
+ #
28
+ def password
29
+ ENV.fetch('NESSUS_PASS', 'test_pass')
30
+ end
31
+ #
32
+ # SSL connection settings for Nessus instance
33
+ #
34
+ # @note set to 'ssl_verify' in PRODUCTION
35
+ #
36
+ # @return [String]
37
+ #
38
+ def ssl_verify
39
+ 'none' # ssl_verify for secure connection
40
+ end
41
+ #
42
+ # Refresh interval when checking for job completion
43
+ #
44
+ # @return [Fixnum]
45
+ #
46
+ def refresh_interval
47
+ 5
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,6 @@
1
+ #
2
+ # Gem versioning
3
+ #
4
+ module Nessus
5
+ VERSION = '0.0.1'
6
+ end
@@ -0,0 +1,315 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'openssl'
4
+ #
5
+ # Nessus XML RPC Client
6
+ #
7
+ # @author Metasploit Framework
8
+ # @see https://github.com/rapid7/metasploit-framework/blob/master/lib/nessus/nessus-xmlrpc.rb
9
+ #
10
+ module Nessus
11
+ class Client
12
+ class << self
13
+ @connection
14
+ @token
15
+ end
16
+
17
+ def initialize(host, username = nil, password = nil, ssl_option = nil)
18
+ uri = URI.parse(host)
19
+ @connection = Net::HTTP.new(uri.host, uri.port)
20
+ @connection.use_ssl = true
21
+ if ssl_option == "ssl_verify"
22
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
23
+ else
24
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
25
+ end
26
+
27
+ yield @connection if block_given?
28
+ authenticate(username, password) if username && password
29
+ end
30
+
31
+ def authenticate(username, password)
32
+ payload = {
33
+ :username => username,
34
+ :password => password,
35
+ :json => 1
36
+ }
37
+ res = http_post(:uri=>"/session", :data=>payload)
38
+ if res['token']
39
+ @token = "token=#{res['token']}"
40
+ return true
41
+ else
42
+ false
43
+ end
44
+ end
45
+
46
+ def x_cookie
47
+ {'X-Cookie'=>@token}
48
+ end
49
+
50
+ alias_method :login, :authenticate
51
+
52
+ def authenticated
53
+ if (@token && @token.include?('token='))
54
+ return true
55
+ else
56
+ return false
57
+ end
58
+ end
59
+
60
+ def get_server_properties
61
+ http_get(:uri=>"/server/properties", :fields=>x_cookie)
62
+ end
63
+
64
+ def user_add(username, password, permissions, type)
65
+ payload = {
66
+ :username => username,
67
+ :password => password,
68
+ :permissions => permissions,
69
+ :type => type,
70
+ :json => 1
71
+ }
72
+ http_post(:uri=>"/users", :fields=>x_cookie, :data=>payload)
73
+ end
74
+
75
+ def user_delete(user_id)
76
+ res = http_delete(:uri=>"/users/#{user_id}", :fields=>x_cookie)
77
+ return res.code
78
+ end
79
+
80
+ def user_chpasswd(user_id, password)
81
+ payload = {
82
+ :password => password,
83
+ :json => 1
84
+ }
85
+ res = http_put(:uri=>"/users/#{user_id}/chpasswd", :data=>payload, :fields=>x_cookie)
86
+ return res.code
87
+ end
88
+
89
+ def user_logout
90
+ res = http_delete(:uri=>"/session", :fields=>x_cookie)
91
+ return res.code
92
+ end
93
+
94
+ def list_policies
95
+ http_get(:uri=>"/policies", :fields=>x_cookie)
96
+ end
97
+
98
+ def list_users
99
+ http_get(:uri=>"/users", :fields=>x_cookie)
100
+ end
101
+
102
+ def list_folders
103
+ http_get(:uri=>"/folders", :fields=>x_cookie)
104
+ end
105
+
106
+ def list_scanners
107
+ http_get(:uri=>"/scanners", :fields=>x_cookie)
108
+ end
109
+
110
+ def list_families
111
+ http_get(:uri=>"/plugins/families", :fields=>x_cookie)
112
+ end
113
+
114
+ def list_plugins(family_id)
115
+ http_get(:uri=>"/plugins/families/#{family_id}", :fields=>x_cookie)
116
+ end
117
+
118
+ def list_template(type)
119
+ res = http_get(:uri=>"/editor/#{type}/templates", :fields=>x_cookie)
120
+ end
121
+
122
+ def plugin_details(plugin_id)
123
+ http_get(:uri=>"/plugins/plugin/#{plugin_id}", :fields=>x_cookie)
124
+ end
125
+
126
+ def is_admin
127
+ res = http_get(:uri=>"/session", :fields=>x_cookie)
128
+ if res['permissions'] == 128
129
+ return true
130
+ else
131
+ return false
132
+ end
133
+ end
134
+
135
+ def server_properties
136
+ http_get(:uri=>"/server/properties", :fields=>x_cookie)
137
+ end
138
+
139
+ def scan_create(uuid, name, description, targets)
140
+ payload = {
141
+ :uuid => uuid,
142
+ :settings => {
143
+ :name => name,
144
+ :description => description,
145
+ :text_targets => targets
146
+ },
147
+ :json => 1
148
+ }.to_json
149
+ http_post(:uri=>"/scans", :body=>payload, :fields=>x_cookie, :ctype=>'application/json')
150
+ end
151
+
152
+ def scan_launch(scan_id)
153
+ http_post(:uri=>"/scans/#{scan_id}/launch", :fields=>x_cookie)
154
+ end
155
+
156
+ def server_status
157
+ http_get(:uri=>"/server/status", :fields=>x_cookie)
158
+ end
159
+
160
+ def scan_list
161
+ http_get(:uri=>"/scans", :fields=>x_cookie)
162
+ end
163
+
164
+ def scan_details(scan_id)
165
+ http_get(:uri=>"/scans/#{scan_id}", :fields=>x_cookie)
166
+ end
167
+
168
+ def scan_pause(scan_id)
169
+ http_post(:uri=>"/scans/#{scan_id}/pause", :fields=>x_cookie)
170
+ end
171
+
172
+ def scan_resume(scan_id)
173
+ http_post(:uri=>"/scans/#{scan_id}/resume", :fields=>x_cookie)
174
+ end
175
+
176
+ def scan_stop(scan_id)
177
+ http_post(:uri=>"/scans/#{scan_id}/stop", :fields=>x_cookie)
178
+ end
179
+
180
+ def scan_export(scan_id, format)
181
+ payload = {
182
+ :format => format
183
+ }.to_json
184
+ http_post(:uri=>"/scans/#{scan_id}/export", :body=>payload, :ctype=>'application/json', :fields=>x_cookie)
185
+ end
186
+
187
+ def scan_export_status(scan_id, file_id)
188
+ request = Net::HTTP::Get.new("/scans/#{scan_id}/export/#{file_id}/status")
189
+ request.add_field("X-Cookie", @token)
190
+ res = @connection.request(request)
191
+ if res.code == "200"
192
+ return "ready"
193
+ else
194
+ res = JSON.parse(res.body)
195
+ return res
196
+ end
197
+ end
198
+
199
+ def policy_delete(policy_id)
200
+ res = http_delete(:uri=>"/policies/#{policy_id}", :fields=>x_cookie)
201
+ return res.code
202
+ end
203
+
204
+ def host_detail(scan_id, host_id)
205
+ res = http_get(:uri=>"/scans/#{scan_id}/hosts/#{host_id}", :fields=>x_cookie)
206
+ end
207
+
208
+ def report_download(scan_id, file_id)
209
+ res = http_get(:uri=>"/scans/#{scan_id}/export/#{file_id}/download", :raw_content=> true, :fields=>x_cookie)
210
+ end
211
+
212
+ private
213
+
214
+ def http_put(opts={})
215
+ uri = opts[:uri]
216
+ data = opts[:data]
217
+ fields = opts[:fields] || {}
218
+ res = nil
219
+
220
+ req = Net::HTTP::Put.new(uri)
221
+ req.set_form_data(data) unless data.blank?
222
+ fields.each_pair do |name, value|
223
+ req.add_field(name, value)
224
+ end
225
+
226
+ begin
227
+ res = @connection.request(req)
228
+ rescue URI::InvalidURIError
229
+ return res
230
+ end
231
+
232
+ res
233
+ end
234
+
235
+ def http_delete(opts={})
236
+ uri = opts[:uri]
237
+ fields = opts[:fields] || {}
238
+ res = nil
239
+
240
+ req = Net::HTTP::Delete.new(uri)
241
+
242
+ fields.each_pair do |name, value|
243
+ req.add_field(name, value)
244
+ end
245
+
246
+ begin
247
+ res = @connection.request(req)
248
+ rescue URI::InvalidURIError
249
+ return res
250
+ end
251
+
252
+ res
253
+ end
254
+
255
+ def http_get(opts={})
256
+ uri = opts[:uri]
257
+ fields = opts[:fields] || {}
258
+ raw_content = opts[:raw_content] || false
259
+ json = {}
260
+
261
+ req = Net::HTTP::Get.new(uri)
262
+ fields.each_pair do |name, value|
263
+ req.add_field(name, value)
264
+ end
265
+
266
+ begin
267
+ res = @connection.request(req)
268
+ rescue URI::InvalidURIError
269
+ return json
270
+ end
271
+ if !raw_content
272
+ parse_json(res.body)
273
+ else
274
+ res.body
275
+ end
276
+ end
277
+
278
+ def http_post(opts = {})
279
+ uri = opts[:uri]
280
+ data = opts[:data]
281
+ fields = opts[:fields] || {}
282
+ body = opts[:body]
283
+ ctype = opts[:ctype]
284
+ json = {}
285
+
286
+ req = Net::HTTP::Post.new(uri)
287
+ req.set_form_data(data) if data
288
+ req.body = body if body
289
+ req['Content-Type'] = ctype if ctype
290
+ fields.each_pair do |name, value|
291
+ req.add_field(name, value)
292
+ end
293
+
294
+ begin
295
+ res = @connection.request(req)
296
+ rescue URI::InvalidURIError
297
+ return json
298
+ end
299
+
300
+ parse_json(res.body)
301
+ end
302
+
303
+ def parse_json(body)
304
+ buf = {}
305
+
306
+ begin
307
+ buf = JSON.parse(body)
308
+ rescue JSON::ParserError
309
+ end
310
+
311
+ buf
312
+ end
313
+
314
+ end
315
+ end
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('./lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require './lib/nessus/version.rb'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'moj-nessus-automation'
10
+ s.version = Nessus::VERSION
11
+ s.date = '2014-09-24'
12
+ s.summary = 'Nessus Automation Gem'
13
+ s.description = 'A gem to automate nessus vulnerability scanning'
14
+ s.authors = ['Jeremy Fox']
15
+ s.email = 'jeremy.fox@digital.justice.gov.uk'
16
+ s.files = `git ls-files`.split($/)
17
+ s.require_paths = ['lib']
18
+ s.homepage =
19
+ 'http://rubygems.org/gems/moj-nesssus-automation'
20
+ s.license = 'MIT'
21
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moj-nessus-automation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Fox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A gem to automate nessus vulnerability scanning
14
+ email: jeremy.fox@digital.justice.gov.uk
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - README.md
21
+ - lib/example.rb
22
+ - lib/nessus.rb
23
+ - lib/nessus/scan.rb
24
+ - lib/nessus/settings.rb
25
+ - lib/nessus/version.rb
26
+ - lib/nessus/xmlrpc.rb
27
+ - moj-nessus-automation.gemspec
28
+ homepage: http://rubygems.org/gems/moj-nesssus-automation
29
+ licenses:
30
+ - MIT
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.4.5
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Nessus Automation Gem
52
+ test_files: []