cvss-suite 1.1.0 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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