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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/nexpose_servicenow.rb +58 -91
- data/lib/nexpose_servicenow/arg_parser.rb +80 -75
- data/lib/nexpose_servicenow/chunker.rb +0 -1
- data/lib/nexpose_servicenow/csv_compare.rb +17 -0
- data/lib/nexpose_servicenow/helpers/connection_helper.rb +79 -0
- data/lib/nexpose_servicenow/helpers/data_warehouse_helper.rb +134 -0
- data/lib/nexpose_servicenow/{nexpose_helper.rb → helpers/nexpose_console_helper.rb} +32 -85
- data/lib/nexpose_servicenow/historical_data.rb +46 -355
- data/lib/nexpose_servicenow/{queries.rb → queries/nexpose_queries.rb} +61 -90
- data/lib/nexpose_servicenow/queries/queries_base.rb +25 -0
- data/lib/nexpose_servicenow/queries/warehouse_queries.rb +330 -0
- data/lib/nexpose_servicenow/version.rb +1 -1
- data/nexpose_servicenow.gemspec +14 -11
- metadata +27 -6
@@ -1,5 +1,7 @@
|
|
1
|
+
require_relative './queries_base'
|
2
|
+
|
1
3
|
module NexposeServiceNow
|
2
|
-
class
|
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
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
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
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
FROM fact_asset_scan_vulnerability_finding
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
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
|
359
|
-
|
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,
|
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
|
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
|