cvss.c
Go to the documentation of this file.
/* SPDX-FileCopyrightText: 2012-2023 Greenbone AG
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "cvss.h"
#include <glib.h>
#include <math.h>
#include <strings.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "libgvm base"
/* Static Headers. */
static double
get_cvss_score_from_base_metrics_v3 (const char *);
/* CVSS v2. */
// clang-format off
#define AV_NETWORK 1.0
#define AV_ADJACENT_NETWORK 0.646
#define AV_LOCAL 0.395
#define AC_LOW 0.71
#define AC_MEDIUM 0.61
#define AC_HIGH 0.35
#define Au_MULTIPLE_INSTANCES 0.45
#define Au_SINGLE_INSTANCE 0.56
#define Au_NONE 0.704
#define C_NONE 0.0
#define C_PARTIAL 0.275
#define C_COMPLETE 0.660
#define I_NONE 0.0
#define I_PARTIAL 0.275
#define I_COMPLETE 0.660
#define A_NONE 0.0
#define A_PARTIAL 0.275
#define A_COMPLETE 0.660
// clang-format on
enum base_metrics
{
A,
I,
C,
Au,
AC,
AV
};
struct impact_item
{
const char *name;
double nvalue;
};
struct cvss
{
double conf_impact;
double integ_impact;
double avail_impact;
double access_vector;
double access_complexity;
double authentication;
};
static const struct impact_item impact_map[][3] = {
[A] =
{
{"N", A_NONE},
{"P", A_PARTIAL},
{"C", A_COMPLETE},
},
[I] =
{
{"N", I_NONE},
{"P", I_PARTIAL},
{"C", I_COMPLETE},
},
[C] =
{
{"N", C_NONE},
{"P", C_PARTIAL},
{"C", C_COMPLETE},
},
[Au] =
{
{"N", Au_NONE},
{"M", Au_MULTIPLE_INSTANCES},
{"S", Au_SINGLE_INSTANCE},
},
[AV] =
{
{"N", AV_NETWORK},
{"A", AV_ADJACENT_NETWORK},
{"L", AV_LOCAL},
},
[AC] =
{
{"L", AC_LOW},
{"M", AC_MEDIUM},
{"H", AC_HIGH},
},
};
static int
toenum (const char *str, enum base_metrics *res)
{
int rc = 0; /* let's be optimistic */
if (g_strcmp0 (str, "A") == 0)
*res = A;
else if (g_strcmp0 (str, "I") == 0)
*res = I;
else if (g_strcmp0 (str, "C") == 0)
*res = C;
else if (g_strcmp0 (str, "Au") == 0)
*res = Au;
else if (g_strcmp0 (str, "AU") == 0)
*res = Au;
else if (g_strcmp0 (str, "AV") == 0)
*res = AV;
else if (g_strcmp0 (str, "AC") == 0)
*res = AC;
else
rc = -1;
return rc;
}
static double
get_impact_subscore (const struct cvss *cvss)
{
return 10.41
* (1
- (1 - cvss->conf_impact) * (1 - cvss->integ_impact)
* (1 - cvss->avail_impact));
}
static double
get_exploitability_subscore (const struct cvss *cvss)
{
return 20 * cvss->access_vector * cvss->access_complexity
* cvss->authentication;
}
static inline int
set_impact_from_str (const char *value, enum base_metrics metric,
struct cvss *cvss)
{
int i;
for (i = 0; i < 3; i++)
{
const struct impact_item *impact;
impact = &impact_map[metric][i];
if (g_strcmp0 (impact->name, value) == 0)
{
switch (metric)
{
case A:
cvss->avail_impact = impact->nvalue;
break;
case I:
cvss->integ_impact = impact->nvalue;
break;
case C:
cvss->conf_impact = impact->nvalue;
break;
case Au:
cvss->authentication = impact->nvalue;
break;
case AV:
cvss->access_vector = impact->nvalue;
break;
case AC:
cvss->access_complexity = impact->nvalue;
break;
default:
return -1;
}
return 0;
}
}
return -1;
}
static double
__get_cvss_score (struct cvss *cvss)
{
double impact = 1.176;
double impact_sub;
double exploitability_sub;
impact_sub = get_impact_subscore (cvss);
exploitability_sub = get_exploitability_subscore (cvss);
if (impact_sub < 0.1)
impact = 0.0;
return (((0.6 * impact_sub) + (0.4 * exploitability_sub) - 1.5) * impact)
+ 0.0;
}
double
get_cvss_score_from_base_metrics (const char *cvss_str)
{
struct cvss cvss;
char *token, *base_str, *base_metrics;
if (cvss_str == NULL)
return -1.0;
if (g_str_has_prefix (cvss_str, "CVSS:3.1/")
|| g_str_has_prefix (cvss_str, "CVSS:3.0/"))
return get_cvss_score_from_base_metrics_v3 (cvss_str
+ strlen ("CVSS:3.X/"));
memset (&cvss, 0x00, sizeof (struct cvss));
base_str = base_metrics = g_strdup_printf ("%s/", cvss_str);
while ((token = strchr (base_metrics, '/')) != NULL)
{
char *token2 = strtok (base_metrics, ":");
char *metric_name = token2;
char *metric_value;
enum base_metrics mval;
int rc;
*token++ = '\0';
if (metric_name == NULL)
goto ret_err;
metric_value = strtok (NULL, ":");
if (metric_value == NULL)
goto ret_err;
rc = toenum (metric_name, &mval);
if (rc)
goto ret_err;
if (set_impact_from_str (metric_value, mval, &cvss))
goto ret_err;
base_metrics = token;
}
g_free (base_str);
return __get_cvss_score (&cvss);
ret_err:
g_free (base_str);
return (double) -1;
}
/* CVSS v3. */
static double
roundup (double cvss)
{
int trim;
/* "Roundup returns the smallest number, specified to 1 decimal place,
* that is equal to or higher than its input. For example, Roundup (4.02)
* returns 4.1; and Roundup (4.00) returns 4.0." */
/* 3.020000000 => 3.1 */
/* 3.000000001 => 3.0 */
/* 5.299996 => 5.3 */
/* 5.500320 => 5.6 */
trim = round (cvss * 100000);
if ((trim % 10000) == 0)
return ((double) trim) / 100000;
return (floor (trim / 10000) + 1) / 10.0;
}
static double
v3_impact (const char *value)
{
if (strcasecmp (value, "N") == 0)
return 0.0;
if (strcasecmp (value, "L") == 0)
return 0.22;
if (strcasecmp (value, "H") == 0)
return 0.56;
return -1.0;
}
static double
get_cvss_score_from_base_metrics_v3 (const char *cvss_str)
{
gchar **split, **point;
int scope_changed;
double impact_conf, impact_integ, impact_avail;
double vector, complexity, privilege, user;
double isc_base, impact, exploitability, base;
/* https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator
* https://www.first.org/cvss/v3.1/specification-document
* https://www.first.org/cvss/v3.0/specification-document */
scope_changed = -1;
impact_conf = -1.0;
impact_integ = -1.0;
impact_avail = -1.0;
vector = -1.0;
complexity = -1.0;
privilege = -1.0;
user = -1.0;
/* AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N */
split = g_strsplit (cvss_str, "/", 0);
point = split;
while (*point)
{
/* Scope. */
if (strncasecmp ("S:", *point, 2) == 0)
{
if (strcasecmp (*point + 2, "U") == 0)
scope_changed = 0;
else if (strcasecmp (*point + 2, "C") == 0)
scope_changed = 1;
}
/* Confidentiality. */
if (strncasecmp ("C:", *point, 2) == 0)
impact_conf = v3_impact (*point + 2);
/* Integrity. */
if (strncasecmp ("I:", *point, 2) == 0)
impact_integ = v3_impact (*point + 2);
/* Availability. */
if (strncasecmp ("A:", *point, 2) == 0)
impact_avail = v3_impact (*point + 2);
/* Attack Vector. */
if (strncasecmp ("AV:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "N") == 0)
vector = 0.85;
else if (strcasecmp (*point + 3, "A") == 0)
vector = 0.62;
else if (strcasecmp (*point + 3, "L") == 0)
vector = 0.55;
else if (strcasecmp (*point + 3, "P") == 0)
vector = 0.2;
}
/* Attack Complexity. */
if (strncasecmp ("AC:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "L") == 0)
complexity = 0.77;
else if (strcasecmp (*point + 3, "H") == 0)
complexity = 0.44;
}
/* Privileges Required. */
if (strncasecmp ("PR:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "N") == 0)
privilege = 0.85;
else if (strcasecmp (*point + 3, "L") == 0)
privilege = 0.62;
else if (strcasecmp (*point + 3, "H") == 0)
privilege = 0.27;
else
privilege = -1.0;
}
/* User Interaction. */
if (strncasecmp ("UI:", *point, 3) == 0)
{
if (strcasecmp (*point + 3, "N") == 0)
user = 0.85;
else if (strcasecmp (*point + 3, "R") == 0)
user = 0.62;
}
point++;
}
g_strfreev (split);
/* All of the base metrics are required. */
if (scope_changed == -1 || impact_conf == -1.0 || impact_integ == -1.0
|| impact_avail == -1.0 || vector == -1.0 || complexity == -1.0
|| privilege == -1.0 || user == -1.0)
return -1.0;
/* Privileges Required has a special case for S:C. */
if (scope_changed && privilege == 0.62)
privilege = 0.68;
else if (scope_changed && privilege == 0.27)
privilege = 0.5;
/* Impact. */
isc_base = 1 - ((1 - impact_conf) * (1 - impact_integ) * (1 - impact_avail));
if (scope_changed)
impact = 7.52 * (isc_base - 0.029) - 3.25 * pow ((isc_base - 0.02), 15);
else
impact = 6.42 * isc_base;
if (impact <= 0)
return 0.0;
/* Exploitability. */
exploitability = 8.22 * vector * complexity * privilege * user;
/* Final. */
if (scope_changed)
base = 1.08 * (impact + exploitability);
else
base = impact + exploitability;
if (base > 10.0)
return 10.0;
return roundup (base);
}
C_COMPLETE
#define C_COMPLETE
Definition cvss.c:111
set_impact_from_str
static int set_impact_from_str(const char *value, enum base_metrics metric, struct cvss *cvss)
Set impact score from string representation.
Definition cvss.c:277
AV_LOCAL
#define AV_LOCAL
Definition cvss.c:90
get_exploitability_subscore
static double get_exploitability_subscore(const struct cvss *cvss)
Calculate Exploitability Sub Score.
Definition cvss.c:261
Au_SINGLE_INSTANCE
#define Au_SINGLE_INSTANCE
Definition cvss.c:103
A_PARTIAL
#define A_PARTIAL
Definition cvss.c:124
toenum
static int toenum(const char *str, enum base_metrics *res)
Determine base metric enumeration from a string.
Definition cvss.c:211
C_NONE
#define C_NONE
ConfidentialityImpact (C) Constants.
Definition cvss.c:109
I_PARTIAL
#define I_PARTIAL
Definition cvss.c:117
v3_impact
static double v3_impact(const char *value)
Get impact.
Definition cvss.c:448
AV_NETWORK
#define AV_NETWORK
AccessVector (AV) Constants.
Definition cvss.c:88
C_PARTIAL
#define C_PARTIAL
Definition cvss.c:110
A_COMPLETE
#define A_COMPLETE
Definition cvss.c:125
Au_MULTIPLE_INSTANCES
#define Au_MULTIPLE_INSTANCES
Authentication (Au) Constants.
Definition cvss.c:102
get_impact_subscore
static double get_impact_subscore(const struct cvss *cvss)
Calculate Impact Sub Score.
Definition cvss.c:244
AC_LOW
#define AC_LOW
AccessComplexity (AC) Constants.
Definition cvss.c:95
I_NONE
#define I_NONE
IntegrityImpact (I) Constants.
Definition cvss.c:116
impact_map
static const struct impact_item impact_map[][3]
Definition cvss.c:163
base_metrics
base_metrics
Base metrics.
Definition cvss.c:132
AC
@ AC
Definition cvss.c:137
A
@ A
Definition cvss.c:133
C
@ C
Definition cvss.c:135
Au
@ Au
Definition cvss.c:136
I
@ I
Definition cvss.c:134
AV
@ AV
Definition cvss.c:138
get_cvss_score_from_base_metrics_v3
static double get_cvss_score_from_base_metrics_v3(const char *)
Calculate CVSS Score.
Definition cvss.c:467
A_NONE
#define A_NONE
AvailabilityImpact (A) Constants.
Definition cvss.c:123
get_cvss_score_from_base_metrics
double get_cvss_score_from_base_metrics(const char *cvss_str)
Calculate CVSS Score.
Definition cvss.c:358
__get_cvss_score
static double __get_cvss_score(struct cvss *cvss)
Final CVSS score computation helper.
Definition cvss.c:334
I_COMPLETE
#define I_COMPLETE
Definition cvss.c:118
AC_MEDIUM
#define AC_MEDIUM
Definition cvss.c:96
AV_ADJACENT_NETWORK
#define AV_ADJACENT_NETWORK
Definition cvss.c:89
roundup
static double roundup(double cvss)
Round final score as in spec.
Definition cvss.c:421
AC_HIGH
#define AC_HIGH
Definition cvss.c:97
Au_NONE
#define Au_NONE
Definition cvss.c:104
cvss.h
Protos for CVSS utility functions.
strings.h
String utilities.
cvss
Describe a CVSS metrics.
Definition cvss.c:154
cvss::integ_impact
double integ_impact
Definition cvss.c:156
cvss::access_vector
double access_vector
Definition cvss.c:158
cvss::avail_impact
double avail_impact
Definition cvss.c:157
cvss::authentication
double authentication
Definition cvss.c:160
cvss::access_complexity
double access_complexity
Definition cvss.c:159
cvss::conf_impact
double conf_impact
Definition cvss.c:155
impact_item
Describe a CVSS impact element.
Definition cvss.c:145
impact_item::name
const char * name
Definition cvss.c:146
impact_item::nvalue
double nvalue
Definition cvss.c:147