diff --git a/CMakeLists.txt b/CMakeLists.txt
index 772712ac4..a45eb22f9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,7 +101,7 @@ include (CPack)
## Variables
-set (GVMD_DATABASE_VERSION 255)
+set (GVMD_DATABASE_VERSION 256)
set (GVMD_SCAP_DATABASE_VERSION 21)
diff --git a/src/manage.c b/src/manage.c
index 12ae1c6a0..0af8a5486 100644
--- a/src/manage.c
+++ b/src/manage.c
@@ -5085,6 +5085,8 @@ manage_sync (sigset_t *sigmask_current,
wait_for_pid (scap_pid, "SCAP sync");
wait_for_pid (cert_pid, "CERT sync");
+ update_scap_extra ();
+
lockfile_unlock (&lockfile);
}
}
@@ -5977,6 +5979,54 @@ get_nvt_xml (iterator_t *nvts, int details, int pref_count,
free (default_timeout);
}
+ if (nvt_iterator_epss_cve (nvts))
+ {
+ buffer_xml_append_printf
+ (buffer,
+ ""
+ ""
+ "%0.5f"
+ "%0.5f"
+ "",
+ nvt_iterator_epss_score (nvts),
+ nvt_iterator_epss_percentile (nvts),
+ nvt_iterator_epss_cve (nvts));
+
+ if (nvt_iterator_has_epss_severity (nvts))
+ {
+ buffer_xml_append_printf
+ (buffer,
+ "%0.1f",
+ nvt_iterator_epss_severity (nvts));
+ }
+
+ buffer_xml_append_printf
+ (buffer,
+ ""
+ ""
+ ""
+ "%0.5f"
+ "%0.5f"
+ "",
+ nvt_iterator_max_epss_score (nvts),
+ nvt_iterator_max_epss_percentile (nvts),
+ nvt_iterator_max_epss_cve (nvts));
+
+ if (nvt_iterator_has_max_epss_severity (nvts))
+ {
+ buffer_xml_append_printf
+ (buffer,
+ "%0.1f",
+ nvt_iterator_max_epss_severity (nvts));
+ }
+
+ buffer_xml_append_printf
+ (buffer,
+ ""
+ ""
+ "");
+ }
+
xml_string_append (buffer, close_tag ? "" : "");
msg = g_string_free (buffer, FALSE);
}
diff --git a/src/manage.h b/src/manage.h
index 018fbfed3..74ec69c88 100644
--- a/src/manage.h
+++ b/src/manage.h
@@ -1982,6 +1982,36 @@ nvt_iterator_solution_type (iterator_t*);
const char*
nvt_iterator_solution_method (iterator_t*);
+double
+nvt_iterator_epss_score (iterator_t*);
+
+double
+nvt_iterator_epss_percentile (iterator_t*);
+
+const char*
+nvt_iterator_epss_cve (iterator_t*);
+
+double
+nvt_iterator_epss_severity (iterator_t*);
+
+gboolean
+nvt_iterator_has_epss_severity (iterator_t*);
+
+double
+nvt_iterator_max_epss_score (iterator_t*);
+
+double
+nvt_iterator_max_epss_percentile (iterator_t*);
+
+const char*
+nvt_iterator_max_epss_cve (iterator_t*);
+
+double
+nvt_iterator_max_epss_severity (iterator_t*);
+
+gboolean
+nvt_iterator_has_max_epss_severity (iterator_t*);
+
char*
nvt_default_timeout (const char *);
diff --git a/src/manage_migrators.c b/src/manage_migrators.c
index 9d5436716..3053fd2fe 100644
--- a/src/manage_migrators.c
+++ b/src/manage_migrators.c
@@ -3176,6 +3176,46 @@ migrate_254_to_255 ()
return 0;
}
+/**
+ * @brief Migrate the database from version 255 to version 256.
+ *
+ * @return 0 success, -1 error.
+ */
+int
+migrate_255_to_256 ()
+{
+ sql_begin_immediate ();
+
+ /* Ensure that the database is currently version 255. */
+
+ if (manage_db_version () != 255)
+ {
+ sql_rollback ();
+ return -1;
+ }
+
+ /* Update the database. */
+
+ // Add new columns
+
+ sql ("ALTER TABLE nvts ADD COLUMN epss_cve TEXT;");
+ sql ("ALTER TABLE nvts ADD COLUMN epss_score DOUBLE PRECISION;");
+ sql ("ALTER TABLE nvts ADD COLUMN epss_percentile DOUBLE PRECISION;");
+ sql ("ALTER TABLE nvts ADD COLUMN epss_severity DOUBLE PRECISION;");
+ sql ("ALTER TABLE nvts ADD COLUMN max_epss_cve TEXT;");
+ sql ("ALTER TABLE nvts ADD COLUMN max_epss_score DOUBLE PRECISION;");
+ sql ("ALTER TABLE nvts ADD COLUMN max_epss_percentile DOUBLE PRECISION;");
+ sql ("ALTER TABLE nvts ADD COLUMN max_epss_severity DOUBLE PRECISION;");
+
+ /* Set the database version to 256. */
+
+ set_db_version (256);
+
+ sql_commit ();
+
+ return 0;
+}
+
#undef UPDATE_DASHBOARD_SETTINGS
/**
@@ -3237,6 +3277,7 @@ static migrator_t database_migrators[] = {
{253, migrate_252_to_253},
{254, migrate_253_to_254},
{255, migrate_254_to_255},
+ {256, migrate_255_to_256},
/* End marker. */
{-1, NULL}};
diff --git a/src/manage_pg.c b/src/manage_pg.c
index 851769370..19d3463f7 100644
--- a/src/manage_pg.c
+++ b/src/manage_pg.c
@@ -1868,7 +1868,16 @@ create_tables_nvt (const gchar *suffix)
" solution_method text,"
" detection text,"
" qod integer,"
- " qod_type text);",
+ " qod_type text,"
+ " epss_cve TEXT,"
+ " epss_score DOUBLE PRECISION,"
+ " epss_percentile DOUBLE PRECISION,"
+ " epss_severity DOUBLE PRECISION,"
+ " max_epss_cve TEXT,"
+ " max_epss_score DOUBLE PRECISION,"
+ " max_epss_percentile DOUBLE PRECISION,"
+ " max_epss_severity DOUBLE PRECISION"
+ ");",
suffix);
}
diff --git a/src/manage_sql_nvts.c b/src/manage_sql_nvts.c
index 95714193d..adb57348f 100644
--- a/src/manage_sql_nvts.c
+++ b/src/manage_sql_nvts.c
@@ -41,6 +41,7 @@
#include "manage_preferences.h"
#include "manage_sql.h"
#include "manage_sql_configs.h"
+#include "manage_sql_secinfo.h"
#include "sql.h"
#include "utils.h"
@@ -1214,6 +1215,153 @@ DEF_ACCESS (nvt_iterator_detection, GET_ITERATOR_COLUMN_COUNT + 19);
*/
DEF_ACCESS (nvt_iterator_solution_method, GET_ITERATOR_COLUMN_COUNT + 20);
+/**
+ * @brief Get the EPSS score selected by severity from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The EPSS score.
+ */
+double
+nvt_iterator_epss_score (iterator_t* iterator)
+{
+ double ret;
+ if (iterator->done) return -1;
+ ret = iterator_double (iterator, GET_ITERATOR_COLUMN_COUNT + 21);
+ return ret;
+}
+
+/**
+ * @brief Get the EPSS percentile selected by severity from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The EPSS percentile.
+ */
+double
+nvt_iterator_epss_percentile (iterator_t* iterator)
+{
+ double ret;
+ if (iterator->done) return -1;
+ ret = iterator_double (iterator, GET_ITERATOR_COLUMN_COUNT + 22);
+ return ret;
+}
+
+/**
+ * @brief Get the CVE of the EPSS score by severity from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return CVE-ID of the EPSS score, or NULL if iteration is complete.
+ * Freed by cleanup_iterator.
+ */
+DEF_ACCESS (nvt_iterator_epss_cve, GET_ITERATOR_COLUMN_COUNT + 23);
+
+/**
+ * @brief Get the maximum severity of CVEs with EPSS info from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The severity score.
+ */
+double
+nvt_iterator_epss_severity (iterator_t* iterator)
+{
+ double ret;
+ if (iterator->done) return -1;
+ ret = iterator_double (iterator, GET_ITERATOR_COLUMN_COUNT + 24);
+ return ret;
+}
+
+/**
+ * @brief Get whether the NVT has a severity for the max severity EPSS score.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Whether the severity exists.
+ */
+gboolean
+nvt_iterator_has_epss_severity (iterator_t* iterator)
+{
+ gboolean ret;
+ if (iterator->done) return -1;
+ ret = iterator_string (iterator, GET_ITERATOR_COLUMN_COUNT + 24) != NULL;
+ return ret;
+}
+
+/**
+ * @brief Get the maximum EPSS score from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The maximum EPSS score.
+ */
+double
+nvt_iterator_max_epss_score (iterator_t* iterator)
+{
+ double ret;
+ if (iterator->done) return -1;
+ ret = iterator_double (iterator, GET_ITERATOR_COLUMN_COUNT + 25);
+ return ret;
+}
+
+/**
+ * @brief Get the maximum EPSS percentile from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The maximum EPSS percentile.
+ */
+double
+nvt_iterator_max_epss_percentile (iterator_t* iterator)
+{
+ double ret;
+ if (iterator->done) return -1;
+ ret = iterator_double (iterator, GET_ITERATOR_COLUMN_COUNT + 26);
+ return ret;
+}
+
+/**
+ * @brief Get the CVE of the maximum EPSS score from an NVT iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return CVE-ID of the maximum EPSS score, or NULL if iteration is complete.
+ * Freed by cleanup_iterator.
+ */
+DEF_ACCESS (nvt_iterator_max_epss_cve, GET_ITERATOR_COLUMN_COUNT + 27);
+
+/**
+ * @brief Get the severity of the maximum EPSS score from an NVT iterator.
+ * @param[in] iterator Iterator.
+ *
+ * @return The severity score.
+ */
+double
+nvt_iterator_max_epss_severity (iterator_t* iterator)
+{
+ double ret;
+ if (iterator->done) return -1;
+ ret = iterator_double (iterator, GET_ITERATOR_COLUMN_COUNT + 28);
+ return ret;
+}
+
+/**
+ * @brief Get whether the NVT has a severity for the max EPSS score.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Whether the severity exists.
+ */
+gboolean
+nvt_iterator_has_max_epss_severity (iterator_t* iterator)
+{
+ gboolean ret;
+ if (iterator->done) return -1;
+ ret = iterator_string (iterator, GET_ITERATOR_COLUMN_COUNT + 28) != NULL;
+ return ret;
+}
+
/**
* @brief Get the default timeout of an NVT.
*
@@ -2532,6 +2680,9 @@ manage_rebuild (GSList *log_config, const db_conn_info_t *database)
break;
}
+ if (ret == 0)
+ ret = update_scap_extra ();
+
feed_lockfile_unlock (&lockfile);
manage_option_cleanup ();
diff --git a/src/manage_sql_nvts.h b/src/manage_sql_nvts.h
index e9db88fad..bbe4d39a6 100644
--- a/src/manage_sql_nvts.h
+++ b/src/manage_sql_nvts.h
@@ -31,7 +31,9 @@
{ GET_ITERATOR_FILTER_COLUMNS, "version", "cve", \
"family", "cvss_base", "severity", "cvss", "script_tags", "qod", \
"qod_type", "solution_type", "solution", "summary", "insight", \
- "affected", "impact", "detection", "solution_method", NULL }
+ "affected", "impact", "detection", "solution_method", "epss_score", \
+ "epss_percentile", "max_epss_score", "max_epss_percentile", \
+ NULL }
/**
* @brief NVT iterator columns.
@@ -62,6 +64,18 @@
{ "impact", NULL, KEYWORD_TYPE_STRING }, \
{ "detection", NULL, KEYWORD_TYPE_STRING }, \
{ "solution_method", NULL, KEYWORD_TYPE_STRING }, \
+ { "coalesce (epss_score, 0.0)", "epss_score", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "coalesce (epss_percentile, 0.0)", "epss_percentile", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "epss_cve", NULL, KEYWORD_TYPE_STRING }, \
+ { "epss_severity", NULL, KEYWORD_TYPE_DOUBLE }, \
+ { "coalesce (max_epss_score, 0.0)", "max_epss_score", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "coalesce (max_epss_percentile, 0.0)", "max_epss_percentile", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "max_epss_cve", NULL, KEYWORD_TYPE_STRING }, \
+ { "max_epss_severity", NULL, KEYWORD_TYPE_DOUBLE }, \
{ NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
}
@@ -94,6 +108,18 @@
{ "impact", NULL, KEYWORD_TYPE_STRING }, \
{ "detection", NULL, KEYWORD_TYPE_STRING }, \
{ "solution_method", NULL, KEYWORD_TYPE_STRING }, \
+ { "coalesce (epss_score, 0.0)", "epss_score", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "coalesce (epss_percentile, 0.0)", "epss_percentile", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "epss_cve", NULL, KEYWORD_TYPE_STRING }, \
+ { "epss_severity", NULL, KEYWORD_TYPE_DOUBLE }, \
+ { "coalesce (max_epss_score, 0.0)", "max_epss_score", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "coalesce (max_epss_percentile, 0.0)", "max_epss_percentile", \
+ KEYWORD_TYPE_DOUBLE }, \
+ { "max_epss_cve", NULL, KEYWORD_TYPE_STRING }, \
+ { "max_epss_severity", NULL, KEYWORD_TYPE_DOUBLE }, \
{ NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
}
diff --git a/src/manage_sql_secinfo.c b/src/manage_sql_secinfo.c
index 455fc3dbc..3de05c6f1 100644
--- a/src/manage_sql_secinfo.c
+++ b/src/manage_sql_secinfo.c
@@ -3571,6 +3571,65 @@ update_scap_placeholders ()
" WHERE cpe=cpes.id))"
" WHERE cpes.title IS NULL;");
}
+
+/**
+ * @brief Update extra data for VTs based on SCAP and SCAP supplement data.
+ */
+static void
+update_vt_scap_extra_data ()
+{
+ g_info ("Assigning EPSS scores to VTs");
+
+ sql ("UPDATE nvts"
+ " SET epss_cve = NULL,"
+ " epss_score = NULL,"
+ " epss_percentile = NULL,"
+ " epss_severity = NULL,"
+ " max_epss_cve = NULL,"
+ " max_epss_score = NULL,"
+ " max_epss_percentile = NULL,"
+ " max_epss_severity = NULL;");
+
+ sql ("WITH epss_candidates AS ("
+ " SELECT vt_oid, cve, severity, epss, percentile,"
+ " rank() OVER (PARTITION BY vt_oid"
+ " ORDER BY severity DESC,"
+ " epss DESC,"
+ " scap.cves.modification_time DESC) AS rank"
+ " FROM (SELECT * FROM vt_refs WHERE type='cve') AS vt_cves"
+ " JOIN scap.epss_scores ON ref_id = cve"
+ " LEFT JOIN scap.cves ON scap.cves.name = cve"
+ " ORDER BY vt_oid"
+ ") "
+ "UPDATE nvts"
+ " SET epss_cve = epss_candidates.cve,"
+ " epss_score = epss_candidates.epss,"
+ " epss_percentile = epss_candidates.percentile,"
+ " epss_severity = epss_candidates.severity"
+ " FROM epss_candidates"
+ " WHERE epss_candidates.vt_oid = nvts.oid"
+ " AND epss_candidates.rank = 1;");
+
+ sql ("WITH epss_candidates AS ("
+ " SELECT vt_oid, cve, severity, epss, percentile,"
+ " rank() OVER (PARTITION BY vt_oid"
+ " ORDER BY epss DESC,"
+ " severity DESC,"
+ " scap.cves.modification_time DESC) AS rank"
+ " FROM (SELECT * FROM vt_refs WHERE type='cve') AS vt_cves"
+ " JOIN scap.epss_scores ON ref_id = cve"
+ " LEFT JOIN scap.cves ON scap.cves.name = cve"
+ " ORDER BY vt_oid"
+ ") "
+ "UPDATE nvts"
+ " SET max_epss_cve = epss_candidates.cve,"
+ " max_epss_score = epss_candidates.epss,"
+ " max_epss_percentile = epss_candidates.percentile,"
+ " max_epss_severity = epss_candidates.severity"
+ " FROM epss_candidates"
+ " WHERE epss_candidates.vt_oid = nvts.oid"
+ " AND epss_candidates.rank = 1;");
+}
/**
* @brief Update CERT data that depends on SCAP.
@@ -3906,6 +3965,29 @@ update_scap (gboolean reset_scap_db)
return 0;
}
+/**
+ * @brief Update extra data in the SCAP DB that depends on other feeds.
+ *
+ * @return 0 success, -1 error.
+ */
+int
+update_scap_extra ()
+{
+ if (manage_scap_loaded () == 0)
+ {
+ g_info ("%s: SCAP database missing, skipping extra data update",
+ __func__);
+ return 0;
+ }
+
+ g_debug ("%s: update SCAP extra data of VTs", __func__);
+ setproctitle ("Syncing SCAP: Updating VT extra data");
+
+ update_vt_scap_extra_data ();
+
+ return 0;
+}
+
/**
* @brief Sync the SCAP DB.
*
@@ -3953,6 +4035,9 @@ rebuild_scap ()
if (ret == 1)
ret = 2;
+ if (ret == 0)
+ ret = update_scap_extra ();
+
if (feed_lockfile_unlock (&lockfile))
{
g_warning (
diff --git a/src/manage_sql_secinfo.h b/src/manage_sql_secinfo.h
index 7e7a83ed6..c0518cc79 100644
--- a/src/manage_sql_secinfo.h
+++ b/src/manage_sql_secinfo.h
@@ -195,4 +195,7 @@ get_secinfo_commit_size ();
void
set_secinfo_commit_size (int);
+int
+update_scap_extra ();
+
#endif /* not _GVMD_MANAGE_SQL_SECINFO_H */
diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in
index ba7bba56f..4e09742ca 100644
--- a/src/schema_formats/XML/GMP.xml.in
+++ b/src/schema_formats/XML/GMP.xml.in
@@ -582,6 +582,7 @@ along with this program. If not, see .
timeout
default_timeout
solution
+ epss
preferences
@@ -680,6 +681,112 @@ along with this program. If not, see .
+
+ epss
+ Exploit Prediction Scoring System (EPSS) info if available
+
+ max_severity
+ max_epss
+
+
+ max_severity
+
+ EPSS info of the referenced CVE with the highest severity
+
+
+ In case there are multiple CVEs referenced by the NVT tied for the
+ highest severity, they are also sorted by EPSS score and modification
+ time and the first one is chosen.
+
+
+ score
+ percentile
+ cve
+
+
+ score
+ EPSS score of the CVE
+
+ decimal
+
+
+
+ percentile
+ EPSS percentile of the CVE
+
+ decimal
+
+
+
+ cve
+ The representative CVE chosen
+
+
+ id
+ CVE-ID of the CVE
+ text
+
+ severity
+
+
+ severity
+ Severity (CVSS) score of the CVE if available
+
+ severity
+
+
+
+
+
+ max_epss
+
+ EPSS info of the referenced CVE with the highest EPSS score
+
+
+ In case there are multiple CVEs referenced by the NVT tied for the
+ highest EPSS score, they are also sorted by severity and modification
+ time and the first one is chosen.
+
+
+ score
+ percentile
+ cve
+
+
+ score
+ EPSS score of the CVE
+
+ decimal
+
+
+
+ percentile
+ EPSS percentile of the CVE
+
+ decimal
+
+
+
+ cve
+ The representative CVE chosen
+
+
+ id
+ CVE-ID of the CVE
+ text
+
+ severity
+
+
+ severity
+ Severity (CVSS) score of the CVE if available
+
+ severity
+
+
+
+
+
preferences
The list of preferences
@@ -12199,6 +12306,34 @@ END:VCALENDAR
integer
Version of the NVT (deprected)
+
+ epss_score
+ decimal
+
+ EPSS score of highest severity CVE (see epss/max_severity)
+
+
+
+ epss_percentile
+ decimal
+
+ EPSS percentile of highest severity CVE (see epss/max_severity)
+
+
+
+ max_epss_score
+ decimal
+
+ Highest EPSS score of referenced CVEs (see epss/max_epss)
+
+
+
+ max_epss_percentile
+ decimal
+
+ Highest EPSS percentile of referenced CVEs (see epss/max_epss)
+
+
type is "cve"
@@ -12222,6 +12357,16 @@ END:VCALENDAR
iso_time
Time the CVE was published, alias for created
+
+ epss_score
+ decimal
+ EPSS score the CVE
+
+
+ epss_percentile
+ decimal
+ EPSS percentile of the CVE
+
type is "cpe"
@@ -13793,6 +13938,7 @@ END:VCALENDAR
timeout
default_timeout
solution
+ epss
preferences
@@ -13969,6 +14115,112 @@ END:VCALENDAR
text
+
+ epss
+ Exploit Prediction Scoring System (EPSS) info if available
+
+ max_severity
+ max_epss
+
+
+ max_severity
+
+ EPSS info of the referenced CVE with the highest severity
+
+
+ In case there are multiple CVEs referenced by the NVT tied for the
+ highest severity, they are also sorted by EPSS score and modification
+ time and the first one is chosen.
+
+
+ score
+ percentile
+ cve
+
+
+ score
+ EPSS score of the CVE
+
+ decimal
+
+
+
+ percentile
+ EPSS percentile of the CVE
+
+ decimal
+
+
+
+ cve
+ The representative CVE chosen
+
+
+ id
+ CVE-ID of the CVE
+ text
+
+ severity
+
+
+ severity
+ Severity (CVSS) score of the CVE if available
+
+ severity
+
+
+
+
+
+ max_epss
+
+ EPSS info of the referenced CVE with the highest EPSS score
+
+
+ In case there are multiple CVEs referenced by the NVT tied for the
+ highest EPSS score, they are also sorted by severity and modification
+ time and the first one is chosen.
+
+
+ score
+ percentile
+ cve
+
+
+ score
+ EPSS score of the CVE
+
+ decimal
+
+
+
+ percentile
+ EPSS percentile of the CVE
+
+ decimal
+
+
+
+ cve
+ The representative CVE chosen
+
+
+ id
+ CVE-ID of the CVE
+ text
+
+ severity
+
+
+ severity
+ Severity (CVSS) score of the CVE if available
+
+ severity
+
+
+
+
+
preferences
List of preferences of the NVT