ospd.cvss   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 76
dl 0
loc 150
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B CVSS.cvss_base_v3_value() 0 49 5
A CVSS._parse_cvss_base_vector() 0 11 1
A CVSS.roundup() 0 4 1
A CVSS.cvss_base_v2_value() 0 35 3
1
# Copyright (C) 2014-2021 Greenbone Networks GmbH
2
#
3
# SPDX-License-Identifier: AGPL-3.0-or-later
4
#
5
# This program is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU Affero General Public License as
7
# published by the Free Software Foundation, either version 3 of the
8
# License, or (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU Affero General Public License for more details.
14
#
15
# You should have received a copy of the GNU Affero General Public License
16
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18
""" Common Vulnerability Scoring System handling class. """
19
20
import math
21
from typing import List, Dict, Optional
22
23
CVSS_V2_METRICS = {
24
    'AV': {'L': 0.395, 'A': 0.646, 'N': 1.0},
25
    'AC': {'H': 0.35, 'M': 0.61, 'L': 0.71},
26
    'Au': {'M': 0.45, 'S': 0.56, 'N': 0.704},
27
    'C': {'N': 0.0, 'P': 0.275, 'C': 0.660},
28
    'I': {'N': 0.0, 'P': 0.275, 'C': 0.660},
29
    'A': {'N': 0.0, 'P': 0.275, 'C': 0.660},
30
}  # type: Dict
31
32
CVSS_V3_METRICS = {
33
    'AV': {'N': 0.85, 'A': 0.62, 'L': 0.55, 'P': 0.2},
34
    'AC': {'L': 0.77, 'H': 0.44},
35
    'PR_SU': {'N': 0.85, 'L': 0.62, 'H': 0.27},
36
    'PR_SC': {'N': 0.85, 'L': 0.68, 'H': 0.50},
37
    'UI': {'N': 0.85, 'R': 0.62},
38
    'S': {'U': False, 'C': True},
39
    'C': {'H': 0.56, 'L': 0.22, 'N': 0},
40
    'I': {'H': 0.56, 'L': 0.22, 'N': 0},
41
    'A': {'H': 0.56, 'L': 0.22, 'N': 0},
42
}  # type: Dict
43
44
45
class CVSS(object):
46
    """Handle cvss vectors and calculate the cvss scoring"""
47
48
    @staticmethod
49
    def roundup(value: float) -> float:
50
        """It rounds up to 1 decimal."""
51
        return math.ceil(value * 10) / 10
52
53
    @staticmethod
54
    def _parse_cvss_base_vector(cvss_vector: str) -> List:
55
        """Parse a string containing a cvss base vector.
56
57
        Arguments:
58
            cvss_vector (str): cvss base vector to be parsed.
59
60
        Return list with the string values of each vector element.
61
        """
62
        vector_as_list = cvss_vector.split('/')
63
        return [item.split(':')[1] for item in vector_as_list]
64
65
    @classmethod
66
    def cvss_base_v2_value(cls, cvss_base_vector: str) -> Optional[float]:
67
        """Calculate the cvss base score from a cvss base vector
68
        for cvss version 2.
69
        Arguments:
70
            cvss_base_vector (str) Cvss base vector v2.
71
72
        Return the calculated score
73
        """
74
        if not cvss_base_vector:
75
            return None
76
77
        _av, _ac, _au, _c, _i, _a = cls._parse_cvss_base_vector(
78
            cvss_base_vector
79
        )
80
81
        _impact = 10.41 * (
82
            1
83
            - (1 - CVSS_V2_METRICS['C'].get(_c))
84
            * (1 - CVSS_V2_METRICS['I'].get(_i))
85
            * (1 - CVSS_V2_METRICS['A'].get(_a))
86
        )
87
88
        _exploitability = (
89
            20
90
            * CVSS_V2_METRICS['AV'].get(_av)
91
            * CVSS_V2_METRICS['AC'].get(_ac)
92
            * CVSS_V2_METRICS['Au'].get(_au)
93
        )
94
95
        f_impact = 0 if _impact == 0 else 1.176
96
97
        cvss_base = ((0.6 * _impact) + (0.4 * _exploitability) - 1.5) * f_impact
98
99
        return round(cvss_base, 1)
100
101
    @classmethod
102
    def cvss_base_v3_value(cls, cvss_base_vector: str) -> Optional[float]:
103
        """Calculate the cvss base score from a cvss base vector
104
        for cvss version 3.
105
        Arguments:
106
            cvss_base_vector (str) Cvss base vector v3.
107
108
        Return the calculated score, None on fail.
109
        """
110
        if not cvss_base_vector:
111
            return None
112
        _ver, _av, _ac, _pr, _ui, _s, _c, _i, _a = cls._parse_cvss_base_vector(
113
            cvss_base_vector
114
        )
115
116
        scope_changed = CVSS_V3_METRICS['S'].get(_s)
117
118
        isc_base = 1 - (
119
            (1 - CVSS_V3_METRICS['C'].get(_c))
120
            * (1 - CVSS_V3_METRICS['I'].get(_i))
121
            * (1 - CVSS_V3_METRICS['A'].get(_a))
122
        )
123
124
        if scope_changed:
125
            _priv_req = CVSS_V3_METRICS['PR_SC'].get(_pr)
126
        else:
127
            _priv_req = CVSS_V3_METRICS['PR_SU'].get(_pr)
128
129
        _exploitability = (
130
            8.22
131
            * CVSS_V3_METRICS['AV'].get(_av)
132
            * CVSS_V3_METRICS['AC'].get(_ac)
133
            * _priv_req
134
            * CVSS_V3_METRICS['UI'].get(_ui)
135
        )
136
137
        if scope_changed:
138
            _impact = 7.52 * (isc_base - 0.029) - 3.25 * pow(
139
                isc_base - 0.02, 15
140
            )
141
            _base_score = min(1.08 * (_impact + _exploitability), 10)
142
        else:
143
            _impact = 6.42 * isc_base
144
            _base_score = min(_impact + _exploitability, 10)
145
146
        if _impact > 0:
147
            return cls.roundup(_base_score)
148
149
        return 0
150