nexpose_ticketing 0.8.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -64,8 +64,13 @@ module NexposeTicketing
64
64
  # |url| |summary| |fix|
65
65
  #
66
66
  def self.all_new_vulns(options = {})
67
- "SELECT DISTINCT on (da.ip_address, davs.solution_id) subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id,
68
- ds.url,proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore, dv.cvss_score, dvr.source, dvr.reference,
67
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
68
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
69
+ '|Nexpose ID: ' || ds.nexpose_id ||
70
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
71
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
72
+ fa.riskscore, dv.cvss_score,
73
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
69
74
  fasva.first_discovered, fasva.most_recently_discovered
70
75
  FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
71
76
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -77,15 +82,17 @@ module NexposeTicketing
77
82
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, fasv.scan_id
78
83
  HAVING NOT baselineComparison(fasv.scan_id, current_scan) = 'Old'
79
84
  ) subs
80
- JOIN dim_vulnerability dv USING (vulnerability_id)
81
- JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
82
- JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
83
- JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
84
- JOIN dim_solution ds USING (solution_id)
85
- JOIN dim_asset da ON subs.asset_id = da.asset_id
86
- JOIN fact_asset fa ON fa.asset_id = da.asset_id
87
- #{createRiskString( options[:riskScore])}
88
- ORDER BY da.ip_address, davs.solution_id"
85
+ JOIN dim_vulnerability dv USING (vulnerability_id)
86
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
87
+ JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
88
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
89
+ JOIN dim_solution ds USING (solution_id)
90
+ JOIN dim_asset da ON subs.asset_id = da.asset_id
91
+ JOIN fact_asset fa ON fa.asset_id = da.asset_id
92
+ #{createRiskString( options[:riskScore])}
93
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
94
+ fa.riskscore, dv.cvss_score, fasva.first_discovered, fasva.most_recently_discovered
95
+ ORDER BY da.ip_address, subs.vulnerability_id"
89
96
  end
90
97
 
91
98
  # Gets all delta vulns for all sites sorted by vuln ID.
@@ -95,25 +102,38 @@ module NexposeTicketing
95
102
  # |url| |summary| |fix|
96
103
  #
97
104
  def self.all_new_vulns_by_vuln_id(options = {})
98
- "SELECT DISTINCT on (subs.vulnerability_id, subs.asset_id, davs.solution_id) subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dv.title, davs.solution_id, ds.nexpose_id,
99
- ds.url,proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore
100
- FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
101
- FROM fact_asset_scan_vulnerability_finding fasv
102
- JOIN
103
- (
104
- SELECT asset_id, previousScan(asset_id) AS baseline_scan, lastScan(asset_id) AS current_scan
105
- FROM dim_asset #{createAssetString(options)}) s
106
- ON s.asset_id = fasv.asset_id AND (fasv.scan_id = s.baseline_scan OR fasv.scan_id = s.current_scan)
107
- GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, fasv.scan_id
108
- HAVING NOT baselineComparison(fasv.scan_id, current_scan) = 'Old'
109
- ) subs
110
- JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
111
- JOIN dim_solution ds USING (solution_id)
112
- JOIN dim_asset da ON subs.asset_id = da.asset_id
113
- JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
114
- JOIN fact_asset fa ON fa.asset_id = da.asset_id
115
- #{createRiskString(options[:riskScore])}
116
- ORDER BY subs.vulnerability_id, subs.asset_id, davs.solution_id"
105
+ "SELECT DISTINCT on (subs.vulnerability_id) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
106
+ string_agg(DISTINCT subs.asset_id ||
107
+ '|' || da.ip_address ||
108
+ '|' || coalesce(da.host_name, '') ||
109
+ '|' || fa.riskscore, '~') as assets,
110
+
111
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
112
+ '|Nexpose ID: ' || ds.nexpose_id ||
113
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
114
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
115
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references
116
+ FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
117
+ FROM fact_asset_scan_vulnerability_finding fasv
118
+ JOIN
119
+ (
120
+ SELECT asset_id, previousScan(asset_id) AS baseline_scan, lastScan(asset_id) AS current_scan
121
+ FROM dim_asset #{createAssetString(options)}) s
122
+ ON s.asset_id = fasv.asset_id AND (fasv.scan_id = s.baseline_scan OR fasv.scan_id = s.current_scan)
123
+ GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, fasv.scan_id
124
+ HAVING NOT baselineComparison(fasv.scan_id, current_scan) = 'Old'
125
+ ) subs
126
+ JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
127
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
128
+ JOIN dim_solution ds USING (solution_id)
129
+ JOIN dim_asset da ON subs.asset_id = da.asset_id
130
+ JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
131
+ JOIN fact_asset fa ON fa.asset_id = da.asset_id
132
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
133
+ #{createRiskString(options[:riskScore])}
134
+
135
+ GROUP BY subs.vulnerability_id, dv.title
136
+ ORDER BY subs.vulnerability_id"
117
137
  end
118
138
 
119
139
  # Gets all new vulnerabilities happening after a reported scan id.
@@ -126,25 +146,36 @@ module NexposeTicketing
126
146
  # |url| |summary| |fix|
127
147
  #
128
148
  def self.new_vulns_since_scan(options = {})
129
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id,
130
- ds.url, proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore
149
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
150
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
151
+ '|Nexpose ID: ' || ds.nexpose_id ||
152
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
153
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
154
+ fa.riskscore, dv.cvss_score,
155
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
156
+ fasva.first_discovered, fasva.most_recently_discovered
131
157
  FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
132
158
  FROM fact_asset_scan_vulnerability_finding fasv
133
159
  JOIN
134
160
  (
135
161
  SELECT asset_id, previousScan(asset_id) AS baseline_scan, lastScan(asset_id) AS current_scan
136
162
  FROM dim_asset #{createAssetString(options)}) s
137
- ON s.asset_id = fasv.asset_id AND (fasv.scan_id >= #{options[:scan_id]} OR fasv.scan_id = s.current_scan)
163
+ ON s.asset_id = fasv.asset_id AND (fasv.scan_id >= #{options[:scan_id]} OR fasv.scan_id = s.current_scan)
138
164
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
139
165
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'New'
140
166
  ) subs
167
+ JOIN dim_vulnerability dv USING (vulnerability_id)
168
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
141
169
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
170
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
142
171
  JOIN dim_solution ds USING (solution_id)
143
172
  JOIN dim_asset da ON subs.asset_id = da.asset_id
144
173
  AND subs.current_scan > #{options[:scan_id]}
145
174
  JOIN fact_asset fa ON fa.asset_id = da.asset_id
146
175
  #{createRiskString(options[:riskScore])}
147
- ORDER BY da.ip_address"
176
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
177
+ fa.riskscore, dv.cvss_score, fasva.first_discovered, fasva.most_recently_discovered
178
+ ORDER BY da.ip_address, subs.vulnerability_id"
148
179
  end
149
180
 
150
181
 
@@ -158,8 +189,17 @@ module NexposeTicketing
158
189
  # |url| |summary| |fix|
159
190
  #
160
191
  def self.new_vulns_by_vuln_id_since_scan(options = {})
161
- "SELECT DISTINCT on (subs.vulnerability_id, subs.asset_id, davs.solution_id) subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id,
162
- ds.url, proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, fa.riskscore
192
+ "SELECT DISTINCT on (subs.vulnerability_id) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
193
+ string_agg(DISTINCT subs.asset_id ||
194
+ '|' || da.ip_address ||
195
+ '|' || coalesce(da.host_name, '') ||
196
+ '|' || fa.riskscore, '~') as assets,
197
+
198
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
199
+ '|Nexpose ID: ' || ds.nexpose_id ||
200
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
201
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
202
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references
163
203
  FROM (SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan
164
204
  FROM fact_asset_scan_vulnerability_finding fasv
165
205
  JOIN
@@ -170,13 +210,17 @@ module NexposeTicketing
170
210
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
171
211
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'New'
172
212
  ) subs
213
+ JOIN dim_vulnerability dv USING (vulnerability_id)
214
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
173
215
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
216
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
174
217
  JOIN dim_solution ds USING (solution_id)
175
218
  JOIN dim_asset da ON subs.asset_id = da.asset_id
176
219
  AND subs.current_scan > #{options[:scan_id]}
177
220
  JOIN fact_asset fa ON fa.asset_id = da.asset_id
178
221
  #{createRiskString(options[:riskScore])}
179
- ORDER BY subs.vulnerability_id, subs.asset_id, davs.solution_id"
222
+ GROUP BY subs.vulnerability_id, dv.title
223
+ ORDER BY vulnerability_id"
180
224
  end
181
225
 
182
226
 
@@ -190,7 +234,7 @@ module NexposeTicketing
190
234
  # |url| |summary| |fix|
191
235
  #
192
236
  def self.old_vulns_since_scan(options = {})
193
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dvs.solution_id, ds.nexpose_id, ds.url,
237
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id, dvs.solution_id, ds.nexpose_id, ds.url,
194
238
  proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
195
239
  FROM (
196
240
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
@@ -223,8 +267,14 @@ module NexposeTicketing
223
267
  # |url| |summary| |fix| |comparison|
224
268
  #
225
269
  def self.all_vulns_since_scan(options = {})
226
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dvs.solution_id, ds.nexpose_id, ds.url,
227
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
270
+ "SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
271
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
272
+ '|Nexpose ID: ' || ds.nexpose_id ||
273
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
274
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
275
+ subs.comparison, fa.riskscore, dv.cvss_score,
276
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
277
+ null as first_discovered, null as most_recently_discovered
228
278
  FROM (
229
279
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
230
280
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -235,17 +285,27 @@ module NexposeTicketing
235
285
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
236
286
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'Old'
237
287
  ) subs
288
+ JOIN dim_vulnerability dv USING (vulnerability_id)
289
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
238
290
  JOIN dim_vulnerability_solution dvs USING (vulnerability_id)
239
291
  JOIN dim_solution ds USING (solution_id)
240
292
  JOIN dim_asset da ON subs.asset_id = da.asset_id
241
- JOIN fact_asset fa ON fa.asset_id = subs.asset_id
242
- #{createRiskString(options[:riskScore])}
293
+ JOIN fact_asset fa ON fa.asset_id = subs.asset_id
294
+ #{createRiskString(options[:riskScore])}
243
295
  AND subs.current_scan > #{options[:scan_id]}
296
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
297
+ fa.riskscore, dv.cvss_score, subs.comparison
244
298
 
245
299
  UNION
246
300
 
247
- SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, davs.solution_id, ds.nexpose_id, ds.url,
248
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
301
+ SELECT DISTINCT on (da.ip_address, subs.vulnerability_id) subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
302
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
303
+ '|Nexpose ID: ' || ds.nexpose_id ||
304
+ '|Fix: ' || coalesce(proofAsText(ds.fix), 'None') ||
305
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
306
+ subs.comparison, fa.riskscore, dv.cvss_score,
307
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
308
+ fasva.first_discovered, fasva.most_recently_discovered
249
309
  FROM
250
310
  (
251
311
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
@@ -258,18 +318,23 @@ module NexposeTicketing
258
318
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
259
319
  HAVING baselineComparison(fasv.scan_id, current_scan) IN ('Same','New')
260
320
  ) subs
321
+ JOIN dim_vulnerability dv USING (vulnerability_id)
322
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
261
323
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
324
+ JOIN fact_asset_vulnerability_age fasva ON subs.vulnerability_id = fasva.vulnerability_id AND subs.asset_id = fasva.asset_id
262
325
  JOIN dim_solution ds USING (solution_id)
263
326
  JOIN dim_asset da ON subs.asset_id = da.asset_id
264
327
  JOIN fact_asset fa ON fa.asset_id = subs.asset_id
265
- #{createRiskString(options[:riskScore])}
328
+ #{createRiskString(options[:riskScore])}
266
329
  AND subs.current_scan > #{options[:scan_id]}
330
+ GROUP BY subs.asset_id, da.ip_address, da.host_name, subs.current_scan, subs.vulnerability_id,
331
+ fa.riskscore, dv.cvss_score, fasva.first_discovered, fasva.most_recently_discovered, subs.comparison
267
332
 
268
333
  ORDER BY ip_address, comparison"
269
334
  end
270
335
 
271
336
  # Gets all vulnerabilities happening after a reported scan id. Sorted by vuln ID. This result set also includes the
272
- # baseline comparision ("Old", "New", or "Same") allowing for IP-based ticket updating.
337
+ # baseline comparision ("Old", "New", or "Same") allowing for vulnerability-based ticket updating.
273
338
  #
274
339
  # * *Args* :
275
340
  # - +reported_scan+ - Last reported scan id.
@@ -279,8 +344,18 @@ module NexposeTicketing
279
344
  # |url| |summary| |fix| |comparison|
280
345
  #
281
346
  def self.all_vulns_by_vuln_id_since_scan(options = {})
282
- "SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dv.title, dvs.solution_id, ds.nexpose_id, ds.url,
283
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
347
+ "SELECT DISTINCT on (subs.vulnerability_id, subs.comparison) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
348
+ string_agg(DISTINCT subs.asset_id ||
349
+ '|' || da.ip_address ||
350
+ '|' || coalesce(da.host_name, '') ||
351
+ '|' || fa.riskscore, '~') as assets,
352
+
353
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
354
+ '|Nexpose ID: ' || ds.nexpose_id ||
355
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
356
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
357
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
358
+ subs.comparison
284
359
  FROM (
285
360
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
286
361
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -291,19 +366,31 @@ module NexposeTicketing
291
366
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
292
367
  HAVING baselineComparison(fasv.scan_id, current_scan) = 'Old'
293
368
  ) subs
369
+ JOIN dim_vulnerability dv USING (vulnerability_id)
370
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
294
371
  JOIN dim_vulnerability_solution dvs USING (vulnerability_id)
295
372
  JOIN dim_solution ds USING (solution_id)
296
373
  JOIN dim_asset da ON subs.asset_id = da.asset_id
297
- JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
298
- JOIN fact_asset fa ON fa.asset_id = subs.asset_id
299
- #{createRiskString(options[:riskScore])}
374
+ JOIN fact_asset fa ON fa.asset_id = subs.asset_id
375
+ #{createRiskString(options[:riskScore])}
300
376
  AND subs.current_scan > #{options[:scan_id]}
377
+ GROUP BY subs.vulnerability_id, dv.title, subs.comparison
301
378
 
302
379
  UNION
303
380
 
304
- SELECT subs.asset_id, da.ip_address, subs.current_scan, subs.vulnerability_id, dv.title, davs.solution_id, ds.nexpose_id, ds.url,
305
- proofAsText(ds.summary) as summary, proofAsText(ds.fix) as fix, subs.comparison, fa.riskscore
306
- FROM
381
+ SELECT DISTINCT on (subs.vulnerability_id, subs.comparison) subs.vulnerability_id, dv.title, MAX(dv.cvss_score) as cvss_score,
382
+ string_agg(DISTINCT subs.asset_id ||
383
+ '|' || da.ip_address ||
384
+ '|' || coalesce(da.host_name, '') ||
385
+ '|' || fa.riskscore, '~') as assets,
386
+
387
+ string_agg(DISTINCT 'Summary: ' || coalesce(ds.summary, 'None') ||
388
+ '|Nexpose ID: ' || ds.nexpose_id ||
389
+ '|Fix: ' || coalesce(proofAsText(ds.fix)) ||
390
+ '|URL: ' || coalesce(ds.url, 'None'), '~') as solutions,
391
+ string_agg(DISTINCT dvr.source || ': ' || dvr.reference, ', ') as references,
392
+ subs.comparison
393
+ FROM
307
394
  (
308
395
  SELECT fasv.asset_id, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
309
396
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -315,15 +402,17 @@ module NexposeTicketing
315
402
  GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
316
403
  HAVING baselineComparison(fasv.scan_id, current_scan) IN ('Same','New')
317
404
  ) subs
405
+ JOIN dim_vulnerability dv USING (vulnerability_id)
406
+ LEFT JOIN dim_vulnerability_reference dvr USING (vulnerability_id)
318
407
  JOIN dim_asset_vulnerability_solution davs USING (vulnerability_id)
319
408
  JOIN dim_solution ds USING (solution_id)
320
409
  JOIN dim_asset da ON subs.asset_id = da.asset_id
321
- JOIN dim_vulnerability dv ON subs.vulnerability_id = dv.vulnerability_id
322
- JOIN fact_asset fa ON fa.asset_id = subs.asset_id
323
- #{createRiskString(options[:riskScore])}
410
+ JOIN fact_asset fa ON fa.asset_id = subs.asset_id
411
+ #{createRiskString(options[:riskScore])}
324
412
  AND subs.current_scan > #{options[:scan_id]}
413
+ GROUP BY subs.vulnerability_id, dv.title, subs.comparison
325
414
 
326
- ORDER BY vulnerability_id, comparison, asset_id, solution_id"
415
+ ORDER BY vulnerability_id, comparison"
327
416
  end
328
417
 
329
418
 
@@ -336,7 +425,7 @@ module NexposeTicketing
336
425
  # - Returns |asset_id| |ip_address| |current_scan| |vulnerability_id| |comparison|
337
426
  #
338
427
  def self.old_tickets_by_ip(options = {})
339
- "SELECT subs.asset_id, subs.ip_address, subs.current_scan, subs.vulnerability_id, subs.comparison
428
+ "SELECT DISTINCT on(subs.ip_address) subs.asset_id, subs.ip_address, subs.current_scan, subs.vulnerability_id, subs.comparison
340
429
  FROM (
341
430
  SELECT fasv.asset_id, s.ip_address, fasv.vulnerability_id, s.current_scan, baselineComparison(fasv.scan_id, s.current_scan) as comparison
342
431
  FROM fact_asset_scan_vulnerability_finding fasv
@@ -5,6 +5,8 @@ module NexposeTicketing
5
5
  require 'nexpose'
6
6
  require 'nexpose_ticketing/queries'
7
7
  require 'nexpose_ticketing/report_helper'
8
+ require 'nexpose_ticketing/nx_logger'
9
+ require 'nexpose_ticketing/version'
8
10
 
9
11
  @timeout = 10800
10
12
 
@@ -13,8 +15,12 @@ module NexposeTicketing
13
15
  end
14
16
 
15
17
  def nexpose_login(nexpose_data)
18
+
16
19
  @nsc = Nexpose::Connection.new(nexpose_data[:nxconsole], nexpose_data[:nxuser], nexpose_data[:nxpasswd])
17
20
  @nsc.login
21
+ @log = NexposeTicketing::NxLogger.instance
22
+ @log.on_connect(nexpose_data[:nxconsole], 3780, @nsc.session_id, "{}")
23
+
18
24
  #After login, create the report helper
19
25
  @report_helper = NexposeReportHelper::ReportOps.new(@nsc, @timeout)
20
26
  end
@@ -52,9 +52,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52
52
  require 'yaml'
53
53
  require 'fileutils'
54
54
  require 'nexpose_ticketing/ticket_repository'
55
+ require 'nexpose_ticketing'
56
+ require 'nexpose_ticketing/nx_logger'
57
+ require 'nexpose_ticketing/version'
55
58
 
56
59
  TICKET_SERVICE_CONFIG_PATH = File.join(File.dirname(__FILE__), '/config/ticket_service.config')
57
- LOGGER_FILE = File.join(File.dirname(__FILE__), '/log/ticket_service.log')
60
+ LOGGER_FILE = File.join(File.dirname(__FILE__), '/logs/ticket_service.log')
58
61
 
59
62
  attr_accessor :helper_data, :nexpose_data, :options, :ticket_repository, :first_time, :nexpose_item_histories
60
63
 
@@ -90,14 +93,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
90
93
  end
91
94
 
92
95
  def setup_logging(enabled = false)
93
- if enabled
94
- require 'logger'
95
- directory = File.dirname(LOGGER_FILE)
96
- FileUtils.mkdir_p(directory) unless File.directory?(directory)
97
- @log = Logger.new(LOGGER_FILE, 'monthly')
98
- @log.level = Logger::INFO
99
- log_message('Logging enabled, starting service.')
100
- end
96
+ helper_log = NexposeTicketing::NxLogger.instance
97
+ helper_log.setup_logging(@options[:logging_enabled],
98
+ @options[:log_level])
99
+
100
+ return unless enabled
101
+ require 'logger'
102
+ directory = File.dirname(LOGGER_FILE)
103
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
104
+ @log = Logger.new(LOGGER_FILE, 'monthly')
105
+ @log.level = Logger::INFO
106
+ log_message('Logging enabled, starting service.')
101
107
  end
102
108
 
103
109
  # Logs a message if logging is enabled.
@@ -222,6 +228,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
222
228
  # There's a new scan with possibly new vulnerabilities.
223
229
  def delta_site_new_scan(ticket_repository, nexpose_item, options, helper, file_site_histories, tag_id=nil)
224
230
  log_message("New scan detected for nexpose id: #{nexpose_item}. Generating report.")
231
+ item = options[:tag_run] ? 'asset' : 'site'
225
232
 
226
233
  if options[:ticket_mode] == 'I' || options[:ticket_mode] == 'V'
227
234
  # I-mode and V-mode tickets require updating the tickets in the target system.
@@ -270,16 +277,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
270
277
  tag_run: options[:tag_run],
271
278
  tag: tag_id)
272
279
 
273
- preparse = CSV.new(new_scan_vuln_file.path, headers: :first_row)
280
+ preparse = CSV.open(new_scan_vuln_file.path, headers: :first_row)
274
281
  empty_report = preparse.shift.nil?
275
- log_message("No new vulnerabilities found in new scan for site: #{nexpose_item}.") if empty_report
276
- log_message("New vulnerabilities found in new scan for site #{nexpose_item}, preparing tickets.") unless empty_report
282
+ preparse.close
283
+
284
+
285
+ log_message("No new vulnerabilities found in new scan for #{item}: #{nexpose_item}.") if empty_report
286
+ log_message("New vulnerabilities found in new scan for #{item} #{nexpose_item}, preparing tickets.") unless empty_report
277
287
  unless empty_report
278
288
  ticket_rate_limiter(options, new_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_create_tickets(ticket_batch, tag_id.nil? ? nexpose_item : "T#{tag_id}")}, Proc.new {|tickets| helper.create_tickets(tickets)})
279
289
  end
280
290
 
281
291
  if helper.respond_to?('prepare_close_tickets') && helper.respond_to?('close_tickets')
282
292
  old_scan_vuln_file = ticket_repository.old_vulns(scan_id: file_site_histories[nexpose_item],
293
+ nexpose_item: nexpose_item,
283
294
  site_id: nexpose_item,
284
295
  severity: options[:severity],
285
296
  riskScore: options[:riskScore],
@@ -287,10 +298,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
287
298
  tag_run: options[:tag_run],
288
299
  tag: tag_id)
289
300
 
290
- preparse = CSV.new(old_scan_vuln_file.path, headers: :first_row, :skip_blanks => true)
301
+ preparse = CSV.open(old_scan_vuln_file.path, headers: :first_row, :skip_blanks => true)
291
302
  empty_report = preparse.shift.nil?
292
- log_message("No old (closed) vulnerabilities found in new scan for site: #{nexpose_item}.") if empty_report
293
- log_message("Old vulnerabilities found in new scan for site #{nexpose_item}, preparing closures.") unless empty_report
303
+ preparse.close
304
+ log_message("No old (closed) vulnerabilities found in new scan for #{item}: #{nexpose_item}.") if empty_report
305
+ log_message("Old vulnerabilities found in new scan for #{item} #{nexpose_item}, preparing closures.") unless empty_report
294
306
  unless empty_report
295
307
  ticket_rate_limiter(options, old_scan_vuln_file, Proc.new {|ticket_batch| helper.prepare_close_tickets(ticket_batch, tag_id.nil? ? nexpose_item : "T#{tag_id}")}, Proc.new {|tickets| helper.close_tickets(tickets)})
296
308
  end
@@ -366,7 +378,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366
378
  # Prep the batch of tickets
367
379
  log_message('Creating tickets.')
368
380
  tickets = ticket_prepare_method.call(ticket_batch.join(''))
369
- log_message("Generated tickets: #{ticket_batch.size}")
381
+ log_message("Parsed rows: #{ticket_batch.size}")
370
382
  # Sent them off
371
383
  log_message('Sending tickets.')
372
384
  ticket_send_method.call(tickets)