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.
@@ -1,52 +1,61 @@
1
1
  # CVSS-Suite, a Ruby gem to manage the CVSS vector
2
2
  #
3
- # Copyright (c) Siemens AG, 2019
3
+ # Copyright (c) 2019-2022 Siemens AG
4
+ # Copyright (c) 2022 0llirocks
4
5
  #
5
6
  # Authors:
6
- # Oliver Hambörger <oliver.hamboerger@siemens.com>
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.
10
11
 
11
- require_relative '../../../lib/cvss_suite/cvss'
12
+ require_relative '../cvss'
12
13
  require_relative 'cvss31_base'
13
14
  require_relative 'cvss31_temporal'
14
15
  require_relative 'cvss31_environmental'
16
+ require_relative '../helpers/cvss31_helper'
15
17
 
16
- ##
17
- # This class represents a CVSS vector in version 3.1.
18
+ module CvssSuite
19
+ ##
20
+ # This class represents a CVSS vector in version 3.1.
21
+ class Cvss31 < Cvss
22
+ ##
23
+ # Returns the Version of the CVSS vector.
18
24
 
19
- class Cvss31 < Cvss
25
+ def version
26
+ 3.1
27
+ end
20
28
 
21
- ##
22
- # Returns the Base Score of the CVSS vector.
29
+ ##
30
+ # Returns the Base Score of the CVSS vector.
23
31
 
24
- def base_score
25
- check_validity
26
- @base.score.roundup
27
- end
32
+ def base_score
33
+ check_validity
34
+ Cvss31Helper.round_up(@base.score)
35
+ end
28
36
 
29
- ##
30
- # Returns the Temporal Score of the CVSS vector.
37
+ ##
38
+ # Returns the Temporal Score of the CVSS vector.
31
39
 
32
- def temporal_score
33
- (@base.score.roundup * @temporal.score).roundup
34
- end
40
+ def temporal_score
41
+ Cvss31Helper.round_up(Cvss31Helper.round_up(@base.score) * @temporal.score)
42
+ end
35
43
 
36
- ##
37
- # Returns the Environmental Score of the CVSS vector.
44
+ ##
45
+ # Returns the Environmental Score of the CVSS vector.
38
46
 
39
- def environmental_score
40
- return temporal_score unless @environmental.valid?
41
- (@environmental.score @temporal.score).roundup
42
- end
47
+ def environmental_score
48
+ return temporal_score unless @environmental.valid?
43
49
 
44
- private
50
+ Cvss31Helper.round_up(@environmental.score(@base, @temporal))
51
+ end
45
52
 
46
- def init_metrics
47
- @base = Cvss31Base.new(@properties)
48
- @temporal = Cvss31Temporal.new(@properties)
49
- @environmental = Cvss31Environmental.new(@properties)
50
- end
53
+ private
51
54
 
52
- end
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
@@ -1,9 +1,10 @@
1
1
  # CVSS-Suite, a Ruby gem to manage the CVSS vector
2
2
  #
3
- # Copyright (c) Siemens AG, 2019
3
+ # Copyright (c) 2019-2022 Siemens AG
4
+ # Copyright (c) 2022 0llirocks
4
5
  #
5
6
  # Authors:
6
- # Oliver Hambörger <oliver.hamboerger@siemens.com>
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,82 @@ 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.1.
17
-
18
- class Cvss31Base < CvssMetric
19
-
16
+ module CvssSuite
20
17
  ##
21
- # Property of this metric
18
+ # This class represents a CVSS Base metric in version 3.1.
19
+ class Cvss31Base < CvssMetric
20
+ ##
21
+ # Property of this metric
22
22
 
23
- attr_reader :attack_vector, :attack_complexity, :privileges_required, :user_interaction,
24
- :scope, :confidentiality, :integrity, :availability
23
+ attr_reader :attack_vector, :attack_complexity, :privileges_required, :user_interaction,
24
+ :scope, :confidentiality, :integrity, :availability
25
25
 
26
- ##
27
- # Returns score of this metric
26
+ ##
27
+ # Returns score of this metric
28
+ def score
29
+ privilege_score = Cvss3Helper.privileges_required_score(@privileges_required, @scope)
28
30
 
29
- def score
31
+ exploitability = 8.22 * @attack_vector.score * @attack_complexity.score *
32
+ privilege_score * @user_interaction.score
30
33
 
31
- privilege_score = Cvss3Helper.privileges_required_score @privileges_required, @scope
34
+ isc_base = 1 - ((1 - @confidentiality.score) * (1 - @integrity.score) * (1 - @availability.score))
32
35
 
33
- exploitability = 8.22 * @attack_vector.score * @attack_complexity.score * privilege_score * @user_interaction.score
36
+ impact_sub_score = if @scope.selected_value[: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
34
41
 
35
- isc_base = 1 - ((1 - @confidentiality.score) * (1 - @integrity.score) * (1 - @availability.score))
42
+ return 0 if impact_sub_score <= 0
36
43
 
37
- if @scope.selected_choice[:name] == 'Changed'
38
- impact_sub_score = 7.52 * (isc_base - 0.029) - 3.25 * (isc_base - 0.02)**15
39
- else
40
- impact_sub_score = 6.42 * isc_base
44
+ if @scope.selected_value[:name] == 'Changed'
45
+ [10, 1.08 * (impact_sub_score + exploitability)].min
46
+ else
47
+ [10, impact_sub_score + exploitability].min
48
+ end
41
49
  end
42
50
 
43
- return 0 if impact_sub_score <= 0
44
-
45
- if @scope.selected_choice[:name] == 'Changed'
46
- [10, 1.08 * (impact_sub_score + exploitability)].min
47
- else
48
- [10, impact_sub_score + exploitability].min
51
+ private
52
+
53
+ def init_properties
54
+ @properties.push(@attack_vector =
55
+ CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV',
56
+ values: [{ 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',
62
+ values: [{ 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',
66
+ values: [{ 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',
71
+ values: [{ 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',
75
+ values: [{ name: 'Unchanged', abbreviation: 'U' },
76
+ { name: 'Changed', abbreviation: 'C' }]))
77
+ @properties.push(@confidentiality =
78
+ CvssProperty.new(name: 'Confidentiality', abbreviation: 'C',
79
+ values: [{ 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',
84
+ values: [{ 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',
89
+ values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
90
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
91
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
49
92
  end
50
93
  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
94
  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, 2019
3
+ # Copyright (c) 2019-2022 Siemens AG
4
+ # Copyright (c) 2022 0llirocks
4
5
  #
5
6
  # Authors:
6
- # Oliver Hambörger <oliver.hamboerger@siemens.com>
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,134 +12,184 @@
11
12
  require_relative '../cvss_property'
12
13
  require_relative '../cvss_metric'
13
14
  require_relative '../helpers/cvss3_helper'
15
+ require_relative '../helpers/cvss31_helper'
14
16
 
15
- ##
16
- # This class represents a CVSS Environmental metric in version 3.1.
17
+ module CvssSuite
18
+ ##
19
+ # This class represents a CVSS Environmental metric in version 3.1.
20
+ class Cvss31Environmental < CvssMetric
21
+ ##
22
+ # Property of this metric
23
+ attr_reader :confidentiality_requirement, :integrity_requirement, :availability_requirement,
24
+ :modified_attack_vector, :modified_attack_complexity, :modified_privileges_required,
25
+ :modified_user_interaction, :modified_scope, :modified_confidentiality,
26
+ :modified_integrity, :modified_availability
17
27
 
18
- class Cvss31Environmental < CvssMetric
28
+ ##
29
+ # Returns score of this metric
30
+ def score(base, temporal)
31
+ @base = base
19
32
 
20
- ##
21
- # Property of this metric
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
22
37
 
23
- attr_reader :confidentiality_requirement, :integrity_requirement, :availability_requirement,
24
- :modified_attack_vector, :modified_attack_complexity, :modified_privileges_required,
25
- :modified_user_interaction, :modified_scope, :modified_confidentiality,
26
- :modified_integrity, :modified_availability
38
+ merged_modified_scope = @modified_scope
39
+ if @modified_scope.selected_value[:name] == 'Not Defined'
40
+ merged_modified_scope = @base.scope
41
+ end
27
42
 
28
- ##
29
- # Returns score of this metric
43
+ privilege_score = Cvss3Helper.privileges_required_score(merged_modified_privileges_required, merged_modified_scope)
30
44
 
31
- def score(temporal_score)
45
+ modified_exploitability_sub_score = modified_exploitability_sub(privilege_score)
32
46
 
33
- privilege_score = Cvss3Helper.privileges_required_score @modified_privileges_required, @modified_scope
47
+ modified_impact_sub_score = modified_impact_sub(isc_modified)
34
48
 
35
- modified_exploitability_sub_score = modified_exploitability_sub privilege_score
49
+ return 0 if modified_impact_sub_score <= 0
36
50
 
37
- isc_modified_score = isc_modified
51
+ calculate_score modified_impact_sub_score, modified_exploitability_sub_score, temporal.score
52
+ end
38
53
 
39
- modified_impact_sub_score = modified_impact_sub isc_modified_score
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
40
123
 
41
- return 0 if modified_impact_sub_score <= 0
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.9731 - 0.02)**13
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.9731 - 0.02)**13
135
+ else
136
+ 6.42 * isc_modified
137
+ end
138
+ end
42
139
 
43
- calculate_score modified_impact_sub_score, modified_exploitability_sub_score, temporal_score
44
- 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
45
145
 
46
- private
47
-
48
- def init_properties
49
- @properties.push(@confidentiality_requirement =
50
- CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR', position: [8, 11],
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
146
+ merged_modified_integrity = @modified_integrity
147
+ if @modified_integrity.selected_value[:name] == 'Not Defined'
148
+ merged_modified_integrity = @base.integrity
149
+ end
114
150
 
115
- def modified_impact_sub(isc_modified)
116
- if @modified_scope.selected_choice[:name] == 'Changed'
117
- 7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified * 0.9731 - 0.02)**13
118
- else
119
- 6.42 * isc_modified
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
- def isc_modified
124
- confidentiality_score = 1 - @modified_confidentiality.score * @confidentiality_requirement.score
125
- integrity_score = 1 - @modified_integrity.score * @integrity_requirement.score
126
- availability_score = 1 - @modified_availability.score * @availability_requirement.score
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
- [0.915, (1 - confidentiality_score * integrity_score * availability_score)].min
129
- end
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
- def modified_exploitability_sub(privilege_score)
132
- modified_exploitability_sub_score = 8.22 * @modified_attack_vector.score
133
- modified_exploitability_sub_score *= @modified_attack_complexity.score
134
- modified_exploitability_sub_score *= privilege_score
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
- def calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
139
- factor = @modified_scope.selected_choice[:name] == 'Changed' ? 1.08 : 1.0
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
- ([factor * (modified_impact_sub_score + modified_exploitability_sub_score), 10].min.round_up(1) * temporal_score)
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
+ Cvss31Helper.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