nexpose_servicenow 0.6.2 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
+ require_relative './queries_base'
2
+
1
3
  module NexposeServiceNow
2
- class Queries
4
+ class NexposeQueries < QueriesBase
3
5
  def self.vulnerabilities(options={})
4
6
  "SELECT
5
7
  concat('R7_', vulnerability_id) as ID,
@@ -78,9 +80,9 @@ module NexposeServiceNow
78
80
  def self.vulnerability_references(options={})
79
81
  "SELECT concat('R7_', vulnerability_id) as ID, dvr.Source, dvr.Reference
80
82
  FROM dim_vulnerability
81
- LEFT OUTER JOIN
82
- (SELECT vulnerability_id, dvr.Source, dvr.Reference
83
- FROM dim_vulnerability_reference dvr) dvr USING (vulnerability_id)
83
+ JOIN
84
+ (SELECT vulnerability_id, dvr.Source, dvr.Reference
85
+ FROM dim_vulnerability_reference dvr) dvr USING (vulnerability_id)
84
86
  WHERE date_modified >= '#{options[:vuln_query_date]}'"
85
87
  end
86
88
 
@@ -125,7 +127,7 @@ module NexposeServiceNow
125
127
  WHERE scan_id = lastScan(asset_id)"
126
128
  end
127
129
 
128
- def self.service_definition(options={})
130
+ def self.service_definition(options={})
129
131
  "SELECT DISTINCT on(dsf.name, ds.name, dp.name, port)
130
132
  dsf.name, ds.name as service_name, dp.name as protocol, port
131
133
 
@@ -268,63 +270,56 @@ module NexposeServiceNow
268
270
  end
269
271
 
270
272
  def self.vulnerable_new_items(options={})
271
- standard_filter = if options[:id_type] == 'site'
272
- "MIN(fasv.scan_id) > #{options[:delta]}"
273
- else
274
- "MIN(fasv.date) > '#{options[:delta]}'"
275
- end
276
-
277
273
  cve_filter = self.generate_cve_filter(options[:filters][:cve])
278
274
  date_filter = self.generate_date_filter(options[:filters][:date], false)
279
275
  cvss_filter = self.generate_cvss_filter(options[:filters][:cvss])
280
276
 
281
- "SELECT
282
- CAST(subq.asset_id as text) Configuration_Item,
283
- TRUE as Active,
284
- concat('R7_', subq.vulnerability_id) as Vulnerability,
285
- fasva.first_discovered as First_Found,
286
- fasva.most_recently_discovered as Last_Found,
287
- subq.vulnerability_instances as Times_Found,
288
- subq.ip_address as IP_Address,
289
- coalesce(NULLIF(CONCAT('\"', favi.proof ,'\"'), '\"\"'), 'None') as Proof,
290
- favi.stat_desc as Status,
291
- array_to_string(favi.ports, ' ', '') as Ports,
292
- coalesce(NULLIF(concat(favi.pro_desc, ' (', favi.name, ')') ,'N/A ()'), 'None') as Protocol,
293
- array_to_string(favi.solution_ids, ',', '') as Solutions
294
- FROM (
295
- SELECT fasv.asset_id, fasv.vulnerability_id, vulnerability_instances,
296
- MIN(fasv.scan_id) as first_found, MAX(fasv.scan_id) as latest_found,
297
- s.current_scan, s.host_name, s.ip_address
298
- FROM fact_asset_scan_vulnerability_finding fasv
299
-
300
- #{cve_filter}
301
- #{cvss_filter}
302
-
303
- JOIN (SELECT asset_id, host_name, ip_address, lastScan(asset_id) AS current_scan
304
- FROM dim_asset
305
- ) s ON s.asset_id = fasv.asset_id
306
- GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, s.host_name, s.ip_address, vulnerability_instances
307
- HAVING MAX(fasv.scan_id)=current_scan AND #{standard_filter}
308
- ) subq
309
-
310
- JOIN (SELECT asset_id, vulnerability_id,
311
- first_discovered, most_recently_discovered
312
- FROM fact_asset_vulnerability_age
313
- #{date_filter}) fasva USING (asset_id, vulnerability_id)
314
-
315
- JOIN (SELECT DISTINCT on(asset_id, vulnerability_id, scan_id)
316
- asset_id, scan_id, vulnerability_id,
317
- proofAsText(proof) as proof, vs.description as stat_desc,
318
- array_agg(DISTINCT port) as ports, dp.name,
319
- dp.description as pro_desc,
320
- array_agg(DISTINCT dvs.solution_id) as solution_ids
321
- FROM fact_asset_vulnerability_instance
322
- INNER JOIN dim_protocol dp USING (protocol_id)
323
- INNER JOIN dim_vulnerability_status vs using (status_id)
324
- LEFT JOIN dim_asset_vulnerability_solution dvs USING (asset_id, vulnerability_id)
325
- GROUP BY asset_id, scan_id, vulnerability_id, proof, stat_desc, port, dp.name, pro_desc
326
- ) favi ON favi.asset_id = subq.asset_id AND favi.scan_id = subq.current_scan AND favi.vulnerability_id = subq.vulnerability_id
327
- ORDER BY fasva.asset_id, vulnerability"
277
+ "SELECT CAST(asset_id as text) Configuration_Item,
278
+ TRUE as Active,
279
+ concat('R7_', vulnerability_id) as Vulnerability,
280
+ first_discovered as First_Found,
281
+ most_recently_discovered as Last_Found,
282
+ vulnerability_instances as Times_Found,
283
+ ip_address as IP_Address,
284
+ proof as Proof,
285
+ status as Status,
286
+ ports as Ports,
287
+ protocol as Protocol,
288
+ array_to_string(dvsol.solution_ids, ',', '') as Solutions
289
+ FROM
290
+ (SELECT asset_id, scan_id, vulnerability_id, vulnerability_instances
291
+ FROM fact_asset_vulnerability_finding
292
+ WHERE (asset_id, vulnerability_id) NOT IN
293
+ (SELECT asset_id, vulnerability_id
294
+ FROM fact_asset_scan_vulnerability_finding
295
+ WHERE scan_id=#{options[:delta]})) favf
296
+ #{cve_filter}
297
+ #{cvss_filter}
298
+ JOIN (SELECT asset_id, vulnerability_id,
299
+ first_discovered, most_recently_discovered
300
+ FROM fact_asset_vulnerability_age #{date_filter}) fasva USING (asset_id, vulnerability_id)
301
+ JOIN (SELECT asset_id,
302
+ vulnerability_id,
303
+ string_agg(proof, E'\n') as proof,
304
+ array_to_string(array_agg(DISTINCT port), ' ', '') as ports,
305
+ string_agg(DISTINCT status, ',') as status,
306
+ string_agg(DISTINCT protocol, ',') as protocol
307
+ FROM (SELECT asset_id, vulnerability_id,
308
+ proofAsText(proof) as proof,
309
+ status_id as status_id,
310
+ port,
311
+ dp.description as protocol,
312
+ dvs.description as status
313
+ FROM fact_asset_vulnerability_instance
314
+ JOIN dim_protocol dp USING (protocol_id)
315
+ JOIN dim_vulnerability_status dvs USING (status_id)) favi
316
+ GROUP BY asset_id, vulnerability_id) favi USING (asset_id, vulnerability_id)
317
+ JOIN (SELECT asset_id, ip_address
318
+ FROM dim_asset) s USING (asset_id)
319
+ LEFT JOIN (SELECT asset_id, vulnerability_id,
320
+ array_agg(DISTINCT solution_id) as solution_ids
321
+ FROM dim_asset_vulnerability_solution
322
+ GROUP BY asset_id, vulnerability_id) dvsol USING (asset_id, vulnerability_id)"
328
323
  end
329
324
 
330
325
  def self.vulnerable_old_items(options={})
@@ -346,33 +341,31 @@ module NexposeServiceNow
346
341
  'MIN(fasv.scan_id) as first_found,'
347
342
  end
348
343
 
349
- "SELECT
344
+ "SELECT
350
345
  CAST(da.asset_id as text) Configuration_Item,
351
346
  FALSE as Active,
352
- concat('R7_', subq.vulnerability_id) as Vulnerability,
353
- da.ip_address as IP_Address
347
+ concat('R7_', subq.vulnerability_id) as Vulnerability
354
348
  FROM (
355
349
  SELECT fasv.asset_id, fasv.vulnerability_id,
356
350
  #{date_field}
357
351
  MAX(fasv.scan_id) as latest_found,
358
- s.current_scan, s.host_name, s.ip_address
359
- FROM fact_asset_scan_vulnerability_finding fasv
352
+ s.current_scan
353
+ FROM fact_asset_scan_vulnerability_finding fasv
360
354
 
361
355
  #{cve_filter}
362
356
  #{cvss_filter}
363
357
 
364
358
  JOIN (
365
- SELECT asset_id, host_name, ip_address, lastScan(asset_id) AS current_scan FROM dim_asset
359
+ SELECT asset_id, lastScan(asset_id) AS current_scan FROM dim_asset
366
360
  ) s ON s.asset_id = fasv.asset_id
367
- GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan, s.host_name, s.ip_address, vulnerability_instances
361
+ GROUP BY fasv.asset_id, fasv.vulnerability_id, s.current_scan
368
362
 
369
363
  HAVING MAX(fasv.scan_id) < current_scan
370
364
  AND #{standard_filter}
371
365
  ) subq
372
366
 
373
367
  JOIN dim_asset da ON subq.asset_id = da.asset_id
374
- #{date_filter}
375
- ORDER BY da.ip_address"
368
+ #{date_filter}"
376
369
 
377
370
  end
378
371
 
@@ -424,31 +417,9 @@ module NexposeServiceNow
424
417
  end
425
418
 
426
419
  def self.latest_scans(options={})
427
- 'SELECT ds.site_id, ds.last_scan_id, dsc.finished
420
+ 'SELECT ds.site_id, ds.name, ds.last_scan_id, dsc.finished
428
421
  FROM dim_site ds
429
422
  JOIN dim_scan dsc ON ds.last_scan_id = dsc.scan_id'
430
423
  end
431
-
432
- def self.multiple_reports?(query_name)
433
- single_queries = %w(vulnerabilities vulnerability_category
434
- asset_groups latest_scans
435
- vulnerability_solutions vulnerability_references
436
- )
437
- return !(single_queries.include? query_name.to_s)
438
- end
439
-
440
- def self.csv_diff_required?(query_name)
441
- diff_required = %w(asset_groups asset_group_memberships)
442
- return (diff_required.include? query_name.to_s)
443
- end
444
-
445
- # TODO: Refactor this.
446
- def self.query_keys(query_name)
447
- if query_name.to_s == 'asset_groups'
448
- [0]
449
- else
450
- [0,1]
451
- end
452
- end
453
424
  end
454
425
  end
@@ -0,0 +1,25 @@
1
+ module NexposeServiceNow
2
+ class QueriesBase
3
+ def self.single_report?(query_name)
4
+ single_queries = %w(vulnerabilities vulnerability_category
5
+ asset_groups latest_scans
6
+ vulnerability_solutions vulnerability_references
7
+ )
8
+ return single_queries.include? query_name.to_s
9
+ end
10
+
11
+ def self.csv_diff_required?(query_name)
12
+ diff_required = %w(asset_groups asset_group_memberships)
13
+ return (diff_required.include? query_name.to_s)
14
+ end
15
+
16
+ # TODO: Refactor this.
17
+ def self.query_keys(query_name)
18
+ if query_name.to_s == 'asset_groups'
19
+ [0]
20
+ else
21
+ [0,1]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,330 @@
1
+ require_relative './queries_base'
2
+ require_relative '../nx_logger'
3
+
4
+ module NexposeServiceNow
5
+ class WarehouseQueries < QueriesBase
6
+ def self.latest_scans(options={})
7
+ 'SELECT ds.site_id, ds.name, ds.last_scan_id, dsc.finished
8
+ FROM dim_site ds
9
+ JOIN dim_scan dsc ON ds.last_scan_id = dsc.scan_id'
10
+ end
11
+
12
+ def self.vulnerabilities(options={})
13
+ "SELECT
14
+ concat('R7_', vulnerability_id) AS ID,
15
+ cve.ref AS CVE,
16
+ cwe.ref AS CWE,
17
+ concat('Rapid7 Nexpose') AS Source,
18
+ to_char(date_published, 'yyyy-MM-dd hh:mm:ss') AS date_published,
19
+ to_char(date_modified, 'yyyy-MM-dd hh:mm:ss') AS Last_Modified,
20
+ dvc.category,
21
+ severity AS Severity_Rating,
22
+ severity_score AS Severity,
23
+ pci_status,
24
+ pci_adjusted_cvss_score AS PCI_Severity,
25
+ coalesce(NULLIF(CONCAT('\"',regexp_replace(title, '\"','''', 'g'),'\"'), '\"\"'), 'None') AS Summary,
26
+ coalesce(NULLIF(CONCAT('\"',regexp_replace(htmltotext(description), '\"','''', 'g'),'\"'), '\"\"'), 'None') AS Threat,
27
+ ROUND(risk_score :: NUMERIC, 2) AS Riskscore,
28
+ cvss_vector,
29
+ ROUND(cvss_impact_score :: NUMERIC, 2) AS Impact_Score,
30
+ ROUND(cvss_exploit_score :: NUMERIC, 2) AS Exploit_Score,
31
+ cvss_access_complexity AS Access_Complexity,
32
+ cvss_access_vector AS Access_Vector,
33
+ cvss_authentication AS Authentication,
34
+ ROUND(cvss_score :: NUMERIC, 2) AS Vulnerability_Score,
35
+ cvss_integrity_impact AS Integrity_Impact,
36
+ cvss_confidentiality_impact AS Confidentiality_Impact,
37
+ cvss_availability_impact AS Availability_Impact,
38
+ (CASE
39
+ WHEN exploits > 0
40
+ THEN 'true'
41
+ ELSE 'false'
42
+ END) AS Exploitability,
43
+ (CASE
44
+ WHEN malware_kits > 0
45
+ THEN 'true'
46
+ ELSE 'false'
47
+ END) AS Malware_Kits,
48
+ NULLIF(CONCAT('\"', array_to_string(sol.solutions, ',', ''), '\"'), '\"\"') AS Solution
49
+ FROM
50
+ dim_vulnerability
51
+ LEFT OUTER JOIN
52
+ (SELECT DISTINCT ON (vulnerability_id)
53
+ vulnerability_id,
54
+ dvr.reference AS ref
55
+ FROM dim_vulnerability_reference dvr
56
+ WHERE source = 'CWE'
57
+ GROUP BY dvr.vulnerability_id, dvr.reference
58
+ ) cwe USING (vulnerability_id)
59
+ LEFT OUTER JOIN
60
+ (SELECT DISTINCT ON (vulnerability_id)
61
+ vulnerability_id,
62
+ dvr.reference AS ref
63
+ FROM dim_vulnerability_reference dvr
64
+ WHERE source = 'CVE'
65
+ GROUP BY dvr.vulnerability_id, dvr.reference
66
+ ) cve USING (vulnerability_id)
67
+ LEFT OUTER JOIN (SELECT DISTINCT ON (dvc.vulnerability_id)
68
+ dvc.vulnerability_id,
69
+ dvc.category_name AS category
70
+ FROM dim_vulnerability_category dvc
71
+ GROUP BY dvc.vulnerability_id, dvc.category_name) dvc USING (vulnerability_id)
72
+ LEFT OUTER JOIN (SELECT
73
+ dvr.vulnerability_id,
74
+ string_agg(dvr.source || ': ' || dvr.reference, '|') AS references
75
+ FROM dim_vulnerability_reference dvr
76
+ GROUP BY dvr.vulnerability_id) ref USING (vulnerability_id)
77
+ LEFT OUTER JOIN (SELECT
78
+ vulnerability_id,
79
+ array_agg(solution_id) AS solutions
80
+ FROM dim_vulnerability_solution
81
+ GROUP BY vulnerability_id) sol USING (vulnerability_id)
82
+ WHERE date_modified >= '#{options[:vuln_query_date]}'"
83
+ end
84
+
85
+ def self.vulnerability_references(options={})
86
+ "SELECT concat('R7_', vulnerability_id) as ID,
87
+ Source,
88
+ Reference
89
+ FROM (SELECT vulnerability_id
90
+ FROM dim_vulnerability
91
+ WHERE date_modified >= '#{options[:vuln_query_date]}') dv
92
+ JOIN (SELECT vulnerability_id, Source, Reference
93
+ FROM dim_vulnerability_reference) dvr USING (vulnerability_id)"
94
+ end
95
+
96
+ def self.vulnerability_category(options={})
97
+ "SELECT concat('R7_', vulnerability_id) as ID, dvc.Category
98
+ FROM dim_vulnerability
99
+ LEFT OUTER JOIN
100
+ (SELECT vulnerability_id, category_name as Category
101
+ FROM dim_vulnerability_category dvc) dvc USING (vulnerability_id)
102
+ WHERE date_modified >= '#{options[:vuln_query_date]}'"
103
+ end
104
+
105
+ def self.assets(options={})
106
+ last_import_date = options[:delta]
107
+ site_id = options[:site_id]
108
+
109
+ "WITH scan_found AS (
110
+ SELECT DISTINCT (asset_id)
111
+ asset_id,
112
+ MIN(scan_id) AS scan_found
113
+ FROM fact_asset_event
114
+ WHERE type = 'SCAN'
115
+ GROUP BY asset_id
116
+ ), new_assets AS (
117
+ SELECT
118
+ sf.asset_id
119
+ FROM dim_scan ds
120
+ JOIN scan_found sf ON (ds.scan_id = sf.scan_found)
121
+ WHERE ds.finished > '#{last_import_date}'
122
+ AND ds.site_id = #{site_id}
123
+ )
124
+ SELECT
125
+ coalesce(host_name, CAST(dim_asset.asset_id AS TEXT)) AS Name,
126
+ dim_asset.ip_address,
127
+ dim_asset.mac_address,
128
+ concat('Rapid7 Nexpose') AS Discovery_Source,
129
+ CAST(CASE
130
+ WHEN dim_asset.host_type = 'Virtual Machine' OR dim_asset.host_type = 'Hypervisor'
131
+ THEN 1
132
+ ELSE 0
133
+ END AS BIT) AS Is_Virtual,
134
+ CONCAT('\"', dim_asset.os_description, '\"') AS Operating_System,
135
+ dim_asset.last_assessed_for_vulnerabilities AS Most_Recent_Discovery,
136
+ dim_asset.asset_id AS Nexpose_ID,
137
+ fact_asset.pci_status,
138
+ dim_asset.credential_status
139
+ FROM dim_asset
140
+ JOIN fact_asset USING (asset_id)
141
+ WHERE dim_asset.asset_id IN (
142
+ SELECT asset_id
143
+ FROM new_assets
144
+ )"
145
+ end
146
+
147
+ def self.generate_vulnerability_filter(cves, cvss_range)
148
+ return '' if cves.to_a.empty? && cvss_range.to_a.empty?
149
+ vuln_filter = ''
150
+ vuln_filter += cves.map { |c| "reference='#{c}'" }.join(' OR ') unless cves.nil?
151
+
152
+ cvss_min = cvss_range.first || '0'
153
+ cvss_max = cvss_range.last || '10'
154
+ unless cvss_min.to_s == '0' && cvss_max.to_s == '10'
155
+ vuln_filter += ' AND ' unless vuln_filter.empty?
156
+ vuln_filter += "cvss_score >= #{cvss_min} AND cvss_score <= #{cvss_max}"
157
+ end
158
+ return '' if vuln_filter.empty?
159
+
160
+ "AND favi.vulnerability_id IN (
161
+ SELECT dvr.vulnerability_id
162
+ FROM dim_vulnerability_reference dvr
163
+ JOIN dim_vulnerability dv ON dv.vulnerability_id = dvr.vulnerability_id
164
+ WHERE dvr.vulnerability_id IN (SELECT av.vulnerability_id FROM asset_vulns av)
165
+ AND #{vuln_filter})"
166
+ end
167
+
168
+ def self.generate_date_filter(dates)
169
+ return '' if dates.to_a.empty?
170
+ filters = []
171
+ filters << "first_found > '#{dates.first}'" unless dates.first.nil?
172
+ filters << "first_found < '#{dates.last}'" unless dates.last.nil?
173
+ filters.empty? ? '' : " AND #{filters.join(' AND ')}"
174
+ end
175
+
176
+ def self.vulnerable_new_items(options={})
177
+ site_id = options[:site_id]
178
+ last_import_date = options[:delta]
179
+ vuln_filter = self.generate_vulnerability_filter(
180
+ options[:filters][:cve], options[:filters][:cvss]
181
+ )
182
+ date_filters = self.generate_date_filter(options[:filters][:date])
183
+
184
+ "WITH asset_vulns AS (
185
+ SELECT DISTINCT ON (favf.asset_id, favf.vulnerability_id)
186
+ favf.asset_id,
187
+ favf.vulnerability_id,
188
+ favf.date AS first_found,
189
+ favf.vulnerability_instances,
190
+ ip_address,
191
+ (SELECT max(date)
192
+ FROM fact_asset_event fae
193
+ WHERE type = 'SCAN'
194
+ AND fae.asset_id = favf.asset_id
195
+ GROUP BY fae.asset_id) AS last_found
196
+ FROM fact_asset_vulnerability_finding favf
197
+ JOIN dim_site_asset dsa ON favf.asset_id = dsa.asset_id AND dsa.site_id = #{site_id}
198
+ JOIN dim_asset da ON favf.asset_id = da.asset_id
199
+ WHERE date > '#{last_import_date}'
200
+ ), valid_vulns AS (
201
+ SELECT DISTINCT ON (favi.asset_id, favi.vulnerability_id)
202
+ favi.asset_id,
203
+ favi.vulnerability_id,
204
+ array_agg(DISTINCT favi.port) AS ports,
205
+ array_agg(DISTINCT davs.solution_id) AS solutions,
206
+ favi.protocol,
207
+ regexp_replace(htmltotext(favi.proof), '\"','''', 'g') AS proof,
208
+ favi.status
209
+ FROM fact_asset_vulnerability_instance favi
210
+ LEFT JOIN dim_asset_vulnerability_finding_solution davs ON
211
+ davs.asset_id = favi.asset_id AND davs.vulnerability_id = favi.vulnerability_id
212
+ WHERE (favi.vulnerability_id, favi.asset_id) IN (SELECT av.vulnerability_id, av.asset_id FROM asset_vulns av)
213
+ #{vuln_filter}
214
+ GROUP BY favi.asset_id, favi.vulnerability_id, protocol, proof, status
215
+ )
216
+ SELECT
217
+ CAST(nv.asset_id AS TEXT) AS Configuration_Item,
218
+ 'true' AS Active,
219
+ concat('R7_', nv.vulnerability_id) AS Vulnerability,
220
+ nv.first_found AS First_Found,
221
+ nv.last_found AS Last_Found,
222
+ nv.vulnerability_instances AS Times_Found,
223
+ nv.ip_address AS IP_Address,
224
+ coalesce(NULLIF(CONCAT('\"', vv.proof, '\"'), '\"\"'), 'None') AS Proof,
225
+ vv.status AS Status,
226
+ array_to_string(vv.ports, ' ', '') AS Ports,
227
+ coalesce(vv.protocol, 'None') AS Protocol,
228
+ NULLIF(CONCAT('\"', array_to_string(vv.solutions, ',', ''), '\"'), '\"\"') AS Solutions
229
+ FROM asset_vulns nv
230
+ JOIN valid_vulns vv ON vv.asset_id = nv.asset_id AND vv.vulnerability_id = nv.vulnerability_id
231
+ #{date_filters}
232
+ ORDER BY nv.asset_id, Vulnerability"
233
+ end
234
+
235
+ def self.vulnerable_old_items(options={})
236
+ site_id = options[:site_id]
237
+ last_import_date = options[:delta]
238
+ vuln_filter = self.generate_vulnerability_filter(
239
+ options[:filters][:cve], options[:filters][:cvss]
240
+ )
241
+ date_filters = self.generate_date_filter(options[:filters][:date])
242
+
243
+ "WITH site_assets AS (
244
+ SELECT asset_id
245
+ FROM dim_site_asset
246
+ WHERE site_id = #{site_id}
247
+ ), asset_vulns AS (
248
+ -- Asset vulns at last import
249
+ SELECT asset_id, vulnerability_id, date AS first_found
250
+ FROM fact_asset_vulnerability_finding_date
251
+ WHERE asset_id IN (SELECT asset_id FROM site_assets)
252
+ AND DAY = (SELECT periodbefore('#{last_import_date}'))
253
+ ), current_vulns AS (
254
+ SELECT asset_id, vulnerability_id
255
+ FROM fact_asset_vulnerability_finding
256
+ WHERE asset_id IN (SELECT asset_id FROM site_assets)
257
+ )
258
+ SELECT
259
+ CAST(da.asset_id AS TEXT) AS Configuration_Item,
260
+ 'false' AS Active,
261
+ concat('R7_', favi.vulnerability_id) AS Vulnerability,
262
+ da.ip_address AS IP_Address
263
+ FROM dim_asset da
264
+ -- Name this table favi to use the vulnerability ID with the vuln filter.
265
+ JOIN asset_vulns favi ON (da.asset_id = favi.asset_id)
266
+ LEFT JOIN current_vulns cv ON (cv.asset_id = da.asset_id) AND (cv.vulnerability_id = favi.vulnerability_id)
267
+ WHERE da.asset_id IN (SELECT asset_id FROM site_assets)
268
+ AND cv.vulnerability_id IS NULL
269
+ #{vuln_filter}
270
+ #{date_filters}
271
+ ORDER BY da.asset_id, Vulnerability"
272
+ end
273
+
274
+ def self.vulnerability_solutions(options={})
275
+ "SELECT DISTINCT (solution_id)
276
+ solution_id,
277
+ nexpose_id,
278
+ coalesce(NULLIF(CONCAT('\"',regexp_replace(htmltotext(fix), '\"','''', 'g'),'\"'), '\"\"'), 'None') as fix,
279
+ estimate,
280
+ coalesce(NULLIF(CONCAT('\"',regexp_replace(htmltotext(summary), '\"','''', 'g'),'\"'), '\"\"'), 'None') as summary,
281
+ solution_type,
282
+ coalesce(NULLIF(CONCAT('\"',regexp_replace(htmltotext(applies_to), '\"','''', 'g'),'\"'), '\"\"'), 'None') as applies_to,
283
+ coalesce(NULLIF(CONCAT('\"', url, '\"'), '\"\"'), 'None') as url,
284
+ coalesce(NULLIF(CONCAT('\"',regexp_replace(htmltotext(additional_data), '\"','''', 'g'),'\"'), '\"\"'), 'None') as additional_data,
285
+ CONCAT('\"', array_to_string(req_solutions, ',', ''), '\"') as required_solutions,
286
+ CONCAT('\"', array_to_string(super_solutions, ',', ''), '\"') as superceding_solutions
287
+ FROM dim_solution
288
+ RIGHT OUTER JOIN (
289
+ SELECT DISTINCT (solution_id) solution_id
290
+ FROM (
291
+ SELECT solution_id, vulnerability_id, date_modified
292
+ FROM dim_vulnerability
293
+ LEFT JOIN dim_vulnerability_solution idvs USING (vulnerability_id)
294
+ ) dvs
295
+ WHERE date_modified >= '#{options[:vuln_query_date]}'
296
+ UNION
297
+ SELECT DISTINCT (solution_id) solution_id
298
+ FROM dim_solution
299
+ LEFT JOIN (
300
+ SELECT solution_id, vulnerability_id, date_modified
301
+ FROM dim_vulnerability
302
+ LEFT JOIN dim_vulnerability_solution idvs USING (vulnerability_id)
303
+ ) ndvs USING (solution_id)
304
+ WHERE vulnerability_id IS NULL
305
+ ) dvs USING (solution_id)
306
+ LEFT JOIN (
307
+ SELECT DISTINCT (solution_id) solution_id,
308
+ array_agg(required_solution_id) as req_solutions
309
+ FROM dim_solution_prerequisite
310
+ GROUP BY solution_id
311
+ ) dsp USING (solution_id)
312
+ JOIN (
313
+ SELECT DISTINCT (solution_id) solution_id,
314
+ array_agg(superceding_solution_id) as super_solutions
315
+ FROM dim_solution_highest_supercedence
316
+ GROUP BY solution_id
317
+ ) dshs USING (solution_id)
318
+ ORDER BY solution_id"
319
+ end
320
+
321
+ def self.method_missing(m, *args, &block)
322
+ msg = "Method #{m} is not yet available for data warehouse mode."
323
+
324
+ log = NexposeServiceNow::NxLogger.instance
325
+ log.log_message(msg)
326
+ puts "#{msg} Exiting..."
327
+ exit 0
328
+ end
329
+ end
330
+ end