nexpose_ticketing 0.3.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/nexpose_servicedesk +17 -0
- data/lib/nexpose_ticketing/config/servicedesk.config +19 -0
- data/lib/nexpose_ticketing/config/servicenow.config +1 -1
- data/lib/nexpose_ticketing/config/ticket_service.config +15 -5
- data/lib/nexpose_ticketing/helpers/jira_helper.rb +5 -5
- data/lib/nexpose_ticketing/helpers/remedy_helper.rb +401 -78
- data/lib/nexpose_ticketing/helpers/servicedesk_helper.rb +337 -0
- data/lib/nexpose_ticketing/helpers/servicenow_helper.rb +68 -52
- data/lib/nexpose_ticketing/queries.rb +251 -23
- data/lib/nexpose_ticketing/ticket_repository.rb +151 -8
- data/lib/nexpose_ticketing/ticket_service.rb +80 -37
- metadata +20 -2
@@ -79,6 +79,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
79
79
|
log_message("Loading helper: #{file}")
|
80
80
|
require_relative file
|
81
81
|
end
|
82
|
+
log_message("Ticket mode: #{@options[:ticket_mode]}.")
|
83
|
+
|
82
84
|
log_message("Enabling helper: #{@helper_data[:helper_name]}.")
|
83
85
|
@helper = eval(@helper_data[:helper_name]).new(@helper_data, @options)
|
84
86
|
|
@@ -117,15 +119,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
117
119
|
|
118
120
|
# Generates a full site(s) report ticket(s).
|
119
121
|
def all_site_report(ticket_repository, options, helper)
|
120
|
-
|
121
|
-
sites_to_query =
|
122
|
-
if options[:sites].empty?
|
123
|
-
log_message('No site(s) specified, generating full vulnerability report.')
|
124
|
-
@ticket_repository.all_site_details.each { |site| sites_to_query << site.id }
|
125
|
-
else
|
126
|
-
log_message('Generating full vulnerability report on user entered sites.')
|
127
|
-
sites_to_query = Array(options[:sites])
|
128
|
-
end
|
122
|
+
log_message('Generating full vulnerability report on user entered sites.')
|
123
|
+
sites_to_query = Array(options[:sites])
|
129
124
|
|
130
125
|
log_message("Generating full vulnerability report on the following sites: #{sites_to_query.join(', ')}")
|
131
126
|
|
@@ -133,7 +128,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
133
128
|
log_message("Running full vulnerability report on site #{site}")
|
134
129
|
all_vulns_file = ticket_repository.all_vulns(options, site)
|
135
130
|
log_message('Preparing tickets.')
|
136
|
-
ticket_rate_limiter(options, all_vulns_file, Proc.new { |ticket_batch| helper.prepare_create_tickets(ticket_batch) }, Proc.new { |tickets| helper.create_tickets(tickets) })
|
131
|
+
ticket_rate_limiter(options, all_vulns_file, Proc.new { |ticket_batch| helper.prepare_create_tickets(ticket_batch, site) }, Proc.new { |tickets| helper.create_tickets(tickets) })
|
137
132
|
}
|
138
133
|
log_message('Finished process all vulnerabilities.')
|
139
134
|
end
|
@@ -162,66 +157,107 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
162
157
|
# There's a new site we haven't seen before.
|
163
158
|
def full_new_site_report(site_id, ticket_repository, options, helper)
|
164
159
|
log_message("New site id: #{site_id} detected. Generating report.")
|
165
|
-
new_site_vuln_file = ticket_repository.all_vulns(
|
160
|
+
new_site_vuln_file = ticket_repository.all_vulns(options, site_id)
|
166
161
|
log_message('Report generated, preparing tickets.')
|
167
|
-
ticket_rate_limiter(options, new_site_vuln_file, Proc.new {|ticket_batch| helper.prepare_create_tickets(ticket_batch)}, Proc.new {|tickets| helper.create_tickets(tickets)})
|
162
|
+
ticket_rate_limiter(options, new_site_vuln_file, Proc.new {|ticket_batch| helper.prepare_create_tickets(ticket_batch, site_id)}, Proc.new {|tickets| helper.create_tickets(tickets)})
|
168
163
|
end
|
169
164
|
|
170
165
|
# There's a new scan with possibly new vulnerabilities.
|
171
166
|
def delta_site_new_scan(ticket_repository, site_id, options, helper, file_site_histories)
|
172
167
|
log_message("New scan detected for site: #{site_id}. Generating report.")
|
173
168
|
|
174
|
-
if options[:ticket_mode] == 'I'
|
175
|
-
# I-mode tickets require updating the tickets in the target system.
|
169
|
+
if options[:ticket_mode] == 'I' || options[:ticket_mode] == 'V'
|
170
|
+
# I-mode and V-mode tickets require updating the tickets in the target system.
|
176
171
|
log_message("Scan id for new scan: #{file_site_histories[site_id]}.")
|
177
172
|
all_scan_vuln_file = ticket_repository.all_vulns_sites(scan_id: file_site_histories[site_id],
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
173
|
+
site_id: site_id,
|
174
|
+
severity: options[:severity],
|
175
|
+
ticket_mode: options[:ticket_mode],
|
176
|
+
riskScore: options[:riskScore],
|
177
|
+
vulnerabilityCategories: options[:vulnerabilityCategories],
|
178
|
+
tags: options[:tags])
|
179
|
+
|
180
|
+
if helper.respond_to?('prepare_update_tickets') && helper.respond_to?('update_tickets')
|
181
|
+
ticket_rate_limiter(options, all_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_update_tickets(ticket_batch, site_id)}, Proc.new {|tickets| helper.update_tickets(tickets)})
|
182
182
|
else
|
183
|
-
log_message(
|
184
|
-
fail "Helper using 'I' mode must implement prepare_updates and update_tickets"
|
183
|
+
log_message('Helper does not implement update methods')
|
184
|
+
fail "Helper using 'I' or 'V' mode must implement prepare_updates and update_tickets"
|
185
|
+
end
|
186
|
+
|
187
|
+
if options[:close_old_tickets_on_update] == 'Y'
|
188
|
+
tickets_to_close_file = ticket_repository.tickets_to_close(scan_id: file_site_histories[site_id],
|
189
|
+
site_id: site_id,
|
190
|
+
severity: options[:severity],
|
191
|
+
ticket_mode: options[:ticket_mode],
|
192
|
+
riskScore: options[:riskScore],
|
193
|
+
vulnerabilityCategories: options[:vulnerabilityCategories],
|
194
|
+
tags: options[:tags])
|
195
|
+
|
196
|
+
if helper.respond_to?('prepare_close_tickets') && helper.respond_to?('close_tickets')
|
197
|
+
ticket_rate_limiter(options, tickets_to_close_file, Proc.new {|ticket_batch| helper.prepare_close_tickets(ticket_batch, site_id)}, Proc.new {|tickets| helper.close_tickets(tickets)})
|
198
|
+
else
|
199
|
+
log_message('Helper does not implement close methods')
|
200
|
+
fail 'Helper using \'I\' or \'V\' mode must implement prepare_close_tickets and close_tickets'
|
201
|
+
end
|
185
202
|
end
|
186
203
|
else
|
187
204
|
# D-mode tickets require creating new tickets and closing old tickets.
|
188
|
-
new_scan_vuln_file = ticket_repository.new_vulns_sites(scan_id: file_site_histories[site_id],
|
189
|
-
|
205
|
+
new_scan_vuln_file = ticket_repository.new_vulns_sites(scan_id: file_site_histories[site_id],
|
206
|
+
site_id: site_id,
|
207
|
+
severity: options[:severity],
|
208
|
+
ticket_mode: options[:ticket_mode],
|
209
|
+
riskScore: options[:riskScore],
|
210
|
+
vulnerabilityCategories: options[:vulnerabilityCategories],
|
211
|
+
tags: options[:tags])
|
212
|
+
|
190
213
|
preparse = CSV.new(new_scan_vuln_file.path, headers: :first_row)
|
191
214
|
empty_report = preparse.shift.nil?
|
192
215
|
log_message("No new vulnerabilities found in new scan for site: #{site_id}.") if empty_report
|
193
216
|
log_message("New vulnerabilities found in new scan for site #{site_id}, preparing tickets.") unless empty_report
|
194
217
|
unless empty_report
|
195
|
-
ticket_rate_limiter(options, new_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_create_tickets(ticket_batch)}, Proc.new {|tickets| helper.create_tickets(tickets)})
|
218
|
+
ticket_rate_limiter(options, new_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_create_tickets(ticket_batch, site_id)}, Proc.new {|tickets| helper.create_tickets(tickets)})
|
196
219
|
end
|
197
220
|
|
198
|
-
if helper.respond_to?(
|
199
|
-
old_scan_vuln_file = ticket_repository.old_vulns_sites(scan_id: file_site_histories[site_id],
|
200
|
-
|
221
|
+
if helper.respond_to?('prepare_close_tickets') && helper.respond_to?('close_tickets')
|
222
|
+
old_scan_vuln_file = ticket_repository.old_vulns_sites(scan_id: file_site_histories[site_id],
|
223
|
+
site_id: site_id,
|
224
|
+
severity: options[:severity],
|
225
|
+
riskScore: options[:riskScore],
|
226
|
+
vulnerabilityCategories: options[:vulnerabilityCategories],
|
227
|
+
tags: options[:tags])
|
228
|
+
|
201
229
|
preparse = CSV.new(old_scan_vuln_file.path, headers: :first_row, :skip_blanks => true)
|
202
230
|
empty_report = preparse.shift.nil?
|
203
231
|
log_message("No old (closed) vulnerabilities found in new scan for site: #{site_id}.") if empty_report
|
204
232
|
log_message("Old vulnerabilities found in new scan for site #{site_id}, preparing closures.") unless empty_report
|
205
233
|
unless empty_report
|
206
|
-
ticket_rate_limiter(options, old_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_close_tickets(ticket_batch)}, Proc.new {|tickets| helper.close_tickets(tickets)})
|
234
|
+
ticket_rate_limiter(options, old_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_close_tickets(ticket_batch, site_id)}, Proc.new {|tickets| helper.close_tickets(tickets)})
|
207
235
|
end
|
208
236
|
else
|
209
|
-
# Create a log message but do not halt execution of the helper if ticket
|
237
|
+
# Create a log message but do not halt execution of the helper if ticket closing is not
|
210
238
|
# supported to allow legacy code to execute normally.
|
211
|
-
log_message('Helper does not
|
239
|
+
log_message('Helper does not implement close methods.')
|
212
240
|
end
|
213
241
|
end
|
214
242
|
end
|
215
243
|
|
244
|
+
|
216
245
|
def ticket_rate_limiter(options, query_results_file, ticket_prepare_method, ticket_send_method)
|
217
246
|
batch_size_max = (options[:batch_size] + 1)
|
218
247
|
log_message("Batching tickets in sizes: #{options[:batch_size]}")
|
219
248
|
|
249
|
+
#Vulnerability mode is batched by vulnerability_id. The rest are batched by ip_address.
|
250
|
+
if @options[:ticket_mode] == 'V'
|
251
|
+
batching_field = 'vulnerability_id'
|
252
|
+
else
|
253
|
+
batching_field = 'ip_address'
|
254
|
+
end
|
255
|
+
|
220
256
|
# Start the batching
|
221
257
|
query_results_file.rewind
|
222
258
|
csv_header = query_results_file.readline
|
223
259
|
ticket_batch = []
|
224
|
-
|
260
|
+
current_batching_value = -1
|
225
261
|
current_csv_row = nil
|
226
262
|
|
227
263
|
begin
|
@@ -229,15 +265,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
229
265
|
ticket_batch << line
|
230
266
|
|
231
267
|
CSV.parse(line.chomp, headers: csv_header) do |row|
|
232
|
-
if
|
233
|
-
|
268
|
+
if current_batching_value == -1
|
269
|
+
current_batching_value = row[batching_field.to_s] unless row[batching_field.to_s] == 'current_batching_value'
|
234
270
|
end
|
235
|
-
current_csv_row = row unless row[
|
271
|
+
current_csv_row = row unless row[batching_field.to_s] == 'current_batching_value'
|
236
272
|
end
|
237
273
|
|
238
274
|
if ticket_batch.size >= batch_size_max
|
239
275
|
#Batch target reached. Make sure we end with a complete IP address set (all tickets for a single IP in this batch)
|
240
|
-
if(
|
276
|
+
if(current_batching_value != current_csv_row[batching_field.to_s])
|
241
277
|
log_message('Batch size reached. Sending tickets.')
|
242
278
|
|
243
279
|
#Move the mismatching line to the next batch
|
@@ -247,7 +283,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
247
283
|
ticket_batch.clear
|
248
284
|
ticket_batch << csv_header
|
249
285
|
ticket_batch << line_holder
|
250
|
-
|
286
|
+
current_batching_value = -1
|
251
287
|
end
|
252
288
|
end
|
253
289
|
end
|
@@ -283,9 +319,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
283
319
|
file_site_histories = prepare_historical_data(@ticket_repository, @options)
|
284
320
|
historical_scan_file = File.join(File.dirname(__FILE__), "#{@options[:file_name]}")
|
285
321
|
# If we didn't specify a site || first time run (no scan history), then it gets all the vulnerabilities.
|
286
|
-
if @options[:sites].empty? || file_site_histories.nil?
|
322
|
+
if @options[:sites].nil? || @options[:sites].empty? || file_site_histories.nil?
|
287
323
|
log_message('Storing current scan state before obtaining all vulnerabilities.')
|
288
|
-
|
324
|
+
|
325
|
+
if options[:sites].nil? || options[:sites].empty?
|
326
|
+
log_message('No site(s) specified, generating for all sites.')
|
327
|
+
@ticket_repository.all_site_details.each { |site| (@options[:sites] ||= []) << site.id.to_s }
|
328
|
+
log_message("List of sites is now <#{@options[:sites]}>")
|
329
|
+
end
|
330
|
+
|
331
|
+
current_scan_state = ticket_repository.load_last_scans(@options)
|
289
332
|
|
290
333
|
all_site_report(@ticket_repository, @options, @helper)
|
291
334
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexpose_ticketing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damian Finol
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nexpose
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
41
55
|
description: This gem provides a Ruby implementation of different integrations with
|
42
56
|
ticketing services for Nexpose.
|
43
57
|
email:
|
@@ -46,6 +60,7 @@ executables:
|
|
46
60
|
- nexpose_jira
|
47
61
|
- nexpose_servicenow
|
48
62
|
- nexpose_remedy
|
63
|
+
- nexpose_servicedesk
|
49
64
|
extensions: []
|
50
65
|
extra_rdoc_files:
|
51
66
|
- README.md
|
@@ -53,17 +68,20 @@ files:
|
|
53
68
|
- README.md
|
54
69
|
- bin/nexpose_jira
|
55
70
|
- bin/nexpose_remedy
|
71
|
+
- bin/nexpose_servicedesk
|
56
72
|
- bin/nexpose_servicenow
|
57
73
|
- lib/nexpose_ticketing.rb
|
58
74
|
- lib/nexpose_ticketing/config/jira.config
|
59
75
|
- lib/nexpose_ticketing/config/remedy.config
|
60
76
|
- lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_Create_WS.xml
|
61
77
|
- lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_WS.xml
|
78
|
+
- lib/nexpose_ticketing/config/servicedesk.config
|
62
79
|
- lib/nexpose_ticketing/config/servicenow.config
|
63
80
|
- lib/nexpose_ticketing/config/servicenow_updateset/Rapid7 Nexpose Ticketing.glide-calgary-02-15-2013__patch2-hotfix5.xml
|
64
81
|
- lib/nexpose_ticketing/config/ticket_service.config
|
65
82
|
- lib/nexpose_ticketing/helpers/jira_helper.rb
|
66
83
|
- lib/nexpose_ticketing/helpers/remedy_helper.rb
|
84
|
+
- lib/nexpose_ticketing/helpers/servicedesk_helper.rb
|
67
85
|
- lib/nexpose_ticketing/helpers/servicenow_helper.rb
|
68
86
|
- lib/nexpose_ticketing/nx_logger.rb
|
69
87
|
- lib/nexpose_ticketing/queries.rb
|