cvss-suite 1.1.0 → 1.2.2

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