fleet/ee/vulnerability-dashboard/api/controllers/view-dashboard.js
Eric ef2ce8bd7f
Vulnerability dashboard: Update result name in MySQL query. (#35368)
Changes:
- Updated the query to find critically vulnerable rare software for
MySQL databases to return affected host names as `hostNames`
2025-11-07 14:38:17 -06:00

1475 lines
62 KiB
JavaScript

module.exports = {
friendlyName: 'View dashboard',
description: 'Display "Dashboard" page.',
exits: {
success: {
viewTemplatePath: 'pages/dashboard'
}
},
fn: async function () {
// console.time(`Dashboard page view action`);
let dataForGraphs = {};
// Get the most recently created Vulnerability and VulnerabilityInstall record.
let latestVulnerabilityInstallRecord = await VulnerabilityInstall.find().sort('updatedAt DESC').limit(1);
let latestVulnerabilityRecord = await Vulnerability.find().sort('updatedAt DESC').limit(1);
// Get the most recent createdAt timestamp from these records, we'll use this timestamp to set the "Last updated:" on the dashboard page.
let latestTimestamp = Math.max(latestVulnerabilityRecord[0].updatedAt, latestVulnerabilityInstallRecord[0].updatedAt);
let dashboardDataLastUpdatedAt = latestTimestamp;
dataForGraphs.lastUpdatedAt = dashboardDataLastUpdatedAt;
//
// ╦ ╦╦ ╦╦ ╔╗╔╔═╗╦═╗╔═╗╔╗ ╦╦ ╦╔╦╗╦ ╦ ╔═╗╔═╗╦ ╦╔╗╔╔╦╗╔═╗
// ╚╗╔╝║ ║║ ║║║║╣ ╠╦╝╠═╣╠╩╗║║ ║ ║ ╚╦╝ ║ ║ ║║ ║║║║ ║ ╚═╗
// ╚╝ ╚═╝╩═╝╝╚╝╚═╝╩╚═╩ ╩╚═╝╩╩═╝╩ ╩ ╩ ╚═╝╚═╝╚═╝╝╚╝ ╩ ╚═╝
// Note: the information gathered in this section is used in the unique vulnerability count tiles, as well as the "What percentage are critical?" chart.
let nativeQueryToFindAllVulnerabilityIdsWithSeverity;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
nativeQueryToFindAllVulnerabilityIdsWithSeverity = `
SELECT
vulnerability.id,
vulnerability.severity
FROM vulnerability
WHERE EXISTS (
SELECT 1
FROM vulnerabilityinstall
WHERE vulnerabilityinstall.vulnerability = vulnerability.id
AND (vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0)
);`;
} else {
nativeQueryToFindAllVulnerabilityIdsWithSeverity = `
SELECT
vulnerability.id,
vulnerability.severity
FROM vulnerability
WHERE EXISTS (
SELECT 1
FROM vulnerabilityinstall
WHERE vulnerabilityinstall.vulnerability = vulnerability.id
AND (vulnerabilityinstall.uninstalledAt IS NULL
OR vulnerabilityinstall.uninstalledAt = 0)
);`;
}
// console.time('all vulns native query');
let vulnerabilityNativeQueryResult = await sails.sendNativeQuery(nativeQueryToFindAllVulnerabilityIdsWithSeverity);
// console.timeEnd('all vulns native query');
let vulnerabilityIdsWithSeverity = vulnerabilityNativeQueryResult.rows;
// Sort the vulnerabilities by severity, and add the counts to the totalUniqueCounts dictionary.
let criticalSeverity = vulnerabilityIdsWithSeverity.filter((vuln)=>{
return vuln.severity >= 9;
});
let highSeverity = vulnerabilityIdsWithSeverity.filter((vuln)=>{
return vuln.severity <= 8.9 && vuln.severity >= 7.0;
});
let mediumSeverity = vulnerabilityIdsWithSeverity.filter((vuln)=>{
return vuln.severity <= 6.9 && vuln.severity >= 4.0;
});
let lowSeverity = vulnerabilityIdsWithSeverity.filter((vuln)=>{
return vuln.severity >= 0 && vuln.severity <= 3.9;
});
let totalUniqueCounts = {
low: lowSeverity.length,
medium: mediumSeverity.length,
high: highSeverity.length,
critical: criticalSeverity.length,
};
dataForGraphs.totalUniqueCounts = totalUniqueCounts;
// Now build native SQL Queries using the IDs of vulnerabilities to find vulnerabilityInstall records for each severity.
let lowVulnerabilityInstallNativeQuery;
let mediumVulnerabilityInstallNativeQuery;
let highVulnerabilityInstallNativeQuery;
let criticalVulnerabilityInstallNativeQuery;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
// If this app is configured to use a Postgres datastore, we'll need to put double quotes around the uninstalledAt column name.
lowVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN (${_.pluck(lowSeverity,'id').join(',')});`;
mediumVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN (${_.pluck(mediumSeverity,'id').join(',')})`;
highVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN (${_.pluck(highSeverity,'id').join(',')})`;
criticalVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN (${_.pluck(criticalSeverity,'id').join(',')})`;
} else if(sails.config.datastores.default.adapter === 'sails-mysql') {
lowVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN (${_.pluck(lowSeverity,'id').join(',')})`;
mediumVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN (${_.pluck(mediumSeverity,'id').join(',')})`;
highVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN (${_.pluck(highSeverity,'id').join(',')})`;
criticalVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN (${_.pluck(criticalSeverity,'id').join(',')})`;
}
// console.time(`native queries to get total counts`);
// Now send some queries.
let criticalVulnInstallsResult = await sails.sendNativeQuery(criticalVulnerabilityInstallNativeQuery);
let totalInstallsWithCricitalVulns = criticalVulnInstallsResult.rows;
let highVulnInstallsResult = await sails.sendNativeQuery(highVulnerabilityInstallNativeQuery);
let totalInstallsWithHighVulns = highVulnInstallsResult.rows;
let mediumVulnInstallsResult = await sails.sendNativeQuery(mediumVulnerabilityInstallNativeQuery);
let totalInstallsWithMediumVulns = mediumVulnInstallsResult.rows;
let lowVulnInstallsResult = await sails.sendNativeQuery(lowVulnerabilityInstallNativeQuery);
let totalInstallsWithLowVulns = lowVulnInstallsResult.rows;
// console.timeEnd(`native queries to get total counts`);
let totalNumberOfVulns = {
low: totalInstallsWithLowVulns.length,
medium: totalInstallsWithMediumVulns.length,
high: totalInstallsWithHighVulns.length,
critical: totalInstallsWithCricitalVulns.length
};
dataForGraphs.totalNumberOfVulns = totalNumberOfVulns;
// ╔╦╗╦ ╦╔═╗ ╦═╗╦╔═╗╦╔═╦╔═╗╔═╗╔╦╗ ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦═╗╦╔═╗╦ ╦╔╦╗ ╔╗╔╔═╗╦ ╦
// ║ ╠═╣║╣ ╠╦╝║╚═╗╠╩╗║║╣ ╚═╗ ║ ╠═╣║ ║╚═╗ ║ ╚═╗ ╠╦╝║║ ╦╠═╣ ║ ║║║║ ║║║║
// ╩ ╩ ╩╚═╝ ╩╚═╩╚═╝╩ ╩╩╚═╝╚═╝ ╩ ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╩╚═╩╚═╝╩ ╩ ╩ ╝╚╝╚═╝╚╩╝
let nativeQueryToFindTopTenMostVulnerableHosts;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
nativeQueryToFindTopTenMostVulnerableHosts = `
WITH "installAggregates" AS (
SELECT
vulnerabilityinstall.vulnerability AS "vulnerabilityId",
COUNT(DISTINCT CASE
WHEN vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0
THEN vulnerabilityinstall.host END
) AS "currentAffectedHostCount",
COUNT(DISTINCT vulnerabilityinstall.host) AS "totalAffectedHostCount"
FROM vulnerabilityinstall
GROUP BY vulnerabilityinstall.vulnerability
),
"riskCalculation" AS (
SELECT
vulnerability.id AS "vulnerabilityId",
"installAggregates"."currentAffectedHostCount",
"installAggregates"."totalAffectedHostCount",
(
vulnerability.severity *
CASE
WHEN vulnerability."hasKnownExploit" THEN 2.0
WHEN vulnerability."probabilityOfExploit" > 0.5 THEN 1.5
ELSE 1.0
END
) AS "threatScore",
LN(1 + COALESCE("installAggregates"."currentAffectedHostCount", 0)) AS "impactScore"
FROM vulnerability
LEFT JOIN "installAggregates"
ON "installAggregates"."vulnerabilityId" = vulnerability.id
),
"normalizedRisk" AS (
SELECT
"vulnerabilityId",
("threatScore" * "impactScore") AS "rawRiskScore",
MAX("threatScore" * "impactScore") OVER () AS "maxRawRisk"
FROM "riskCalculation"
),
"vulnerabilityPps" AS (
SELECT
"vulnerabilityId",
CASE
WHEN "maxRawRisk" > 0
THEN ("rawRiskScore" / "maxRawRisk" * 9.9) + 0.1
ELSE 0.1
END AS "vulnerabilityPps"
FROM "normalizedRisk"
),
"hostVulnerabilitySet" AS (
SELECT DISTINCT
vulnerabilityinstall.host AS "hostId",
vulnerability.id AS "vulnerabilityId",
vulnerability."hasKnownExploit" AS "hasKnownExploit",
"vulnerabilityPps"."vulnerabilityPps" AS "vulnerabilityPps"
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability.id = vulnerabilityinstall.vulnerability
JOIN "vulnerabilityPps"
ON "vulnerabilityPps"."vulnerabilityId" = vulnerability.id
WHERE vulnerabilityinstall."uninstalledAt" IS NULL
OR vulnerabilityinstall."uninstalledAt" = 0
),
"hostPps" AS (
SELECT
host."displayName",
host."fleetApid",
COUNT(DISTINCT "hostVulnerabilitySet"."vulnerabilityId") AS "vulnerabilityCount",
COUNT(DISTINCT "hostVulnerabilitySet"."vulnerabilityId") FILTER (WHERE "hostVulnerabilitySet"."hasKnownExploit") AS "kevCount",
MAX("hostVulnerabilitySet"."vulnerabilityPps") AS "maxVulnerabilityPps",
(
MAX("hostVulnerabilitySet"."vulnerabilityPps")
* (1 + LN(1 + COUNT(DISTINCT "hostVulnerabilitySet"."vulnerabilityId")) * 0.15)
)::numeric(12,4) AS "hostPpsNumeric"
FROM "hostVulnerabilitySet"
JOIN host ON host.id = "hostVulnerabilitySet"."hostId"
GROUP BY host."displayName", host."fleetApid"
),
"hostPpsNormalized" AS (
SELECT
"hostPps"."displayName",
"hostPps"."fleetApid",
"hostPps"."vulnerabilityCount",
"hostPps"."kevCount",
"hostPps"."maxVulnerabilityPps",
"hostPps"."hostPpsNumeric",
MAX("hostPps"."hostPpsNumeric") OVER () AS "maxHostPps"
FROM "hostPps"
)
SELECT
"hostPpsNormalized"."displayName",
"hostPpsNormalized"."fleetApid",
"hostPpsNormalized"."vulnerabilityCount",
"hostPpsNormalized"."kevCount",
ROUND("hostPpsNormalized"."maxVulnerabilityPps"::numeric, 2) AS "worstVulnerabilityPps",
CASE
WHEN "hostPpsNormalized"."maxHostPps" > 0
THEN ROUND( ( "hostPpsNormalized"."hostPpsNumeric" / "hostPpsNormalized"."maxHostPps" ) * 9 + 1, 2)
ELSE 1.00
END AS "hostPps"
FROM "hostPpsNormalized"
ORDER BY "hostPps" DESC, "hostPpsNormalized"."displayName" ASC
LIMIT 10;`;
} else {
nativeQueryToFindTopTenMostVulnerableHosts = `
WITH installAggregates AS (
SELECT
vi.vulnerability AS vulnerabilityId,
COUNT(DISTINCT IF(vi.uninstalledAt IS NULL OR vi.uninstalledAt = 0, vi.host, NULL)) AS currentAffectedHostCount,
COUNT(DISTINCT vi.host) AS totalAffectedHostCount
FROM vulnerabilityinstall vi
GROUP BY vi.vulnerability
),
riskCalculation AS (
SELECT
v.id AS vulnerabilityId,
ia.currentAffectedHostCount,
ia.totalAffectedHostCount,
(
v.severity *
CASE
WHEN v.hasKnownExploit THEN 2.0
WHEN v.probabilityOfExploit > 0.5 THEN 1.5
ELSE 1.0
END
) AS threatScore,
LN(1 + COALESCE(ia.currentAffectedHostCount, 0)) AS impactScore
FROM vulnerability v
LEFT JOIN installAggregates ia ON ia.vulnerabilityId = v.id
),
normalizedRisk AS (
SELECT
vulnerabilityId,
(threatScore * impactScore) AS rawRiskScore,
MAX(threatScore * impactScore) OVER () AS maxRawRisk
FROM riskCalculation
),
vulnerabilityPps AS (
SELECT
vulnerabilityId,
CASE
WHEN maxRawRisk > 0
THEN (rawRiskScore / maxRawRisk * 9.9) + 0.1
ELSE 0.1
END AS vulnerabilityPps
FROM normalizedRisk
),
hostVulnerabilitySet AS (
SELECT DISTINCT
vi.host AS hostId,
v.id AS vulnerabilityId,
v.hasKnownExploit AS hasKnownExploit,
vp.vulnerabilityPps AS vulnerabilityPps
FROM vulnerabilityinstall vi
JOIN vulnerability v ON v.id = vi.vulnerability
JOIN vulnerabilityPps vp ON vp.vulnerabilityId = v.id
WHERE vi.uninstalledAt IS NULL OR vi.uninstalledAt = 0
),
hostPps AS (
SELECT
h.displayName,
h.fleetApid,
COUNT(DISTINCT hvs.vulnerabilityId) AS vulnerabilityCount,
COUNT(DISTINCT IF(hvs.hasKnownExploit, hvs.vulnerabilityId, NULL)) AS kevCount,
MAX(hvs.vulnerabilityPps) AS maxVulnerabilityPps,
CAST(
MAX(hvs.vulnerabilityPps) * (1 + LN(1 + COUNT(DISTINCT hvs.vulnerabilityId)) * 0.15)
AS DECIMAL(12,4)
) AS hostPpsNumeric
FROM hostVulnerabilitySet hvs
JOIN host h ON h.id = hvs.hostId
GROUP BY h.displayName, h.fleetApid
),
hostPpsNormalized AS (
SELECT
hp.displayName,
hp.fleetApid,
hp.vulnerabilityCount,
hp.kevCount,
hp.maxVulnerabilityPps,
hp.hostPpsNumeric,
MAX(hp.hostPpsNumeric) OVER () AS maxHostPps
FROM hostPps hp
)
SELECT
displayName,
fleetApid,
vulnerabilityCount,
kevCount,
ROUND(maxVulnerabilityPps, 2) AS worstVulnerabilityPps,
CASE
WHEN maxHostPps > 0
THEN ROUND(((hostPpsNumeric / maxHostPps) * 9) + 1, 2)
ELSE 1.00
END AS hostPps
FROM hostPpsNormalized
ORDER BY hostPps DESC, displayName ASC
LIMIT 10;`;
}
// console.time(`native query to find top 10 most vulnerable hosts`);
let topTenMostVulnerableHosts = await sails.sendNativeQuery(nativeQueryToFindTopTenMostVulnerableHosts);
// console.timeEnd(`native query to find top 10 most vulnerable hosts`);
// console.log(topTenMostVulnerableHosts.rows);
let mostVulnerableHosts = topTenMostVulnerableHosts.rows.map((host)=>{
return {
displayName: host.displayName,
fleetUrl: sails.config.custom.fleetBaseUrl + `/hosts/${host.fleetApid}`,
numberOfCves: host.vulnerabilityCount,
pps: host.hostPps,
};
});
dataForGraphs.mostVulnerableHosts = mostVulnerableHosts;
// ╔╦╗╦ ╦╔═╗ ╦ ╦╔═╗╦ ╦╔═╗╦ ╔═╗╦ ╦╔═╗╔═╗╔═╗╔═╗╔╦╗╔═╗ ╦╔╗╔ ╔═╗╔═╗╔═╗╔╦╗╦ ╦╔═╗╦═╗╔═╗
// ║ ╠═╣║╣ ║ ║╚═╗║ ║╠═╣║ ╚═╗║ ║╚═╗╠═╝║╣ ║ ║ ╚═╗ ║║║║ ╚═╗║ ║╠╣ ║ ║║║╠═╣╠╦╝║╣
// ╩ ╩ ╩╚═╝ ╚═╝╚═╝╚═╝╩ ╩╩═╝ ╚═╝╚═╝╚═╝╩ ╚═╝╚═╝ ╩ ╚═╝ ╩╝╚╝ ╚═╝╚═╝╚ ╩ ╚╩╝╩ ╩╩╚═╚═╝
let nativeQueryToFindTopTenMostVulnerableSoftwareItems;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
nativeQueryToFindTopTenMostVulnerableSoftwareItems = `
SELECT
vi."softwareName",
vi."versionName",
MIN(vi."fleetApid") AS "fleetApid",
COUNT(DISTINCT v.id) AS "numberOfVulns"
FROM vulnerabilityinstall vi
JOIN vulnerability v
ON vi.vulnerability = v.id
WHERE COALESCE(vi."uninstalledAt", 0) = 0
GROUP BY
vi."softwareName",
vi."versionName"
ORDER BY
"numberOfVulns" DESC
LIMIT 10;`;
} else {
nativeQueryToFindTopTenMostVulnerableSoftwareItems = `
SELECT
vi.softwareName,
vi.versionName,
MIN(vi.fleetApid) AS fleetApid,
COUNT(DISTINCT v.id) AS numberOfVulns
FROM vulnerabilityinstall vi
JOIN vulnerability v
ON vi.vulnerability = v.id
WHERE vi.uninstalledAt IS NULL OR vi.uninstalledAt = 0
GROUP BY
vi.softwareName,
vi.versionName
ORDER BY
numberOfVulns DESC
LIMIT 10;`;
}
// console.time(`top ten most vulenerable software query`);
let topVulnerableSoftwareResult = await sails.sendNativeQuery(nativeQueryToFindTopTenMostVulnerableSoftwareItems);
// console.timeEnd(`top ten most vulenerable software query`);
let topTenMostVulnerableSoftwareItems = topVulnerableSoftwareResult.rows.map((software)=>{
return {
softwareNameAndVersion: `${software.softwareName} - ${software.versionName}`,
fleetUrl: sails.config.custom.fleetBaseUrl + `/software/versions/${software.fleetApid}`,
numberOfVulns: software.numberOfVulns,
};
});
dataForGraphs.mostVulnerableSoftware = topTenMostVulnerableSoftwareItems;
// ╔═╗╦═╗╦╔╦╗╦╔═╗╔═╗╦ ╦ ╦ ╦ ╦═╗╔═╗╦═╗╔═╗ ╔═╗╔═╗╔═╗╔╦╗╦ ╦╔═╗╦═╗╔═╗
// ║ ╠╦╝║ ║ ║║ ╠═╣║ ║ ╚╦╝ ╠╦╝╠═╣╠╦╝║╣ ╚═╗║ ║╠╣ ║ ║║║╠═╣╠╦╝║╣
// ╚═╝╩╚═╩ ╩ ╩╚═╝╩ ╩╩═╝╩═╝╩ ╩╚═╩ ╩╩╚═╚═╝ ╚═╝╚═╝╚ ╩ ╚╩╝╩ ╩╩╚═╚═╝
// Software that is installed on <5 hosts with critical vulnerabilities.
let queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
SELECT
vi."softwareName",
STRING_AGG(DISTINCT h."displayName", ', ' ORDER BY h."displayName") AS "hostNames",
STRING_AGG(DISTINCT v."cveId", ', ' ORDER BY v."cveId") AS cves,
STRING_AGG(DISTINCT v."cveDescription", '; ' ORDER BY v."cveDescription") AS descriptions,
COUNT(DISTINCT vi.host) AS host_install_count
FROM vulnerabilityinstall vi
JOIN vulnerability v ON vi.vulnerability = v.id
JOIN host h ON vi.host = h.id
WHERE
(vi."uninstalledAt" IS NULL OR vi."uninstalledAt" = 0)
AND v.severity >= 9.0
AND vi."softwareName" !~* '^(Python|perl|lib)'
GROUP BY
vi."softwareName"
HAVING
COUNT(DISTINCT vi.host) < 3
ORDER BY
host_install_count ASC
LIMIT 10;`;
// queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
// WITH "activeInstalls" AS (
// SELECT
// vulnerabilityinstall.host,
// vulnerabilityinstall."softwareName",
// vulnerabilityinstall."versionName",
// vulnerabilityinstall."fleetApid",
// vulnerabilityinstall."softwareName" AS "softwareNameAndVersion"
// FROM vulnerabilityinstall
// WHERE vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0
// ),
// "softwareHostCounts" AS (
// SELECT
// "activeInstalls"."softwareNameAndVersion",
// COUNT(DISTINCT "activeInstalls".host) AS "hostInstallCount",
// STRING_AGG(DISTINCT host."displayName", ', ' ORDER BY host."displayName") AS "hostNames",
// STRING_AGG(
// DISTINCT "activeInstalls"."fleetApid"::text,
// ', ' ORDER BY "activeInstalls"."fleetApid"::text
// ) AS "fleetApid"
// FROM "activeInstalls"
// JOIN host ON host.id = "activeInstalls".host
// GROUP BY "activeInstalls"."softwareNameAndVersion"
// ),
// "criticalVulnerabilityAgg" AS (
// SELECT
// "activeInstalls"."softwareNameAndVersion",
// COUNT(DISTINCT vulnerability.id) AS "vulnerabilityCount",
// STRING_AGG(DISTINCT vulnerability."cveId", ', ' ORDER BY vulnerability."cveId") AS "cveIds"
// FROM "activeInstalls"
// JOIN vulnerabilityinstall ON
// vulnerabilityinstall.host = "activeInstalls".host
// AND vulnerabilityinstall."softwareName" = "activeInstalls"."softwareName"
// AND COALESCE(vulnerabilityinstall."versionName",'') = COALESCE("activeInstalls"."versionName",'')
// AND (vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0)
// JOIN vulnerability ON vulnerability.id = vulnerabilityinstall.vulnerability
// WHERE vulnerability.severity >= 9.0
// GROUP BY "activeInstalls"."softwareNameAndVersion"
// )
// SELECT
// "softwareHostCounts"."softwareNameAndVersion",
// "softwareHostCounts"."hostInstallCount",
// "criticalVulnerabilityAgg"."vulnerabilityCount",
// "criticalVulnerabilityAgg"."cveIds",
// "softwareHostCounts"."hostNames",
// "softwareHostCounts"."fleetApid"
// FROM "softwareHostCounts"
// JOIN "criticalVulnerabilityAgg"
// ON "criticalVulnerabilityAgg"."softwareNameAndVersion" = "softwareHostCounts"."softwareNameAndVersion"
// WHERE "softwareHostCounts"."hostInstallCount" < 5
// ORDER BY
// "criticalVulnerabilityAgg"."vulnerabilityCount" DESC,
// "softwareHostCounts"."hostInstallCount" ASC,
// "softwareHostCounts"."softwareNameAndVersion" ASC
// LIMIT 10;`;
} else {
queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
SELECT
vi.softwareName,
GROUP_CONCAT(DISTINCT h.displayName SEPARATOR ', ') AS hostNames,
GROUP_CONCAT(DISTINCT v.cveId SEPARATOR ', ') AS cves,
GROUP_CONCAT(DISTINCT v.cveDescription SEPARATOR '; ') AS descriptions,
COUNT(DISTINCT vi.host) AS host_install_count
FROM
vulnerabilityinstall vi
JOIN
vulnerability v ON vi.vulnerability = v.id
JOIN
host h ON vi.host = h.id
WHERE
-- Consider only currently installed software
(vi.uninstalledAt IS NULL OR vi.uninstalledAt = 0)
-- Filter for software associated with 'Critical' vulnerabilities (CVSS 8.0-10.0)
AND v.severity >= 8.0
-- Exclude software names starting with 'Python' or 'pert'
AND vi.softwareName NOT REGEXP '^(Python|perl|lib)'
GROUP BY
vi.softwareName
HAVING
host_install_count < 3
ORDER BY
-- Order by the number of hosts the software is installed on, ascending,
-- to show the rarest software first.
host_install_count ASC
LIMIT 10`;
// queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
// WITH activeInstalls AS (
// SELECT
// vulnerabilityinstall.host,
// vulnerabilityinstall.softwareName,
// vulnerabilityinstall.versionName,
// vulnerabilityinstall.fleetApid,
// CONCAT(vulnerabilityinstall.softwareName AS softwareNameAndVersion
// FROM vulnerabilityinstall
// WHERE vulnerabilityinstall.uninstalledAt IS NULL OR vulnerabilityinstall.uninstalledAt = 0
// ),
// softwareHostCounts AS (
// SELECT
// activeInstalls.softwareNameAndVersion,
// COUNT(DISTINCT activeInstalls.host) AS hostInstallCount,
// GROUP_CONCAT(DISTINCT host.displayName ORDER BY host.displayName SEPARATOR ', ') AS hostNames,
// GROUP_CONCAT(DISTINCT CAST(activeInstalls.fleetApid AS CHAR) ORDER BY CAST(activeInstalls.fleetApid AS CHAR) SEPARATOR ', ') AS fleetApid
// FROM activeInstalls
// JOIN host ON host.id = activeInstalls.host
// GROUP BY activeInstalls.softwareNameAndVersion
// ),
// criticalVulnerabilityAgg AS (
// SELECT
// activeInstalls.softwareNameAndVersion,
// COUNT(DISTINCT vulnerability.id) AS vulnerabilityCount,
// GROUP_CONCAT(DISTINCT vulnerability.cveId ORDER BY vulnerability.cveId SEPARATOR ', ') AS cveIds
// FROM activeInstalls
// JOIN vulnerabilityinstall ON
// vulnerabilityinstall.host = activeInstalls.host
// AND vulnerabilityinstall.softwareName = activeInstalls.softwareName
// AND COALESCE(vulnerabilityinstall.versionName,'') = COALESCE(activeInstalls.versionName,'')
// AND (vulnerabilityinstall.uninstalledAt IS NULL OR vulnerabilityinstall.uninstalledAt = 0)
// JOIN vulnerability ON vulnerability.id = vulnerabilityinstall.vulnerability
// WHERE vulnerability.severity >= 9.0
// GROUP BY activeInstalls.softwareNameAndVersion
// )
// SELECT
// softwareHostCounts.softwareNameAndVersion,
// softwareHostCounts.hostInstallCount,
// criticalVulnerabilityAgg.vulnerabilityCount,
// criticalVulnerabilityAgg.cveIds,
// softwareHostCounts.hostNames,
// softwareHostCounts.fleetApid
// FROM softwareHostCounts
// JOIN criticalVulnerabilityAgg
// ON criticalVulnerabilityAgg.softwareNameAndVersion = softwareHostCounts.softwareNameAndVersion
// WHERE softwareHostCounts.hostInstallCount < 5
// ORDER BY
// criticalVulnerabilityAgg.vulnerabilityCount DESC,
// softwareHostCounts.hostInstallCount ASC,
// softwareHostCounts.softwareNameAndVersion ASC
// LIMIT 10;`;
}
// console.time('critical unique software query');
let topUniqueCriticalVulnsResult = await sails.sendNativeQuery(queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities);
// console.timeEnd('critical unique software query');
// console.log(topUniqueCriticalVulnsResult);
let uniqueCriticalSoftware = topUniqueCriticalVulnsResult.rows.map((software)=>{
// Build an array of CVE objects, with each containing the CVE ID and a link to the Fleet page for the CVE.
let cves = software.cves.split(', ').map((cveId)=>{
return {
name: cveId,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/software/vulnerabilities/${cveId}`
};
});
return {
softwareNameAndVersion: software.softwareName,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/software/versions/${software.fleetApid}`,
numberOfVulns: cves.length,
cves,
affectedHosts: software.hostNames.split(', '),
};
});
dataForGraphs.uniqueCriticalSoftware = uniqueCriticalSoftware;
// console.log(uniqueCriticalSoftware);
//
// ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔╦╗╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔═╗
// ╠═╣║ ║╚═╗ ║ ╚═╗ ║║║║ ║ ╠═╣ ║║║║ ║╚═╗ ║ ║ ╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╝ ╚═╝╚═╝
let hostsWithMostVulnsQuery;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
hostsWithMostVulnsQuery = `
WITH "activeVulnerabilityInstalls" AS (
SELECT DISTINCT
vulnerabilityinstall.host,
vulnerabilityinstall.vulnerability
FROM vulnerabilityinstall
WHERE
vulnerabilityinstall."uninstalledAt" IS NULL
OR vulnerabilityinstall."uninstalledAt" = 0
),
"vulnerabilityCountsByHost" AS (
SELECT
activeVulnerabilityInstalls.host,
COUNT(DISTINCT activeVulnerabilityInstalls.vulnerability) AS "vulnerabilityCount",
STRING_AGG(DISTINCT vulnerability."cveId", ', ' ORDER BY vulnerability."cveId") AS "cveIds"
FROM "activeVulnerabilityInstalls" AS activeVulnerabilityInstalls
JOIN vulnerability
ON vulnerability.id = activeVulnerabilityInstalls.vulnerability
GROUP BY
activeVulnerabilityInstalls.host
)
SELECT
host."displayName" AS "displayName",
host."fleetApid" AS "fleetApid",
vulnerabilityCountsByHost."vulnerabilityCount",
vulnerabilityCountsByHost."cveIds"
FROM "vulnerabilityCountsByHost" AS vulnerabilityCountsByHost
JOIN host
ON host.id = vulnerabilityCountsByHost.host
ORDER BY
vulnerabilityCountsByHost."vulnerabilityCount" DESC,
host."displayName" ASC
LIMIT 10;`;
} else {
hostsWithMostVulnsQuery = `
WITH activeVulnerabilityInstalls AS (
SELECT DISTINCT
vulnerabilityinstall.host,
vulnerabilityinstall.vulnerability
FROM vulnerabilityinstall
WHERE
vulnerabilityinstall.uninstalledAt IS NULL
OR vulnerabilityinstall.uninstalledAt = 0
),
vulnerabilityCountsByHost AS (
SELECT
activeVulnerabilityInstalls.host,
COUNT(DISTINCT activeVulnerabilityInstalls.vulnerability) AS vulnerabilityCount,
GROUP_CONCAT(
DISTINCT vulnerability.cveId
ORDER BY vulnerability.cveId
SEPARATOR ', '
) AS cveIds
FROM activeVulnerabilityInstalls
JOIN vulnerability
ON vulnerability.id = activeVulnerabilityInstalls.vulnerability
GROUP BY activeVulnerabilityInstalls.host
)
SELECT
host.displayName AS displayName,
host.fleetApid AS fleetApid,
vulnerabilityCountsByHost.vulnerabilityCount,
vulnerabilityCountsByHost.cveIds
FROM vulnerabilityCountsByHost
JOIN host
ON host.id = vulnerabilityCountsByHost.host
ORDER BY
vulnerabilityCountsByHost.vulnerabilityCount DESC,
host.displayName ASC
LIMIT 10;`;
}
// console.time('hosts with most vulnerabilities query');
let hostWithMostVulnsResult = await sails.sendNativeQuery(hostsWithMostVulnsQuery);
// console.timeEnd('hosts with most vulnerabilities query');
let hostsWithMostVulns = hostWithMostVulnsResult.rows.map((host)=>{
let cves = host.cveIds.split(', ').map((cveId)=>{
return {
name: cveId,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/software/vulnerabilities/${cveId}`
};
});
return {
displayName: host.displayName,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/hosts/${host.fleetApid}`,
numberOfVulns: host.vulnerabilityCount,
cves,
};
});
dataForGraphs.hostsWithMostVulns = hostsWithMostVulns;
//
// ╔═╗╦ ╦╔═╗ ╔═╗╔═╗╔╦╗╦╦ ╦╦╔╦╗╦ ╦ ╔╦╗╦═╗╔═╗╔╗╔╔╦╗╔═╗
// ║ ╚╗╔╝║╣ ╠═╣║ ║ ║╚╗╔╝║ ║ ╚╦╝ ║ ╠╦╝║╣ ║║║ ║║╚═╗
// ╚═╝ ╚╝ ╚═╝ ╩ ╩╚═╝ ╩ ╩ ╚╝ ╩ ╩ ╩ ╩ ╩╚═╚═╝╝╚╝═╩╝╚═╝
let queryToFindRemediationVeloticy;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
queryToFindRemediationVeloticy = `
WITH "params" AS (
SELECT
(3::bigint * 24 * 60 * 60 * 1000) AS "graceMs"
),
"monthAnchors" AS (
SELECT date_trunc('month', (now() AT TIME ZONE 'UTC'))::timestamptz AS "thisMonthStartTs"
),
"monthBoundaries" AS (
SELECT
gs AS "monthStartTs",
LEAD(gs) OVER (ORDER BY gs) AS "monthEndTs"
FROM generate_series(
(SELECT "thisMonthStartTs" - INTERVAL '4 months' FROM "monthAnchors"),
(SELECT "thisMonthStartTs" FROM "monthAnchors"),
INTERVAL '1 month'
) AS gs
),
"months" AS (
SELECT
(EXTRACT(EPOCH FROM "monthStartTs") * 1000)::bigint AS "monthStartMs",
(EXTRACT(EPOCH FROM "monthEndTs") * 1000)::bigint AS "monthEndMs"
FROM "monthBoundaries"
WHERE "monthEndTs" IS NOT NULL
),
"rowsWithLag" AS (
SELECT
vulnerabilityinstall.host,
vulnerabilityinstall."softwareName",
vulnerabilityinstall."versionName",
vulnerabilityinstall.vulnerability,
vulnerabilityinstall."createdAt"::bigint AS "createdAtMs",
vulnerabilityinstall."uninstalledAt"::bigint AS "uninstalledAtMs",
LAG(vulnerabilityinstall."uninstalledAt"::bigint) OVER (
PARTITION BY
vulnerabilityinstall.host,
vulnerabilityinstall."softwareName",
vulnerabilityinstall."versionName",
vulnerabilityinstall.vulnerability
ORDER BY vulnerabilityinstall."createdAt"::bigint
) AS "prevUninstalledMs"
FROM vulnerabilityinstall
),
"labeledEpisodes" AS (
SELECT
"rowsWithLag".*,
CASE
WHEN "rowsWithLag"."prevUninstalledMs" IS NULL THEN 1
WHEN "rowsWithLag"."createdAtMs" > "rowsWithLag"."prevUninstalledMs" + (SELECT "graceMs" FROM "params") THEN 1
ELSE 0
END AS "isNewEpisode"
FROM "rowsWithLag"
),
"episodeIndex" AS (
SELECT
host,
"softwareName",
"versionName",
vulnerability,
"createdAtMs",
"uninstalledAtMs",
SUM("isNewEpisode") OVER (
PARTITION BY host, "softwareName", "versionName", vulnerability
ORDER BY "createdAtMs"
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS "episodeId"
FROM "labeledEpisodes"
),
"episodes" AS (
SELECT
host,
"softwareName",
"versionName",
vulnerability,
MIN("createdAtMs") AS "episodeStartMs",
NULLIF(MAX(COALESCE("uninstalledAtMs", 0)), 0) AS "episodeEndMs"
FROM "episodeIndex"
GROUP BY host, "softwareName", "versionName", vulnerability, "episodeId"
),
"newCvesByMonth" AS (
SELECT
"months"."monthStartMs",
COUNT(*) AS "newCves"
FROM "months"
JOIN "episodes"
ON "episodes"."episodeStartMs" >= "months"."monthStartMs"
AND "episodes"."episodeStartMs" < "months"."monthEndMs"
GROUP BY "months"."monthStartMs"
),
"remediatedCvesByMonth" AS (
SELECT
"months"."monthStartMs",
COUNT(*) AS "remediatedCves"
FROM "months"
JOIN "episodes"
ON "episodes"."episodeEndMs" IS NOT NULL
AND "episodes"."episodeEndMs" >= "months"."monthStartMs"
AND "episodes"."episodeEndMs" < "months"."monthEndMs"
GROUP BY "months"."monthStartMs"
),
"activeCveCountByMonth" AS (
SELECT
"months"."monthStartMs",
COUNT(*) AS "activeCveCount"
FROM "months"
JOIN "episodes"
ON "episodes"."episodeStartMs" < "months"."monthEndMs"
AND (
"episodes"."episodeEndMs" IS NULL
OR "episodes"."episodeEndMs" >= "months"."monthEndMs"
)
GROUP BY "months"."monthStartMs"
)
SELECT
"months"."monthStartMs",
COALESCE("newCvesByMonth"."newCves", 0) AS "newCves",
COALESCE("remediatedCvesByMonth"."remediatedCves", 0) AS "remediatedCves",
COALESCE("activeCveCountByMonth"."activeCveCount", 0) AS "activeCveCount"
FROM "months"
LEFT JOIN "newCvesByMonth"
ON "newCvesByMonth"."monthStartMs" = "months"."monthStartMs"
LEFT JOIN "remediatedCvesByMonth"
ON "remediatedCvesByMonth"."monthStartMs" = "months"."monthStartMs"
LEFT JOIN "activeCveCountByMonth"
ON "activeCveCountByMonth"."monthStartMs" = "months"."monthStartMs"
ORDER BY "months"."monthStartMs" ASC;`;
} else {
queryToFindRemediationVeloticy = `
WITH
params AS (
SELECT CAST(3*24*60*60*1000 AS SIGNED) AS graceMs
),
monthAnchors AS (
SELECT TIMESTAMP(DATE_FORMAT(UTC_TIMESTAMP(), '%Y-%m-01 00:00:00')) AS thisMonthStartTs
),
monthBoundaries AS (
WITH RECURSIVE m AS (
SELECT
0 AS n,
DATE_SUB((SELECT thisMonthStartTs FROM monthAnchors), INTERVAL 4 MONTH) AS monthStartTs
UNION ALL
SELECT
n + 1,
DATE_ADD(monthStartTs, INTERVAL 1 MONTH)
FROM m
WHERE n < 3
)
SELECT monthStartTs FROM m
),
months AS (
SELECT
CAST(UNIX_TIMESTAMP(monthStartTs) * 1000 AS SIGNED) AS monthStartMs,
CAST(UNIX_TIMESTAMP(DATE_ADD(monthStartTs, INTERVAL 1 MONTH)) * 1000 AS SIGNED) AS monthEndMs
FROM monthBoundaries
),
rowsWithLag AS (
SELECT
vulnerabilityinstall.host,
vulnerabilityinstall.softwareName,
vulnerabilityinstall.versionName,
vulnerabilityinstall.vulnerability,
CAST(vulnerabilityinstall.createdAt AS SIGNED) AS createdAtMs,
CAST(vulnerabilityinstall.uninstalledAt AS SIGNED) AS uninstalledAtMs,
LAG(CAST(vulnerabilityinstall.uninstalledAt AS SIGNED)) OVER (
PARTITION BY
vulnerabilityinstall.host,
vulnerabilityinstall.softwareName,
vulnerabilityinstall.versionName,
vulnerabilityinstall.vulnerability
ORDER BY CAST(vulnerabilityinstall.createdAt AS SIGNED)
) AS prevUninstalledMs
FROM vulnerabilityinstall
),
labeledEpisodes AS (
SELECT
rowsWithLag.*,
CASE
WHEN rowsWithLag.prevUninstalledMs IS NULL THEN 1
WHEN rowsWithLag.createdAtMs > rowsWithLag.prevUninstalledMs + (SELECT graceMs FROM params) THEN 1
ELSE 0
END AS isNewEpisode
FROM rowsWithLag
),
episodeIndex AS (
SELECT
host,
softwareName,
versionName,
vulnerability,
createdAtMs,
uninstalledAtMs,
SUM(isNewEpisode) OVER (
PARTITION BY host, softwareName, versionName, vulnerability
ORDER BY createdAtMs
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS episodeId
FROM labeledEpisodes
),
episodes AS (
SELECT
host,
softwareName,
versionName,
vulnerability,
MIN(createdAtMs) AS episodeStartMs,
NULLIF(MAX(COALESCE(uninstalledAtMs, 0)), 0) AS episodeEndMs
FROM episodeIndex
GROUP BY host, softwareName, versionName, vulnerability, episodeId
),
newCvesByMonth AS (
SELECT
months.monthStartMs,
COUNT(*) AS newCves
FROM months
JOIN episodes
ON episodes.episodeStartMs >= months.monthStartMs
AND episodes.episodeStartMs < months.monthEndMs
GROUP BY months.monthStartMs
),
remediatedCvesByMonth AS (
SELECT
months.monthStartMs,
COUNT(*) AS remediatedCves
FROM months
JOIN episodes
ON episodes.episodeEndMs IS NOT NULL
AND episodes.episodeEndMs >= months.monthStartMs
AND episodes.episodeEndMs < months.monthEndMs
GROUP BY months.monthStartMs
),
activeCveCountByMonth AS (
SELECT
months.monthStartMs,
COUNT(*) AS activeCveCount
FROM months
JOIN episodes
ON episodes.episodeStartMs < months.monthEndMs
AND (episodes.episodeEndMs IS NULL OR episodes.episodeEndMs >= months.monthEndMs)
GROUP BY months.monthStartMs
)
SELECT
months.monthStartMs,
COALESCE(newCvesByMonth.newCves, 0) AS newCves,
COALESCE(remediatedCvesByMonth.remediatedCves, 0) AS remediatedCves,
COALESCE(activeCveCountByMonth.activeCveCount, 0) AS activeCveCount
FROM months
LEFT JOIN newCvesByMonth
ON newCvesByMonth.monthStartMs = months.monthStartMs
LEFT JOIN remediatedCvesByMonth
ON remediatedCvesByMonth.monthStartMs = months.monthStartMs
LEFT JOIN activeCveCountByMonth
ON activeCveCountByMonth.monthStartMs = months.monthStartMs
ORDER BY months.monthStartMs ASC;`;
}
// console.time('remediation velocity query');
let remediationTrendResult = await sails.sendNativeQuery(queryToFindRemediationVeloticy);
// console.timeEnd('remediation velocity query');
let activityTrendsTimeline = remediationTrendResult.rows.map((month)=>{
return {
monthStartedAt: month.monthStartMs,
timelineLabel: new Date(Number(month.monthStartMs)).toLocaleString('en-US', { month: 'short', year: 'numeric' }),
newCves: month.newCves,
remediatedCves: month.remediatedCves,
totalNumberOfCves: month.activeCveCount,
};
});
dataForGraphs.activityTrendsTimeline = activityTrendsTimeline;
//
// ╔═╗╦ ╦╔═╗ ╦═╗╔═╗╔╦╗╔═╗╔╦╗╦╔═╗╔╦╗╦╔═╗╔╗╔ ╔═╗╦ ╦╔╦╗╔╦╗╔═╗╦═╗╦ ╦
// ║ ╚╗╔╝║╣ ╠╦╝║╣ ║║║║╣ ║║║╠═╣ ║ ║║ ║║║║ ╚═╗║ ║║║║║║║╠═╣╠╦╝╚╦╝
// ╚═╝ ╚╝ ╚═╝ ╩╚═╚═╝╩ ╩╚═╝═╩╝╩╩ ╩ ╩ ╩╚═╝╝╚╝ ╚═╝╚═╝╩ ╩╩ ╩╩ ╩╩╚═ ╩
let thirtyDaysInMs = (1000 * 60 * 60 * 24 * 30);
let ninetyDaysInMs = (1000 * 60 * 60 * 24 * 90);
let thirtyDaysAgoAt = Date.now() - thirtyDaysInMs;
let ninetyDaysAgoAt = Date.now() - ninetyDaysInMs;
// let numberOfNewCvesInThePastWeek = await Vulnerability.count({createdAt: {'>': oneWeekAgoAt}});
// console.log('numberOfNewCvesInThePastWeek:', numberOfNewCvesInThePastWeek);
let numberOfNewAndActiveVulnInstallsInThePastThirtyDays = await VulnerabilityInstall.count({installedAt: {'>': thirtyDaysAgoAt}, uninstalledAt: 0});
// console.log('numberOfNewAndActiveVulnInstallsInThePastWeek:', numberOfNewAndActiveVulnInstallsInThePastWeek);
// let numberOfNewCvesInThePastThirtyDays = await Vulnerability.count({createdAt: {'>': thirtyDaysAgoAt}});
let numberOfNewAndActiveVulnInstallsInThePastNinetyDays = await VulnerabilityInstall.count({installedAt: {'>': ninetyDaysAgoAt}, uninstalledAt: 0});
// console.log('numberOfNewCvesInThePastThirtyDays:', numberOfNewCvesInThePastThirtyDays):
// console.log('numberOfNewAndActiveVulnInstallsInThePastThirtyDays:', numberOfNewAndActiveVulnInstallsInThePastThirtyDays);
let remediationSummary = {
newCvesThirtyDays: numberOfNewAndActiveVulnInstallsInThePastThirtyDays,
newCvesNinetyDays: numberOfNewAndActiveVulnInstallsInThePastNinetyDays,
};
// Send native queries to get number of remediated CVEs
let nativeQueryToGetNumberOfRemediatedCves;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
nativeQueryToGetNumberOfRemediatedCves = `
WITH "timeBounds" AS (
SELECT
(EXTRACT(EPOCH FROM (now() AT TIME ZONE 'UTC')) * 1000)::bigint AS "nowMs",
(EXTRACT(EPOCH FROM ((now() AT TIME ZONE 'UTC') - INTERVAL '30 days')) * 1000)::bigint AS "thirtyDaysAgoMs",
(EXTRACT(EPOCH FROM ((now() AT TIME ZONE 'UTC') - INTERVAL '90 days')) * 1000)::bigint AS "ninetyDaysAgoMs"
),
"remediatedOnceLast90Days" AS (
SELECT
vulnerabilityinstall.id,
vulnerabilityinstall."uninstalledAt" AS "remediatedAtMs"
FROM vulnerabilityinstall
JOIN "timeBounds" ON TRUE
WHERE
vulnerabilityinstall."uninstalledAt" IS NOT NULL
AND vulnerabilityinstall."uninstalledAt" > 0
AND vulnerabilityinstall."uninstalledAt" >= "timeBounds"."ninetyDaysAgoMs"
AND vulnerabilityinstall."uninstalledAt" < "timeBounds"."nowMs"
AND NOT EXISTS (
SELECT 1
FROM vulnerabilityinstall AS vi_reinstall
WHERE
vi_reinstall.host = vulnerabilityinstall.host
AND vi_reinstall.vulnerability = vulnerabilityinstall.vulnerability
AND vi_reinstall."softwareName" = vulnerabilityinstall."softwareName"
AND COALESCE(vi_reinstall."versionName",'') = COALESCE(vulnerabilityinstall."versionName",'')
AND vi_reinstall."createdAt" > vulnerabilityinstall."uninstalledAt"
)
)
SELECT
COUNT(*) FILTER (WHERE "remediatedAtMs" >= "timeBounds"."thirtyDaysAgoMs") AS "remediatedCveCountLast30Days",
COUNT(*) AS "remediatedCveCountLast90Days"
FROM "remediatedOnceLast90Days"
CROSS JOIN "timeBounds";`;
} else {
nativeQueryToGetNumberOfRemediatedCves = `
WITH timeBounds AS (
SELECT
CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP()) * 1000 AS SIGNED) AS nowMs,
CAST(UNIX_TIMESTAMP(DATE_SUB(UTC_TIMESTAMP(), INTERVAL 7 DAY)) * 1000 AS SIGNED) AS thirtyDaysAgoMs,
CAST(UNIX_TIMESTAMP(DATE_SUB(UTC_TIMESTAMP(), INTERVAL 30 DAY)) * 1000 AS SIGNED) AS ninetyDaysAgoMs
),
remediatedOnceLast90Days AS (
SELECT
vulnerabilityinstall.id,
vulnerabilityinstall.uninstalledAt AS remediatedAtMs
FROM vulnerabilityinstall
JOIN timeBounds ON TRUE
WHERE
vulnerabilityinstall.uninstalledAt IS NOT NULL
AND vulnerabilityinstall.uninstalledAt > 0
AND vulnerabilityinstall.uninstalledAt >= timeBounds.ninetyDaysAgoMs
AND vulnerabilityinstall.uninstalledAt < timeBounds.nowMs
AND NOT EXISTS (
SELECT 1
FROM vulnerabilityinstall AS vi_reinstall
WHERE
vi_reinstall.host = vulnerabilityinstall.host
AND vi_reinstall.vulnerability = vulnerabilityinstall.vulnerability
AND vi_reinstall.softwareName = vulnerabilityinstall.softwareName
AND COALESCE(vi_reinstall.versionName,'') = COALESCE(vulnerabilityinstall.versionName,'')
AND vi_reinstall.createdAt > vulnerabilityinstall.uninstalledAt
)
)
SELECT
SUM(CASE WHEN remediatedAtMs >= timeBounds.thirtyDaysAgoMs THEN 1 ELSE 0 END) AS remediatedCveCountLast30Days,
COUNT(*) AS remediatedCveCountLast90Days
FROM remediatedOnceLast90Days
CROSS JOIN timeBounds;`;
}
// console.time('recent remediated cves query');
let remediatedCvesQueryResult = await sails.sendNativeQuery(nativeQueryToGetNumberOfRemediatedCves);
// console.timeEnd('recent remediated cves query');
remediationSummary.remediatedCvesThirtyDays = remediatedCvesQueryResult.rows[0].remediatedCveCountLast30Days ? remediatedCvesQueryResult.rows[0].remediatedCveCountLast30Days : 0;
remediationSummary.remediatedCvesNinetyDays = remediatedCvesQueryResult.rows[0].remediatedCveCountLast90Days ? remediatedCvesQueryResult.rows[0].remediatedCveCountLast90Days : 0;
dataForGraphs.remediationSummary = remediationSummary;
//
// ╔═╗╦ ╔╦╗╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗
// ║ ║║ ║║║╣ ╚═╗ ║ ║ ╚╗╔╝║╣ ╚═╗ ║║║║ ║ ╠═╣ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╚═╗
// ╚═╝╩═╝═╩╝╚═╝╚═╝ ╩ ╚═╝ ╚╝ ╚═╝╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╚═╝
let queryToFindOldestExploitableCves;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
queryToFindOldestExploitableCves = `
WITH oldestExploitable AS (
SELECT DISTINCT vulnerability."cveId", vulnerability."publishedAt"
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall.vulnerability = vulnerability.id
AND (vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0)
WHERE vulnerability."hasKnownExploit" = TRUE
)
SELECT "cveId"
FROM oldestExploitable
ORDER BY "publishedAt" ASC
LIMIT 5;`;
} else {
queryToFindOldestExploitableCves = `
WITH oldestExploitable AS (
SELECT DISTINCT
vulnerability.cveId,
vulnerability.publishedAt
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall.vulnerability = vulnerability.id
AND (vulnerabilityinstall.uninstalledAt IS NULL
OR vulnerabilityinstall.uninstalledAt = 0)
WHERE vulnerability.hasKnownExploit = TRUE
)
SELECT cveId
FROM oldestExploitable
ORDER BY publishedAt ASC
LIMIT 5;`;
}
// console.time('oldest exploitable cves query');
let oldestExploitableCvesResult = await sails.sendNativeQuery(queryToFindOldestExploitableCves);
// console.timeEnd('oldest exploitable cves query');
let oldestExploitableCves = oldestExploitableCvesResult.rows.map((cve)=>{
return {
cveId: cve.cveId,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/software/vulnerabilities/${cve.cveId}`,
yearPublished: cve.cveId.split('-')[1],
};
});
dataForGraphs.oldestExploitableCves = oldestExploitableCves;
//
// ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔═╗╦ ╔╦╗╔═╗╔═╗╔╦╗ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗╔╗ ╦ ╔═╗ ╔═╗╦ ╦╔═╗╔═╗
// ╠═╣║ ║╚═╗ ║ ╚═╗ ║║║║ ║ ╠═╣ ║ ║║ ║║║╣ ╚═╗ ║ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╠═╣╠╩╗║ ║╣ ║ ╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╚═╝╩═╝═╩╝╚═╝╚═╝ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╩ ╩╚═╝╩═╝╚═╝ ╚═╝ ╚╝ ╚═╝╚═╝
let queryToFindHostsWithOldestExploitableCves;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
queryToFindHostsWithOldestExploitableCves = `
WITH "hostOldestExploitable" AS (
SELECT
host.id AS "hostId",
host."displayName" AS "displayName",
host."fleetApid" AS "fleetApid",
vulnerability."cveId" AS "cveId",
vulnerability."publishedAt" AS "publishedAtMs",
vulnerabilityinstall."softwareName" AS "softwareName",
vulnerabilityinstall."versionName" AS "versionName"
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability.id = vulnerabilityinstall.vulnerability
AND vulnerability."hasKnownExploit" = TRUE
JOIN host
ON host.id = vulnerabilityinstall.host
WHERE
vulnerabilityinstall."uninstalledAt" IS NULL
OR vulnerabilityinstall."uninstalledAt" = 0
),
"rankedOldestPerHost" AS (
SELECT
"hostId",
"displayName",
"fleetApid",
"cveId",
"publishedAtMs",
"softwareName",
"versionName",
ROW_NUMBER() OVER (
PARTITION BY "hostId"
ORDER BY "publishedAtMs" ASC
) AS "rowNumber"
FROM "hostOldestExploitable"
)
SELECT
"displayName",
"fleetApid",
"cveId",
("softwareName" || ' ' || COALESCE("versionName", '')) AS "softwareNameAndVersion",
"publishedAtMs"
FROM "rankedOldestPerHost"
WHERE "rowNumber" = 1
ORDER BY "publishedAtMs" ASC
LIMIT 5;`;
} else {
queryToFindHostsWithOldestExploitableCves = `
WITH hostOldestExploitable AS (
SELECT
host.id AS hostId,
host.displayName AS displayName,
host.fleetApid AS fleetApid,
vulnerability.cveId AS cveId,
vulnerability.publishedAt AS publishedAtMs,
vulnerabilityinstall.softwareName AS softwareName,
vulnerabilityinstall.versionName AS versionName
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability.id = vulnerabilityinstall.vulnerability
AND vulnerability.hasKnownExploit = TRUE
JOIN host
ON host.id = vulnerabilityinstall.host
WHERE
vulnerabilityinstall.uninstalledAt IS NULL
OR vulnerabilityinstall.uninstalledAt = 0
),
rankedOldestPerHost AS (
SELECT
hostId,
displayName,
fleetApid,
cveId,
publishedAtMs,
softwareName,
versionName,
ROW_NUMBER() OVER (
PARTITION BY hostId
ORDER BY publishedAtMs ASC
) AS rowNumber
FROM hostOldestExploitable
)
SELECT
displayName,
fleetApid,
cveId,
CONCAT(softwareName, ' ', COALESCE(versionName, '')) AS softwareNameAndVersion,
publishedAtMs
FROM rankedOldestPerHost
WHERE rowNumber = 1
ORDER BY publishedAtMs ASC
LIMIT 5;`;
}
// console.time('oldest exploitable hosts query');
let oldestExploitableHostsResult = await sails.sendNativeQuery(queryToFindHostsWithOldestExploitableCves);
// console.timeEnd('oldest exploitable hosts query');
let oldestExploitableHosts = oldestExploitableHostsResult.rows.map((host)=>{
return {
displayName: host.displayName,
affectedSoftware: host.softwareNameAndVersion,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/hosts/${host.fleetApid}`,
cveId: host.cveId,
yearPublished: host.cveId.split('-')[1],
};
});
dataForGraphs.oldestExploitableHosts = oldestExploitableHosts;
//
// ╔╗╔╔═╗╦ ╦╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗
// ║║║║╣ ║║║║╣ ╚═╗ ║ ║ ╚╗╔╝║╣ ╚═╗ ║║║║ ║ ╠═╣ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╚═╗
// ╝╚╝╚═╝╚╩╝╚═╝╚═╝ ╩ ╚═╝ ╚╝ ╚═╝╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╚═╝
let queryToFindNewestExploitableCves;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
queryToFindNewestExploitableCves = `
WITH newestExploitable AS (
SELECT DISTINCT vulnerability."cveId", vulnerability."publishedAt"
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall.vulnerability = vulnerability.id
AND (vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0)
WHERE vulnerability."hasKnownExploit" = TRUE
)
SELECT "cveId"
FROM newestExploitable
ORDER BY "publishedAt" DESC
LIMIT 5;`;
} else {
queryToFindNewestExploitableCves = `
WITH newestExploitable AS (
SELECT DISTINCT
vulnerability.cveId,
vulnerability.publishedAt
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall.vulnerability = vulnerability.id
AND (vulnerabilityinstall.uninstalledAt IS NULL OR vulnerabilityinstall.uninstalledAt = 0)
WHERE vulnerability.hasKnownExploit = TRUE
)
SELECT cveId
FROM newestExploitable
ORDER BY publishedAt DESC
LIMIT 5;`;
}
// console.time('newest exploitable cves');
let newestExploitableCvesResult = await sails.sendNativeQuery(queryToFindNewestExploitableCves);
// console.timeEnd('newest exploitable cves');
// console.log(newestExploitableCvesResult);
let newestExploitableCves = newestExploitableCvesResult.rows.map((cve)=>{
return {
cveId: cve.cveId,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/software/vulnerabilities/${cve.cveId}`,
yearPublished: cve.cveId.split('-')[1],
};
});
dataForGraphs.newestExploitableCves = newestExploitableCves;
//
// ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔╗╔╔═╗╦ ╦╔═╗╔═╗╔╦╗ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗╔╗ ╦ ╔═╗ ╔═╗╦ ╦╔═╗╔═╗
// ╠═╣║ ║╚═╗ ║ ╚═╗ ║║║║ ║ ╠═╣ ║║║║╣ ║║║║╣ ╚═╗ ║ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╠═╣╠╩╗║ ║╣ ║ ╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╝╚╝╚═╝╚╩╝╚═╝╚═╝ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╩ ╩╚═╝╩═╝╚═╝ ╚═╝ ╚╝ ╚═╝╚═╝
let queryToFindHostsWithNewestExploitableCves;
if(sails.config.datastores.default.adapter === 'sails-postgresql') {
queryToFindHostsWithNewestExploitableCves = `
WITH "hostNewestExploitable" AS (
SELECT
host.id AS "hostId",
host."displayName" AS "displayName",
host."fleetApid" AS "fleetApid",
vulnerability."cveId" AS "cveId",
vulnerability."publishedAt" AS "publishedAtMs",
vulnerabilityinstall."softwareName" AS "softwareName",
vulnerabilityinstall."versionName" AS "versionName"
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability.id = vulnerabilityinstall.vulnerability
AND vulnerability."hasKnownExploit" = TRUE
JOIN host
ON host.id = vulnerabilityinstall.host
WHERE
vulnerabilityinstall."uninstalledAt" IS NULL
OR vulnerabilityinstall."uninstalledAt" = 0
),
"rankedNewestPerHost" AS (
SELECT
"hostId",
"displayName",
"fleetApid",
"cveId",
"publishedAtMs",
"softwareName",
"versionName",
ROW_NUMBER() OVER (
PARTITION BY "hostId"
ORDER BY "publishedAtMs" ASC
) AS "rowNumber"
FROM "hostNewestExploitable"
)
SELECT
"displayName",
"fleetApid",
"cveId",
("softwareName" || ' ' || COALESCE("versionName", '')) AS "softwareNameAndVersion",
"publishedAtMs"
FROM "rankedNewestPerHost"
WHERE "rowNumber" = 1
ORDER BY "publishedAtMs" DESC
LIMIT 5;`;
} else {
queryToFindHostsWithNewestExploitableCves = `
WITH hostNewestExploitable AS (
SELECT
host.id AS hostId,
host.displayName AS displayName,
host.fleetApid AS fleetApid,
vulnerability.cveId AS cveId,
vulnerability.publishedAt AS publishedAtMs,
vulnerabilityinstall.softwareName AS softwareName,
vulnerabilityinstall.versionName AS versionName
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability.id = vulnerabilityinstall.vulnerability
AND vulnerability.hasKnownExploit = TRUE
JOIN host
ON host.id = vulnerabilityinstall.host
WHERE
vulnerabilityinstall.uninstalledAt IS NULL
OR vulnerabilityinstall.uninstalledAt = 0
),
rankedNewestPerHost AS (
SELECT
hostId,
displayName,
fleetApid,
cveId,
publishedAtMs,
softwareName,
versionName,
ROW_NUMBER() OVER (
PARTITION BY hostId
ORDER BY publishedAtMs ASC
) AS rowNumber
FROM hostNewestExploitable
)
SELECT
displayName,
fleetApid,
cveId,
CONCAT(softwareName, ' ', COALESCE(versionName, '')) AS softwareNameAndVersion,
publishedAtMs
FROM rankedNewestPerHost
WHERE rowNumber = 1
ORDER BY publishedAtMs DESC
LIMIT 5;`;
}
// console.time('hosts with newest exploitable cves query');
let newestExploitableHostsResult = await sails.sendNativeQuery(queryToFindHostsWithNewestExploitableCves);
// console.timeEnd('hosts with newest exploitable cves query');
// console.log(newestExploitableHostsResult);
let newestExploitableHosts = newestExploitableHostsResult.rows.map((host)=>{
return {
displayName: host.displayName,
affectedSoftware: host.softwareNameAndVersion,
fleetUrl: `${sails.config.custom.fleetBaseUrl}/hosts/${host.fleetApid}`,
cveId: host.cveId,
yearPublished: host.cveId.split('-')[1],
};
});
dataForGraphs.newestExploitableHosts = newestExploitableHosts;
// console.timeEnd(`Dashboard page view action`);
// Respond with view.
return {
...dataForGraphs
};
}
};