cvss-suite 1.1.1 → 2.0.1

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