cvss-suite 1.2.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yml +23 -0
- data/.github/workflows/rubocop.yml +22 -0
- data/.rubocop.yml +47 -1
- data/.rubocop_todo.yml +59 -0
- data/CHANGES.md +61 -1
- data/CNAME +1 -0
- data/CODE_OF_CONDUCT.md +3 -2
- data/Gemfile +3 -2
- data/LICENSE.md +2 -1
- data/README.md +21 -18
- data/_config.yml +1 -0
- data/bin/console +3 -3
- data/cvss_suite.gemspec +23 -16
- data/lib/cvss_suite/cvss.rb +77 -98
- data/lib/cvss_suite/cvss2/cvss2.rb +53 -30
- data/lib/cvss_suite/cvss2/cvss2_base.rb +72 -77
- data/lib/cvss_suite/cvss2/cvss2_environmental.rb +55 -56
- data/lib/cvss_suite/cvss2/cvss2_temporal.rb +43 -43
- data/lib/cvss_suite/cvss3/cvss3.rb +42 -38
- data/lib/cvss_suite/cvss3/cvss3_base.rb +75 -77
- data/lib/cvss_suite/cvss3/cvss3_environmental.rb +162 -111
- data/lib/cvss_suite/cvss3/cvss3_temporal.rb +44 -44
- data/lib/cvss_suite/cvss31/cvss31.rb +39 -30
- data/lib/cvss_suite/cvss31/cvss31_base.rb +69 -70
- data/lib/cvss_suite/cvss31/cvss31_environmental.rb +162 -111
- data/lib/cvss_suite/cvss31/cvss31_temporal.rb +44 -44
- data/lib/cvss_suite/cvss_metric.rb +37 -38
- data/lib/cvss_suite/cvss_property.rb +69 -57
- data/lib/cvss_suite/errors.rb +4 -1
- data/lib/cvss_suite/helpers/cvss31_helper.rb +28 -0
- data/lib/cvss_suite/helpers/cvss3_helper.rb +24 -17
- data/lib/cvss_suite/invalid_cvss.rb +42 -47
- data/lib/cvss_suite/version.rb +4 -3
- data/lib/cvss_suite.rb +46 -15
- metadata +23 -29
- data/.travis.yml +0 -4
- data/lib/cvss_suite/helpers/extensions.rb +0 -56
@@ -1,9 +1,10 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
|
-
# Copyright (c) Siemens AG
|
3
|
+
# Copyright (c) 2016-2022 Siemens AG
|
4
|
+
# Copyright (c) 2022 0llirocks
|
4
5
|
#
|
5
6
|
# Authors:
|
6
|
-
#
|
7
|
+
# 0llirocks <http://0lli.rocks>
|
7
8
|
#
|
8
9
|
# This work is licensed under the terms of the MIT license.
|
9
10
|
# See the LICENSE.md file in the top-level directory.
|
@@ -12,84 +13,81 @@ require_relative '../cvss_property'
|
|
12
13
|
require_relative '../cvss_metric'
|
13
14
|
require_relative '../helpers/cvss3_helper'
|
14
15
|
|
15
|
-
|
16
|
-
# This class represents a CVSS Base metric in version 3.
|
17
|
-
|
18
|
-
class Cvss3Base < CvssMetric
|
19
|
-
|
20
|
-
##
|
21
|
-
# Property of this metric
|
22
|
-
|
23
|
-
attr_reader :attack_vector, :attack_complexity, :privileges_required, :user_interaction,
|
24
|
-
:scope, :confidentiality, :integrity, :availability
|
25
|
-
|
16
|
+
module CvssSuite
|
26
17
|
##
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
18
|
+
# This class represents a CVSS Base metric in version 3.
|
19
|
+
class Cvss3Base < CvssMetric
|
20
|
+
##
|
21
|
+
# Property of this metric
|
22
|
+
attr_reader :attack_vector, :attack_complexity, :privileges_required, :user_interaction,
|
23
|
+
:scope, :confidentiality, :integrity, :availability
|
24
|
+
|
25
|
+
##
|
26
|
+
# Returns score of this metric
|
27
|
+
def score
|
28
|
+
privilege_score = Cvss3Helper.privileges_required_score @privileges_required, @scope
|
29
|
+
|
30
|
+
exploitability = 8.22 * @attack_vector.score * @attack_complexity.score *
|
31
|
+
privilege_score * @user_interaction.score
|
32
|
+
|
33
|
+
isc_base = 1 - ((1 - @confidentiality.score) * (1 - @integrity.score) * (1 - @availability.score))
|
34
|
+
|
35
|
+
impact_sub_score = if @scope.selected_value[:name] == 'Changed'
|
36
|
+
7.52 * (isc_base - 0.029) - 3.25 * (isc_base - 0.02)**15
|
37
|
+
else
|
38
|
+
6.42 * isc_base
|
39
|
+
end
|
40
|
+
|
41
|
+
return 0 if impact_sub_score <= 0
|
42
|
+
|
43
|
+
if @scope.selected_value[:name] == 'Changed'
|
44
|
+
[10, 1.08 * (impact_sub_score + exploitability)].min
|
45
|
+
else
|
46
|
+
[10, impact_sub_score + exploitability].min
|
47
|
+
end
|
41
48
|
end
|
42
49
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
50
|
+
private
|
51
|
+
|
52
|
+
def init_properties
|
53
|
+
@properties.push(@attack_vector =
|
54
|
+
CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV',
|
55
|
+
values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
56
|
+
{ name: 'Adjacent', abbreviation: 'A', weight: 0.62 },
|
57
|
+
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
58
|
+
{ name: 'Physical', abbreviation: 'P', weight: 0.2 }]))
|
59
|
+
@properties.push(@attack_complexity =
|
60
|
+
CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC',
|
61
|
+
values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
62
|
+
{ name: 'High', abbreviation: 'H', weight: 0.44 }]))
|
63
|
+
@properties.push(@privileges_required =
|
64
|
+
CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR',
|
65
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
66
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
67
|
+
{ name: 'High', abbreviation: 'H', weight: 0.27 }]))
|
68
|
+
@properties.push(@user_interaction =
|
69
|
+
CvssProperty.new(name: 'User Interaction', abbreviation: 'UI',
|
70
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
71
|
+
{ name: 'Required', abbreviation: 'R', weight: 0.62 }]))
|
72
|
+
@properties.push(@scope =
|
73
|
+
CvssProperty.new(name: 'Scope', abbreviation: 'S',
|
74
|
+
values: [{ name: 'Unchanged', abbreviation: 'U' },
|
75
|
+
{ name: 'Changed', abbreviation: 'C' }]))
|
76
|
+
@properties.push(@confidentiality =
|
77
|
+
CvssProperty.new(name: 'Confidentiality', abbreviation: 'C',
|
78
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
79
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
80
|
+
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
81
|
+
@properties.push(@integrity =
|
82
|
+
CvssProperty.new(name: 'Integrity', abbreviation: 'I',
|
83
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
84
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
85
|
+
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
86
|
+
@properties.push(@availability =
|
87
|
+
CvssProperty.new(name: 'Availability', abbreviation: 'A',
|
88
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
89
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
90
|
+
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
49
91
|
end
|
50
92
|
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def init_properties
|
55
|
-
@properties.push(@attack_vector =
|
56
|
-
CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV', position: [0],
|
57
|
-
choices: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
58
|
-
{ name: 'Adjacent', abbreviation: 'A', weight: 0.62 },
|
59
|
-
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
60
|
-
{ name: 'Physical', abbreviation: 'P', weight: 0.2 }]))
|
61
|
-
@properties.push(@attack_complexity =
|
62
|
-
CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC', position: [1],
|
63
|
-
choices: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
64
|
-
{ name: 'High', abbreviation: 'H', weight: 0.44 }]))
|
65
|
-
@properties.push(@privileges_required =
|
66
|
-
CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR', position: [2],
|
67
|
-
choices: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
68
|
-
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
69
|
-
{ name: 'High', abbreviation: 'H', weight: 0.27 }]))
|
70
|
-
@properties.push(@user_interaction =
|
71
|
-
CvssProperty.new(name: 'User Interaction', abbreviation: 'UI', position: [3],
|
72
|
-
choices: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
73
|
-
{ name: 'Required', abbreviation: 'R', weight: 0.62 }]))
|
74
|
-
@properties.push(@scope =
|
75
|
-
CvssProperty.new(name: 'Scope', abbreviation: 'S', position: [4],
|
76
|
-
choices: [{ name: 'Unchanged', abbreviation: 'U' },
|
77
|
-
{ name: 'Changed', abbreviation: 'C' }]))
|
78
|
-
@properties.push(@confidentiality =
|
79
|
-
CvssProperty.new(name: 'Confidentiality', abbreviation: 'C', position: [5],
|
80
|
-
choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
81
|
-
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
82
|
-
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
83
|
-
@properties.push(@integrity =
|
84
|
-
CvssProperty.new(name: 'Integrity', abbreviation: 'I', position: [6],
|
85
|
-
choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
86
|
-
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
87
|
-
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
88
|
-
@properties.push(@availability =
|
89
|
-
CvssProperty.new(name: 'Availability', abbreviation: 'A', position: [7],
|
90
|
-
choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
91
|
-
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
92
|
-
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
93
|
-
end
|
94
93
|
end
|
95
|
-
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
|
-
# Copyright (c) Siemens AG
|
3
|
+
# Copyright (c) 2016-2022 Siemens AG
|
4
|
+
# Copyright (c) 2022 0llirocks
|
4
5
|
#
|
5
6
|
# Authors:
|
6
|
-
#
|
7
|
+
# 0llirocks <http://0lli.rocks>
|
7
8
|
#
|
8
9
|
# This work is licensed under the terms of the MIT license.
|
9
10
|
# See the LICENSE.md file in the top-level directory.
|
@@ -12,133 +13,183 @@ require_relative '../cvss_property'
|
|
12
13
|
require_relative '../cvss_metric'
|
13
14
|
require_relative '../helpers/cvss3_helper'
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
module CvssSuite
|
17
|
+
##
|
18
|
+
# This class represents a CVSS Environmental metric in version 3.
|
19
|
+
class Cvss3Environmental < CvssMetric
|
20
|
+
##
|
21
|
+
# Property of this metric
|
22
|
+
attr_reader :confidentiality_requirement, :integrity_requirement, :availability_requirement,
|
23
|
+
:modified_attack_vector, :modified_attack_complexity, :modified_privileges_required,
|
24
|
+
:modified_user_interaction, :modified_scope, :modified_confidentiality,
|
25
|
+
:modified_integrity, :modified_availability
|
17
26
|
|
18
|
-
|
27
|
+
##
|
28
|
+
# Returns score of this metric
|
19
29
|
|
20
|
-
|
21
|
-
|
30
|
+
def score(base, temporal)
|
31
|
+
@base = base
|
22
32
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
33
|
+
merged_modified_privileges_required = @modified_privileges_required
|
34
|
+
if @modified_privileges_required.selected_value[:name] == 'Not Defined'
|
35
|
+
merged_modified_privileges_required = @base.privileges_required
|
36
|
+
end
|
27
37
|
|
28
|
-
|
29
|
-
|
38
|
+
merged_modified_scope = @modified_scope
|
39
|
+
if @modified_scope.selected_value[:name] == 'Not Defined'
|
40
|
+
merged_modified_scope = @base.scope
|
41
|
+
end
|
30
42
|
|
31
|
-
|
43
|
+
privilege_score = Cvss3Helper.privileges_required_score(merged_modified_privileges_required, merged_modified_scope)
|
32
44
|
|
33
|
-
|
45
|
+
modified_exploitability_sub_score = modified_exploitability_sub(privilege_score)
|
34
46
|
|
35
|
-
|
47
|
+
modified_impact_sub_score = modified_impact_sub(isc_modified)
|
36
48
|
|
37
|
-
|
49
|
+
return 0 if modified_impact_sub_score <= 0
|
38
50
|
|
39
|
-
|
51
|
+
calculate_score modified_impact_sub_score, modified_exploitability_sub_score, temporal.score
|
52
|
+
end
|
40
53
|
|
41
|
-
|
54
|
+
private
|
55
|
+
|
56
|
+
def init_properties
|
57
|
+
@properties.push(@confidentiality_requirement =
|
58
|
+
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
59
|
+
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
60
|
+
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
61
|
+
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
62
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
63
|
+
@properties.push(@integrity_requirement =
|
64
|
+
CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR',
|
65
|
+
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
66
|
+
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
67
|
+
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
68
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
69
|
+
|
70
|
+
@properties.push(@availability_requirement =
|
71
|
+
CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR',
|
72
|
+
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
73
|
+
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
74
|
+
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
75
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
76
|
+
@properties.push(@modified_attack_vector =
|
77
|
+
CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV',
|
78
|
+
values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
79
|
+
{ name: 'Adjacent Network', abbreviation: 'A', weight: 0.62 },
|
80
|
+
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
81
|
+
{ name: 'Physical', abbreviation: 'P', weight: 0.2 },
|
82
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
83
|
+
@properties.push(@modified_attack_complexity =
|
84
|
+
CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC',
|
85
|
+
values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
86
|
+
{ name: 'High', abbreviation: 'H', weight: 0.44 },
|
87
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
88
|
+
@properties.push(@modified_privileges_required =
|
89
|
+
CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR',
|
90
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
91
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
92
|
+
{ name: 'High', abbreviation: 'H', weight: 0.27 },
|
93
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
94
|
+
@properties.push(@modified_user_interaction =
|
95
|
+
CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI',
|
96
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
97
|
+
{ name: 'Required', abbreviation: 'R', weight: 0.62 },
|
98
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
99
|
+
@properties.push(@modified_scope =
|
100
|
+
CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS',
|
101
|
+
values: [{ name: 'Changed', abbreviation: 'C' },
|
102
|
+
{ name: 'Unchanged', abbreviation: 'U' },
|
103
|
+
{ name: 'Not Defined', abbreviation: 'X' }]))
|
104
|
+
@properties.push(@modified_confidentiality =
|
105
|
+
CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC',
|
106
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
107
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
108
|
+
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
109
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
110
|
+
@properties.push(@modified_integrity =
|
111
|
+
CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI',
|
112
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
113
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
114
|
+
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
115
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
116
|
+
@properties.push(@modified_availability =
|
117
|
+
CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA',
|
118
|
+
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
119
|
+
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
120
|
+
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
121
|
+
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
122
|
+
end
|
42
123
|
|
43
|
-
|
44
|
-
|
124
|
+
def modified_impact_sub(isc_modified)
|
125
|
+
if @modified_scope.selected_value[:name] == 'Not Defined'
|
126
|
+
if @base.scope.selected_value[:name] == 'Changed'
|
127
|
+
return 7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified - 0.02)**15
|
128
|
+
else
|
129
|
+
return 6.42 * isc_modified
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
if @modified_scope.selected_value[:name] == 'Changed'
|
134
|
+
7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified - 0.02)**15
|
135
|
+
else
|
136
|
+
6.42 * isc_modified
|
137
|
+
end
|
138
|
+
end
|
45
139
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
choices: [{name: 'Low', abbreviation: 'L', weight: 0.5},
|
52
|
-
{name: 'Medium', abbreviation: 'M', weight: 1.0},
|
53
|
-
{name: 'High', abbreviation: 'H', weight: 1.5},
|
54
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
55
|
-
@properties.push(@integrity_requirement =
|
56
|
-
CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR', position: [9, 12],
|
57
|
-
choices: [{name: 'Low', abbreviation: 'L', weight: 0.5},
|
58
|
-
{name: 'Medium', abbreviation: 'M', weight: 1.0},
|
59
|
-
{name: 'High', abbreviation: 'H', weight: 1.5},
|
60
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
61
|
-
|
62
|
-
@properties.push(@availability_requirement =
|
63
|
-
CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR', position: [10, 13],
|
64
|
-
choices: [{name: 'Low', abbreviation: 'L', weight: 0.5},
|
65
|
-
{name: 'Medium', abbreviation: 'M', weight: 1.0},
|
66
|
-
{name: 'High', abbreviation: 'H', weight: 1.5},
|
67
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
68
|
-
@properties.push(@modified_attack_vector =
|
69
|
-
CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV', position: [11, 14],
|
70
|
-
choices: [{name: 'Network', abbreviation: 'N', weight: 0.85},
|
71
|
-
{name: 'Adjacent Network', abbreviation: 'A', weight: 0.62},
|
72
|
-
{name: 'Local', abbreviation: 'L', weight: 0.55},
|
73
|
-
{name: 'Physical', abbreviation: 'P', weight: 0.2},
|
74
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
75
|
-
@properties.push(@modified_attack_complexity =
|
76
|
-
CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC', position: [12, 15],
|
77
|
-
choices: [{name: 'Low', abbreviation: 'L', weight: 0.77},
|
78
|
-
{name: 'High', abbreviation: 'H', weight: 0.44},
|
79
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
80
|
-
@properties.push(@modified_privileges_required =
|
81
|
-
CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR', position: [13, 16],
|
82
|
-
choices: [{name: 'None', abbreviation: 'N', weight: 0.85},
|
83
|
-
{name: 'Low', abbreviation: 'L', weight: 0.62},
|
84
|
-
{name: 'High', abbreviation: 'H', weight: 0.27},
|
85
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
86
|
-
@properties.push(@modified_user_interaction =
|
87
|
-
CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI', position: [14, 17],
|
88
|
-
choices: [{name: 'None', abbreviation: 'N', weight: 0.85},
|
89
|
-
{name: 'Required', abbreviation: 'R', weight: 0.62},
|
90
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
91
|
-
@properties.push(@modified_scope =
|
92
|
-
CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS', position: [15, 18],
|
93
|
-
choices: [{name: 'Changed', abbreviation: 'C'},
|
94
|
-
{name: 'Unchanged', abbreviation: 'U'}]))
|
95
|
-
@properties.push(@modified_confidentiality =
|
96
|
-
CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC', position: [16, 19],
|
97
|
-
choices: [{name: 'None', abbreviation: 'N', weight: 0},
|
98
|
-
{name: 'Low', abbreviation: 'L', weight: 0.22},
|
99
|
-
{name: 'High', abbreviation: 'H', weight: 0.56},
|
100
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
101
|
-
@properties.push(@modified_integrity =
|
102
|
-
CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI', position: [17, 20],
|
103
|
-
choices: [{name: 'None', abbreviation: 'N', weight: 0},
|
104
|
-
{name: 'Low', abbreviation: 'L', weight: 0.22},
|
105
|
-
{name: 'High', abbreviation: 'H', weight: 0.56},
|
106
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
107
|
-
@properties.push(@modified_availability =
|
108
|
-
CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA', position: [18, 21],
|
109
|
-
choices: [{name: 'None', abbreviation: 'N', weight: 0},
|
110
|
-
{name: 'Low', abbreviation: 'L', weight: 0.22},
|
111
|
-
{name: 'High', abbreviation: 'H', weight: 0.56},
|
112
|
-
{name: 'Not Defined', abbreviation: 'X', weight: 1}]))
|
113
|
-
end
|
140
|
+
def isc_modified
|
141
|
+
merged_modified_confidentiality = @modified_confidentiality
|
142
|
+
if @modified_confidentiality.selected_value[:name] == 'Not Defined'
|
143
|
+
merged_modified_confidentiality = @base.confidentiality
|
144
|
+
end
|
114
145
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
146
|
+
merged_modified_integrity = @modified_integrity
|
147
|
+
if @modified_integrity.selected_value[:name] == 'Not Defined'
|
148
|
+
merged_modified_integrity = @base.integrity
|
149
|
+
end
|
150
|
+
|
151
|
+
merged_modified_availability = @modified_availability
|
152
|
+
if @modified_availability.selected_value[:name] == 'Not Defined'
|
153
|
+
merged_modified_availability = @base.availability
|
154
|
+
end
|
155
|
+
|
156
|
+
confidentiality_score = 1 - merged_modified_confidentiality.score * @confidentiality_requirement.score
|
157
|
+
integrity_score = 1 - merged_modified_integrity.score * @integrity_requirement.score
|
158
|
+
availability_score = 1 - merged_modified_availability.score * @availability_requirement.score
|
159
|
+
|
160
|
+
[0.915, (1 - confidentiality_score * integrity_score * availability_score)].min
|
120
161
|
end
|
121
|
-
end
|
122
162
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
163
|
+
def modified_exploitability_sub(privilege_score)
|
164
|
+
merged_modified_attack_vector = @modified_attack_vector
|
165
|
+
if @modified_attack_vector.selected_value[:name] == 'Not Defined'
|
166
|
+
merged_modified_attack_vector = @base.attack_vector
|
167
|
+
end
|
127
168
|
|
128
|
-
|
129
|
-
|
169
|
+
merged_modified_attack_complexity = @modified_attack_complexity
|
170
|
+
if @modified_attack_complexity.selected_value[:name] == 'Not Defined'
|
171
|
+
merged_modified_attack_complexity = @base.attack_complexity
|
172
|
+
end
|
130
173
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
modified_exploitability_sub_score *= @modified_user_interaction.score
|
136
|
-
end
|
174
|
+
merged_modified_user_interaction = @modified_user_interaction
|
175
|
+
if @modified_user_interaction.selected_value[:name] == 'Not Defined'
|
176
|
+
merged_modified_user_interaction = @base.user_interaction
|
177
|
+
end
|
137
178
|
|
138
|
-
|
139
|
-
|
179
|
+
8.22 * merged_modified_attack_vector.score * merged_modified_attack_complexity.score *
|
180
|
+
privilege_score * merged_modified_user_interaction.score
|
181
|
+
end
|
140
182
|
|
141
|
-
|
183
|
+
def calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
|
184
|
+
if @modified_scope.selected_value[:name] == 'Not Defined'
|
185
|
+
factor = @base.scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
|
186
|
+
else
|
187
|
+
factor = @modified_scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
|
188
|
+
end
|
142
189
|
|
190
|
+
Cvss3Helper.round_up(
|
191
|
+
[factor * (modified_impact_sub_score + modified_exploitability_sub_score), 10].min
|
192
|
+
) * temporal_score
|
193
|
+
end
|
143
194
|
end
|
144
|
-
end
|
195
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
|
-
# Copyright (c) Siemens AG
|
3
|
+
# Copyright (c) 2016-2022 Siemens AG
|
4
|
+
# Copyright (c) 2022 0llirocks
|
4
5
|
#
|
5
6
|
# Authors:
|
6
|
-
#
|
7
|
+
# 0llirocks <http://0lli.rocks>
|
7
8
|
#
|
8
9
|
# This work is licensed under the terms of the MIT license.
|
9
10
|
# See the LICENSE.md file in the top-level directory.
|
@@ -11,47 +12,46 @@
|
|
11
12
|
require_relative '../cvss_property'
|
12
13
|
require_relative '../cvss_metric'
|
13
14
|
|
14
|
-
|
15
|
-
# This class represents a CVSS Temporal metric in version 3.
|
16
|
-
|
17
|
-
class Cvss3Temporal < CvssMetric
|
18
|
-
|
19
|
-
##
|
20
|
-
# Property of this metric
|
21
|
-
|
22
|
-
attr_reader :exploit_code_maturity, :remediation_level, :report_confidence
|
23
|
-
|
15
|
+
module CvssSuite
|
24
16
|
##
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
17
|
+
# This class represents a CVSS Temporal metric in version 3.
|
18
|
+
class Cvss3Temporal < CvssMetric
|
19
|
+
##
|
20
|
+
# Property of this metric
|
21
|
+
attr_reader :exploit_code_maturity, :remediation_level, :report_confidence
|
22
|
+
|
23
|
+
##
|
24
|
+
# Returns score of this metric
|
25
|
+
def score
|
26
|
+
return 1.0 unless valid?
|
27
|
+
|
28
|
+
@exploit_code_maturity.score * @remediation_level.score * @report_confidence.score
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def init_properties
|
34
|
+
@properties.push(@exploit_code_maturity =
|
35
|
+
CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E',
|
36
|
+
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
37
|
+
{ name: 'Unproven', abbreviation: 'U', weight: 0.91 },
|
38
|
+
{ name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
|
39
|
+
{ name: 'Functional', abbreviation: 'F', weight: 0.97 },
|
40
|
+
{ name: 'High', abbreviation: 'H', weight: 1.0 }]))
|
41
|
+
@properties.push(@remediation_level =
|
42
|
+
CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL',
|
43
|
+
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
44
|
+
{ name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
|
45
|
+
{ name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
|
46
|
+
{ name: 'Workaround', abbreviation: 'W', weight: 0.97 },
|
47
|
+
{ name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
|
48
|
+
|
49
|
+
@properties.push(@report_confidence =
|
50
|
+
CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC',
|
51
|
+
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
52
|
+
{ name: 'Unknown', abbreviation: 'U', weight: 0.92 },
|
53
|
+
{ name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
|
54
|
+
{ name: 'Confirmed', abbreviation: 'C', weight: 1.0 }]))
|
55
|
+
end
|
56
56
|
end
|
57
|
-
end
|
57
|
+
end
|