cvss-suite 4.1.3 → 5.0.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/{CHANGES.md → CHANGELOG.md} +36 -0
- data/LICENSE.md +2 -1
- data/README.md +80 -99
- data/docs/upgrading-to-5.md +117 -0
- data/docs/usage.md +234 -0
- data/lib/cvss_suite/cvss.rb +20 -3
- data/lib/cvss_suite/cvss2/cvss2.rb +3 -0
- data/lib/cvss_suite/cvss2/cvss2_base.rb +15 -4
- data/lib/cvss_suite/cvss2/cvss2_environmental.rb +3 -1
- data/lib/cvss_suite/cvss2/cvss2_temporal.rb +2 -0
- data/lib/cvss_suite/cvss3/cvss3.rb +4 -0
- data/lib/cvss_suite/cvss3/cvss3_base.rb +11 -1
- data/lib/cvss_suite/cvss3/cvss3_environmental.rb +43 -60
- data/lib/cvss_suite/cvss3/cvss3_temporal.rb +2 -0
- data/lib/cvss_suite/cvss31/cvss31.rb +4 -0
- data/lib/cvss_suite/cvss31/cvss31_base.rb +15 -1
- data/lib/cvss_suite/cvss31/cvss31_environmental.rb +46 -60
- data/lib/cvss_suite/cvss31/cvss31_temporal.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40.rb +10 -0
- data/lib/cvss_suite/cvss40/cvss40_all_up.rb +3 -1
- data/lib/cvss_suite/cvss40/cvss40_base.rb +8 -0
- data/lib/cvss_suite/cvss40/cvss40_calc_helper.rb +12 -8
- data/lib/cvss_suite/cvss40/cvss40_constants_levels.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_constants_macro_vector_lookup.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_constants_max_composed.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_constants_max_severity.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_environmental.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_environmental_security.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_supplemental.rb +2 -0
- data/lib/cvss_suite/cvss40/cvss40_threat.rb +2 -0
- data/lib/cvss_suite/cvss_31_and_before.rb +5 -3
- data/lib/cvss_suite/cvss_40_and_later.rb +3 -1
- data/lib/cvss_suite/cvss_metric.rb +4 -2
- data/lib/cvss_suite/cvss_property.rb +8 -6
- data/lib/cvss_suite/errors.rb +75 -9
- data/lib/cvss_suite/helpers/cvss31_helper.rb +6 -0
- data/lib/cvss_suite/helpers/cvss3_helper.rb +4 -0
- data/lib/cvss_suite/invalid_cvss.rb +26 -2
- data/lib/cvss_suite/version.rb +3 -1
- data/lib/cvss_suite.rb +86 -13
- metadata +12 -110
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -21
- data/.github/ISSUE_TEMPLATE/custom.md +0 -7
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
- data/.github/workflows/rspec.yml +0 -23
- data/.github/workflows/rubocop.yml +0 -21
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.rubocop.yml +0 -69
- data/.rubocop_todo.yml +0 -59
- data/CNAME +0 -1
- data/CODE_OF_CONDUCT.md +0 -79
- data/Gemfile +0 -9
- data/PULL_REQUEST_TEMPLATE.md +0 -24
- data/_config.yml +0 -1
- data/bin/console +0 -14
- data/bin/setup +0 -7
- data/cvss_suite.gemspec +0 -48
data/lib/cvss_suite/cvss.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -12,13 +14,17 @@ module CvssSuite
|
|
|
12
14
|
attr_reader :base
|
|
13
15
|
|
|
14
16
|
##
|
|
15
|
-
# Creates a new CVSS vector by a +vector+.
|
|
17
|
+
# Creates a new CVSS vector by a +vector+. CvssSuite.new also passes the
|
|
18
|
+
# +original+ string it was handed, because +vector+ reaches here with the
|
|
19
|
+
# CVSS:x.x/ prefix or the CVSS 2 parentheses already stripped, and an error
|
|
20
|
+
# has to name the vector the caller actually wrote.
|
|
16
21
|
#
|
|
17
22
|
# Raises an exception if it is called on Cvss class.
|
|
18
|
-
def initialize(vector)
|
|
23
|
+
def initialize(vector, original = vector)
|
|
19
24
|
raise CvssSuite::Errors::InvalidParentClass, 'Do not instantiate this class!' if instance_of? Cvss
|
|
20
25
|
|
|
21
26
|
@vector = vector
|
|
27
|
+
@original = original
|
|
22
28
|
@properties = []
|
|
23
29
|
extract_metrics
|
|
24
30
|
init_metrics
|
|
@@ -31,6 +37,9 @@ module CvssSuite
|
|
|
31
37
|
|
|
32
38
|
score = overall_score
|
|
33
39
|
|
|
40
|
+
# The explicit `<= 0.0` branch and the defensive `else` both yield 'None' by
|
|
41
|
+
# design (zero score vs. out-of-range guard); kept distinct for readability.
|
|
42
|
+
# rubocop:disable-next Lint/DuplicateBranch
|
|
34
43
|
if score <= 0.0
|
|
35
44
|
'None'
|
|
36
45
|
elsif (0.1..3.9).cover? score
|
|
@@ -65,7 +74,15 @@ module CvssSuite
|
|
|
65
74
|
end
|
|
66
75
|
|
|
67
76
|
def check_validity
|
|
68
|
-
raise CvssSuite::Errors::InvalidVector
|
|
77
|
+
raise CvssSuite::Errors::InvalidVector.for(rejected_vector) unless valid?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# What the caller passed, not the normalized form. #vector would be the
|
|
81
|
+
# tempting source, but it is lossy: Cvss2 does not restore the parentheses
|
|
82
|
+
# that prepare_cvss2_vector strips, so a rejected '(AV:N/AC:L)' would be
|
|
83
|
+
# reported as 'AV:N/AC:L', and a paren form it cannot parse at all as ''.
|
|
84
|
+
def rejected_vector
|
|
85
|
+
@original
|
|
69
86
|
end
|
|
70
87
|
|
|
71
88
|
def required_amount_of_properties
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -55,6 +57,7 @@ module CvssSuite
|
|
|
55
57
|
##
|
|
56
58
|
# Returns the Environmental Score of the CVSS vector.
|
|
57
59
|
def environmental_score
|
|
60
|
+
check_validity
|
|
58
61
|
return temporal_score unless @environmental.valid?
|
|
59
62
|
|
|
60
63
|
(@environmental.score @base, @temporal.score).round(1)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -19,6 +21,9 @@ module CvssSuite
|
|
|
19
21
|
# Returns the base score of the CVSS vector. The calculation is based on formula version 2.10 .
|
|
20
22
|
# See CVSS documentation for further information https://www.first.org/cvss/v2/guide#i3.2.1 .
|
|
21
23
|
#
|
|
24
|
+
# BaseScore = ((0.6 x Impact) + (0.4 x Exploitability) - 1.5) x f(Impact),
|
|
25
|
+
# where f(Impact) = 0 when Impact is 0, else 1.176.
|
|
26
|
+
#
|
|
22
27
|
# Takes +Security+ +Requirement+ +Impacts+ for calculating environmental score.
|
|
23
28
|
def score(sr_cr_score = 1, sr_ir_score = 1, sr_ar_score = 1)
|
|
24
29
|
impact = calc_impact(sr_cr_score, sr_ir_score, sr_ar_score)
|
|
@@ -73,17 +78,23 @@ module CvssSuite
|
|
|
73
78
|
{ name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
|
|
74
79
|
end
|
|
75
80
|
|
|
81
|
+
# CVSS v2, 3.2.1 -- Impact = 10.41 x (1 - (1-C) x (1-I) x (1-A)).
|
|
82
|
+
# The sr_* args carry the environmental Security Requirements (3.3.1),
|
|
83
|
+
# defaulting to 1 (= no environmental adjustment) for the plain base score.
|
|
84
|
+
# https://www.first.org/cvss/v2/guide#i3.2.1
|
|
76
85
|
def calc_impact(sr_cr_score = 1, sr_ir_score = 1, sr_ar_score = 1)
|
|
77
|
-
confidentiality_score = 1 - @confidentiality_impact.score * sr_cr_score
|
|
78
|
-
integrity_score = 1 - @integrity_impact.score * sr_ir_score
|
|
79
|
-
availability_score = 1 - @availability_impact.score * sr_ar_score
|
|
86
|
+
confidentiality_score = 1 - (@confidentiality_impact.score * sr_cr_score)
|
|
87
|
+
integrity_score = 1 - (@integrity_impact.score * sr_ir_score)
|
|
88
|
+
availability_score = 1 - (@availability_impact.score * sr_ar_score)
|
|
80
89
|
|
|
81
|
-
impact = 10.41 * (1 - confidentiality_score * integrity_score * availability_score)
|
|
90
|
+
impact = 10.41 * (1 - (confidentiality_score * integrity_score * availability_score))
|
|
82
91
|
return impact if sr_cr_score == 1 && sr_ir_score == 1 && sr_ar_score == 1
|
|
83
92
|
|
|
84
93
|
[10, impact].min
|
|
85
94
|
end
|
|
86
95
|
|
|
96
|
+
# CVSS v2, 3.2.1 -- Exploitability = 20 x AccessVector x AccessComplexity x Authentication.
|
|
97
|
+
# https://www.first.org/cvss/v2/guide#i3.2.1
|
|
87
98
|
def calc_exploitability
|
|
88
99
|
20 * @access_vector.score * @access_complexity.score * @authentication.score
|
|
89
100
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -25,7 +27,7 @@ module CvssSuite
|
|
|
25
27
|
@security_requirements_ar.score).round(1)
|
|
26
28
|
|
|
27
29
|
adjusted_temporal = (base_score * temporal_score.to_d).round(1).to_f
|
|
28
|
-
(adjusted_temporal + (10 - adjusted_temporal) * @collateral_damage_potential.score) * @target_distribution.score
|
|
30
|
+
(adjusted_temporal + ((10 - adjusted_temporal) * @collateral_damage_potential.score)) * @target_distribution.score
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
private
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -28,12 +30,14 @@ module CvssSuite
|
|
|
28
30
|
##
|
|
29
31
|
# Returns the Temporal Score of the CVSS vector.
|
|
30
32
|
def temporal_score
|
|
33
|
+
check_validity
|
|
31
34
|
Cvss3Helper.round_up(Cvss3Helper.round_up(@base.score) * @temporal.score)
|
|
32
35
|
end
|
|
33
36
|
|
|
34
37
|
##
|
|
35
38
|
# Returns the Environmental Score of the CVSS vector.
|
|
36
39
|
def environmental_score
|
|
40
|
+
check_validity
|
|
37
41
|
return temporal_score unless @environmental.valid?
|
|
38
42
|
|
|
39
43
|
Cvss3Helper.round_up(@environmental.score(@base, @temporal))
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -82,6 +84,9 @@ module CvssSuite
|
|
|
82
84
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
|
83
85
|
end
|
|
84
86
|
|
|
87
|
+
# CVSS v3.0 spec, 8.1 Base Metrics Equations -- Exploitability sub-score:
|
|
88
|
+
# 8.22 x AttackVector x AttackComplexity x PrivilegesRequired x UserInteraction
|
|
89
|
+
# https://www.first.org/cvss/v3.0/specification-document
|
|
85
90
|
def calc_exploitability
|
|
86
91
|
privilege_score = Cvss3Helper.privileges_required_score @privileges_required, @scope
|
|
87
92
|
|
|
@@ -89,11 +94,16 @@ module CvssSuite
|
|
|
89
94
|
privilege_score * @user_interaction.score
|
|
90
95
|
end
|
|
91
96
|
|
|
97
|
+
# CVSS v3.0 spec, 8.1 Base Metrics Equations -- Impact sub-score:
|
|
98
|
+
# ISCBase = 1 - [(1-C) x (1-I) x (1-A)]
|
|
99
|
+
# Scope Changed: 7.52 x (ISCBase - 0.029) - 3.25 x (ISCBase - 0.02)^15
|
|
100
|
+
# Scope Unchanged: 6.42 x ISCBase
|
|
101
|
+
# https://www.first.org/cvss/v3.0/specification-document
|
|
92
102
|
def calc_impact
|
|
93
103
|
isc_base = 1 - ((1 - @confidentiality.score) * (1 - @integrity.score) * (1 - @availability.score))
|
|
94
104
|
|
|
95
105
|
if @scope.selected_value[:name] == 'Changed'
|
|
96
|
-
7.52 * (isc_base - 0.029) - 3.25 * (isc_base - 0.02)**15
|
|
106
|
+
(7.52 * (isc_base - 0.029)) - (3.25 * ((isc_base - 0.02)**15))
|
|
97
107
|
else
|
|
98
108
|
6.42 * isc_base
|
|
99
109
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -24,17 +26,10 @@ module CvssSuite
|
|
|
24
26
|
def score(base, temporal)
|
|
25
27
|
@base = base
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
merged_modified_scope = @modified_scope
|
|
33
|
-
if @modified_scope.selected_value[:name] == 'Not Defined'
|
|
34
|
-
merged_modified_scope = @base.scope
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
privilege_score = Cvss3Helper.privileges_required_score(merged_modified_privileges_required, merged_modified_scope)
|
|
29
|
+
privilege_score = Cvss3Helper.privileges_required_score(
|
|
30
|
+
merged(@modified_privileges_required, @base.privileges_required),
|
|
31
|
+
merged(@modified_scope, @base.scope)
|
|
32
|
+
)
|
|
38
33
|
|
|
39
34
|
modified_exploitability_sub_score = modified_exploitability_sub(privilege_score)
|
|
40
35
|
|
|
@@ -47,6 +42,18 @@ module CvssSuite
|
|
|
47
42
|
|
|
48
43
|
private
|
|
49
44
|
|
|
45
|
+
# Returns the modified property, falling back to the base property when the
|
|
46
|
+
# modified metric is "Not Defined".
|
|
47
|
+
def merged(modified, base)
|
|
48
|
+
modified.selected_value[:name] == 'Not Defined' ? base : modified
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Whether the effective scope -- the modified scope, or the base scope when
|
|
52
|
+
# the modified scope is "Not Defined" -- is Changed.
|
|
53
|
+
def scope_changed?
|
|
54
|
+
merged(@modified_scope, @base.scope).selected_value[:name] == 'Changed'
|
|
55
|
+
end
|
|
56
|
+
|
|
50
57
|
def init_properties
|
|
51
58
|
@properties.push(@confidentiality_requirement =
|
|
52
59
|
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
|
@@ -115,71 +122,47 @@ module CvssSuite
|
|
|
115
122
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
|
116
123
|
end
|
|
117
124
|
|
|
125
|
+
# CVSS v3.0 spec, 8.3 Environmental -- ModifiedImpact from the MISS below:
|
|
126
|
+
# Scope Changed: 7.52 x (MISS - 0.029) - 3.25 x (MISS - 0.02)^15
|
|
127
|
+
# Scope Unchanged: 6.42 x MISS
|
|
128
|
+
# https://www.first.org/cvss/v3.0/specification-document
|
|
118
129
|
def modified_impact_sub(isc_modified)
|
|
119
|
-
if
|
|
120
|
-
|
|
121
|
-
return 7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified - 0.02)**15
|
|
122
|
-
else
|
|
123
|
-
return 6.42 * isc_modified
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
if @modified_scope.selected_value[:name] == 'Changed'
|
|
128
|
-
7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified - 0.02)**15
|
|
130
|
+
if scope_changed?
|
|
131
|
+
(7.52 * (isc_modified - 0.029)) - (3.25 * ((isc_modified - 0.02)**15))
|
|
129
132
|
else
|
|
130
133
|
6.42 * isc_modified
|
|
131
134
|
end
|
|
132
135
|
end
|
|
133
136
|
|
|
137
|
+
# CVSS v3.0 spec, 8.3 Environmental -- Modified Impact Sub-Score (MISS):
|
|
138
|
+
# Minimum(1 - [(1 - MC x CR) x (1 - MI x IR) x (1 - MA x AR)], 0.915)
|
|
134
139
|
def isc_modified
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
end
|
|
140
|
+
confidentiality = merged(@modified_confidentiality, @base.confidentiality)
|
|
141
|
+
integrity = merged(@modified_integrity, @base.integrity)
|
|
142
|
+
availability = merged(@modified_availability, @base.availability)
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
merged_modified_availability = @modified_availability
|
|
146
|
-
if @modified_availability.selected_value[:name] == 'Not Defined'
|
|
147
|
-
merged_modified_availability = @base.availability
|
|
148
|
-
end
|
|
144
|
+
confidentiality_score = 1 - (confidentiality.score * @confidentiality_requirement.score)
|
|
145
|
+
integrity_score = 1 - (integrity.score * @integrity_requirement.score)
|
|
146
|
+
availability_score = 1 - (availability.score * @availability_requirement.score)
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
integrity_score = 1 - merged_modified_integrity.score * @integrity_requirement.score
|
|
152
|
-
availability_score = 1 - merged_modified_availability.score * @availability_requirement.score
|
|
153
|
-
|
|
154
|
-
[0.915, (1 - confidentiality_score * integrity_score * availability_score)].min
|
|
148
|
+
[0.915, (1 - (confidentiality_score * integrity_score * availability_score))].min
|
|
155
149
|
end
|
|
156
150
|
|
|
151
|
+
# CVSS v3.0 spec, 8.3 Environmental -- ModifiedExploitability:
|
|
152
|
+
# 8.22 x MAV x MAC x MPR x MUI
|
|
157
153
|
def modified_exploitability_sub(privilege_score)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
end
|
|
154
|
+
attack_vector = merged(@modified_attack_vector, @base.attack_vector)
|
|
155
|
+
attack_complexity = merged(@modified_attack_complexity, @base.attack_complexity)
|
|
156
|
+
user_interaction = merged(@modified_user_interaction, @base.user_interaction)
|
|
162
157
|
|
|
163
|
-
|
|
164
|
-
if @modified_attack_complexity.selected_value[:name] == 'Not Defined'
|
|
165
|
-
merged_modified_attack_complexity = @base.attack_complexity
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
merged_modified_user_interaction = @modified_user_interaction
|
|
169
|
-
if @modified_user_interaction.selected_value[:name] == 'Not Defined'
|
|
170
|
-
merged_modified_user_interaction = @base.user_interaction
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
8.22 * merged_modified_attack_vector.score * merged_modified_attack_complexity.score *
|
|
174
|
-
privilege_score * merged_modified_user_interaction.score
|
|
158
|
+
8.22 * attack_vector.score * attack_complexity.score * privilege_score * user_interaction.score
|
|
175
159
|
end
|
|
176
160
|
|
|
161
|
+
# CVSS v3.0 spec, 8.3 Environmental -- ModifiedScore = Roundup(Minimum(
|
|
162
|
+
# [1.08 x] (ModifiedImpact + ModifiedExploitability), 10)) x TemporalScore.
|
|
163
|
+
# The 1.08 factor applies when the effective (modified) scope is Changed.
|
|
177
164
|
def calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
|
|
178
|
-
|
|
179
|
-
factor = @base.scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
|
|
180
|
-
else
|
|
181
|
-
factor = @modified_scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
|
|
182
|
-
end
|
|
165
|
+
factor = scope_changed? ? 1.08 : 1.0
|
|
183
166
|
|
|
184
167
|
Cvss3Helper.round_up(
|
|
185
168
|
[factor * (modified_impact_sub_score + modified_exploitability_sub_score), 10].min
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -32,6 +34,7 @@ module CvssSuite
|
|
|
32
34
|
# Returns the Temporal Score of the CVSS vector.
|
|
33
35
|
|
|
34
36
|
def temporal_score
|
|
37
|
+
check_validity
|
|
35
38
|
Cvss31Helper.round_up(Cvss31Helper.round_up(@base.score) * @temporal.score)
|
|
36
39
|
end
|
|
37
40
|
|
|
@@ -39,6 +42,7 @@ module CvssSuite
|
|
|
39
42
|
# Returns the Environmental Score of the CVSS vector.
|
|
40
43
|
|
|
41
44
|
def environmental_score
|
|
45
|
+
check_validity
|
|
42
46
|
return temporal_score unless @environmental.valid?
|
|
43
47
|
|
|
44
48
|
Cvss31Helper.round_up(@environmental.score(@base, @temporal))
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -83,6 +85,9 @@ module CvssSuite
|
|
|
83
85
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
|
84
86
|
end
|
|
85
87
|
|
|
88
|
+
# CVSS v3.1 spec, 7.1 Base Metrics Equations -- Exploitability sub-score:
|
|
89
|
+
# 8.22 x AttackVector x AttackComplexity x PrivilegesRequired x UserInteraction
|
|
90
|
+
# https://www.first.org/cvss/v3.1/specification-document
|
|
86
91
|
def calc_exploitability
|
|
87
92
|
privilege_score = Cvss3Helper.privileges_required_score(@privileges_required, @scope)
|
|
88
93
|
|
|
@@ -90,11 +95,20 @@ module CvssSuite
|
|
|
90
95
|
privilege_score * @user_interaction.score
|
|
91
96
|
end
|
|
92
97
|
|
|
98
|
+
# CVSS v3.1 spec, 7.1 Base Metrics Equations -- Impact sub-score:
|
|
99
|
+
# ISCBase = 1 - [(1-C) x (1-I) x (1-A)]
|
|
100
|
+
# Scope Changed: 7.52 x (ISCBase - 0.029) - 3.25 x (ISCBase - 0.02)^15
|
|
101
|
+
# Scope Unchanged: 6.42 x ISCBase
|
|
102
|
+
# NOTE: v3.1 Base deliberately keeps the exponent 15 from v3.0. Only the
|
|
103
|
+
# Environmental ModifiedImpact (spec 7.3, see cvss31_environmental.rb) changed
|
|
104
|
+
# to `x 0.9731` and exponent 13. The two are intentionally different -- do not
|
|
105
|
+
# "reconcile" them.
|
|
106
|
+
# https://www.first.org/cvss/v3.1/specification-document
|
|
93
107
|
def calc_impact
|
|
94
108
|
isc_base = 1 - ((1 - @confidentiality.score) * (1 - @integrity.score) * (1 - @availability.score))
|
|
95
109
|
|
|
96
110
|
if @scope.selected_value[:name] == 'Changed'
|
|
97
|
-
7.52 * (isc_base - 0.029) - 3.25 * (isc_base - 0.02)**15
|
|
111
|
+
(7.52 * (isc_base - 0.029)) - (3.25 * ((isc_base - 0.02)**15))
|
|
98
112
|
else
|
|
99
113
|
6.42 * isc_base
|
|
100
114
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -24,17 +26,10 @@ module CvssSuite
|
|
|
24
26
|
def score(base, temporal)
|
|
25
27
|
@base = base
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
merged_modified_scope = @modified_scope
|
|
33
|
-
if @modified_scope.selected_value[:name] == 'Not Defined'
|
|
34
|
-
merged_modified_scope = @base.scope
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
privilege_score = Cvss3Helper.privileges_required_score(merged_modified_privileges_required, merged_modified_scope)
|
|
29
|
+
privilege_score = Cvss3Helper.privileges_required_score(
|
|
30
|
+
merged(@modified_privileges_required, @base.privileges_required),
|
|
31
|
+
merged(@modified_scope, @base.scope)
|
|
32
|
+
)
|
|
38
33
|
|
|
39
34
|
modified_exploitability_sub_score = modified_exploitability_sub(privilege_score)
|
|
40
35
|
|
|
@@ -47,6 +42,18 @@ module CvssSuite
|
|
|
47
42
|
|
|
48
43
|
private
|
|
49
44
|
|
|
45
|
+
# Returns the modified property, falling back to the base property when the
|
|
46
|
+
# modified metric is "Not Defined".
|
|
47
|
+
def merged(modified, base)
|
|
48
|
+
modified.selected_value[:name] == 'Not Defined' ? base : modified
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Whether the effective scope -- the modified scope, or the base scope when
|
|
52
|
+
# the modified scope is "Not Defined" -- is Changed.
|
|
53
|
+
def scope_changed?
|
|
54
|
+
merged(@modified_scope, @base.scope).selected_value[:name] == 'Changed'
|
|
55
|
+
end
|
|
56
|
+
|
|
50
57
|
def init_properties
|
|
51
58
|
@properties.push(@confidentiality_requirement =
|
|
52
59
|
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
|
@@ -115,71 +122,50 @@ module CvssSuite
|
|
|
115
122
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
|
116
123
|
end
|
|
117
124
|
|
|
125
|
+
# CVSS v3.1 spec, 7.3 Environmental -- ModifiedImpact from the MISS below:
|
|
126
|
+
# Scope Changed: 7.52 x (MISS - 0.029) - 3.25 x (MISS x 0.9731 - 0.02)^13
|
|
127
|
+
# Scope Unchanged: 6.42 x MISS
|
|
128
|
+
# NOTE: v3.1 changed this Environmental sub-formula to `x 0.9731` and exponent
|
|
129
|
+
# 13; the v3.1 Base Impact (7.1, see cvss31_base.rb) still uses exponent 15.
|
|
130
|
+
# The difference is intentional per spec.
|
|
131
|
+
# https://www.first.org/cvss/v3.1/specification-document
|
|
118
132
|
def modified_impact_sub(isc_modified)
|
|
119
|
-
if
|
|
120
|
-
|
|
121
|
-
return 7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified * 0.9731 - 0.02)**13
|
|
122
|
-
else
|
|
123
|
-
return 6.42 * isc_modified
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
if @modified_scope.selected_value[:name] == 'Changed'
|
|
128
|
-
7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified * 0.9731 - 0.02)**13
|
|
133
|
+
if scope_changed?
|
|
134
|
+
(7.52 * (isc_modified - 0.029)) - (3.25 * (((isc_modified * 0.9731) - 0.02)**13))
|
|
129
135
|
else
|
|
130
136
|
6.42 * isc_modified
|
|
131
137
|
end
|
|
132
138
|
end
|
|
133
139
|
|
|
140
|
+
# CVSS v3.1 spec, 7.3 Environmental -- Modified Impact Sub-Score (MISS):
|
|
141
|
+
# Minimum(1 - [(1 - MC x CR) x (1 - MI x IR) x (1 - MA x AR)], 0.915)
|
|
134
142
|
def isc_modified
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
end
|
|
143
|
+
confidentiality = merged(@modified_confidentiality, @base.confidentiality)
|
|
144
|
+
integrity = merged(@modified_integrity, @base.integrity)
|
|
145
|
+
availability = merged(@modified_availability, @base.availability)
|
|
139
146
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
merged_modified_availability = @modified_availability
|
|
146
|
-
if @modified_availability.selected_value[:name] == 'Not Defined'
|
|
147
|
-
merged_modified_availability = @base.availability
|
|
148
|
-
end
|
|
147
|
+
confidentiality_score = 1 - (confidentiality.score * @confidentiality_requirement.score)
|
|
148
|
+
integrity_score = 1 - (integrity.score * @integrity_requirement.score)
|
|
149
|
+
availability_score = 1 - (availability.score * @availability_requirement.score)
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
integrity_score = 1 - merged_modified_integrity.score * @integrity_requirement.score
|
|
152
|
-
availability_score = 1 - merged_modified_availability.score * @availability_requirement.score
|
|
153
|
-
|
|
154
|
-
[0.915, (1 - confidentiality_score * integrity_score * availability_score)].min
|
|
151
|
+
[0.915, (1 - (confidentiality_score * integrity_score * availability_score))].min
|
|
155
152
|
end
|
|
156
153
|
|
|
154
|
+
# CVSS v3.1 spec, 7.3 Environmental -- ModifiedExploitability:
|
|
155
|
+
# 8.22 x MAV x MAC x MPR x MUI
|
|
157
156
|
def modified_exploitability_sub(privilege_score)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
end
|
|
157
|
+
attack_vector = merged(@modified_attack_vector, @base.attack_vector)
|
|
158
|
+
attack_complexity = merged(@modified_attack_complexity, @base.attack_complexity)
|
|
159
|
+
user_interaction = merged(@modified_user_interaction, @base.user_interaction)
|
|
162
160
|
|
|
163
|
-
|
|
164
|
-
if @modified_attack_complexity.selected_value[:name] == 'Not Defined'
|
|
165
|
-
merged_modified_attack_complexity = @base.attack_complexity
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
merged_modified_user_interaction = @modified_user_interaction
|
|
169
|
-
if @modified_user_interaction.selected_value[:name] == 'Not Defined'
|
|
170
|
-
merged_modified_user_interaction = @base.user_interaction
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
8.22 * merged_modified_attack_vector.score * merged_modified_attack_complexity.score *
|
|
174
|
-
privilege_score * merged_modified_user_interaction.score
|
|
161
|
+
8.22 * attack_vector.score * attack_complexity.score * privilege_score * user_interaction.score
|
|
175
162
|
end
|
|
176
163
|
|
|
164
|
+
# CVSS v3.1 spec, 7.3 Environmental -- ModifiedScore = Roundup(Minimum(
|
|
165
|
+
# [1.08 x] (ModifiedImpact + ModifiedExploitability), 10)) x TemporalScore.
|
|
166
|
+
# The 1.08 factor applies when the effective (modified) scope is Changed.
|
|
177
167
|
def calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
|
|
178
|
-
|
|
179
|
-
factor = @base.scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
|
|
180
|
-
else
|
|
181
|
-
factor = @modified_scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
|
|
182
|
-
end
|
|
168
|
+
factor = scope_changed? ? 1.08 : 1.0
|
|
183
169
|
|
|
184
170
|
Cvss31Helper.round_up(
|
|
185
171
|
[factor * (modified_impact_sub_score + modified_exploitability_sub_score), 10].min
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -28,6 +30,14 @@ module CvssSuite
|
|
|
28
30
|
"#{CvssSuite::CVSS_VECTOR_BEGINNINGS.find { |beginning| beginning[:version] == version }[:string]}#{@vector}"
|
|
29
31
|
end
|
|
30
32
|
|
|
33
|
+
##
|
|
34
|
+
# Returns the base score of the CVSS vector, ignoring threat and
|
|
35
|
+
# environmental metrics -- the base score as published by NVD/GHSA.
|
|
36
|
+
def base_score
|
|
37
|
+
check_validity
|
|
38
|
+
@base.score
|
|
39
|
+
end
|
|
40
|
+
|
|
31
41
|
private
|
|
32
42
|
|
|
33
43
|
def init_metrics
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -15,7 +17,7 @@ module CvssSuite
|
|
|
15
17
|
##
|
|
16
18
|
# Returns score of this metric
|
|
17
19
|
def score
|
|
18
|
-
Cvss40CalcHelper.new(@properties.
|
|
20
|
+
Cvss40CalcHelper.new(@properties.to_h { |p| [p.abbreviation, p.selected_value[:abbreviation]] }).score
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def initialize(properties, base, threat, environmental, environmental_security, supplemental)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
|
2
4
|
#
|
|
3
5
|
# This work is licensed under the terms of the MIT license.
|
|
@@ -18,6 +20,12 @@ module CvssSuite
|
|
|
18
20
|
:vulnerable_system_confidentiality, :vulnerable_system_integrity, :vulnerable_system_availability,
|
|
19
21
|
:subsequent_system_confidentiality, :subsequent_system_integrity, :subsequent_system_availability
|
|
20
22
|
|
|
23
|
+
##
|
|
24
|
+
# Returns the base score of these metrics, ignoring threat and environmental metrics.
|
|
25
|
+
def score
|
|
26
|
+
Cvss40CalcHelper.new(@properties.to_h { |p| [p.abbreviation, p.selected_value[:abbreviation]] }).score
|
|
27
|
+
end
|
|
28
|
+
|
|
21
29
|
private
|
|
22
30
|
|
|
23
31
|
def init_properties
|