cvss-suite 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5917987479ecee6f2a020076b59751dda816e259d984a540bd1b6c0fb40b6422
4
- data.tar.gz: 5225e8afd1e553709590bc2bb1a60955c76462d62bbfe825bf2a2081d4647163
3
+ metadata.gz: d4f32e67e6919d58fbd35bc9af64a0af838e484ecfc28d17f83ebc623df9cff5
4
+ data.tar.gz: fc758c191bfbbd12e24e15d8b2d4fe1e012e4597ea0fcc28972bbe4bb9d8f66d
5
5
  SHA512:
6
- metadata.gz: 6824cf5f7f04f2f8eb5ef5613e61fd86b275b36fd316c7f4d4d60af8f9422176b1485eefe24de482e9dc98c328291ed2a7bccafdec3f03d353fae505c43d988c
7
- data.tar.gz: 2014e6368dea9deecd623d88a7f7b4d4c5367d1cb3a832ebdac3f6b47d5308b03e1129d157a11dad7e6ac93645ca971ad8dc4b8d85efdd83145f0f58883af6a4
6
+ metadata.gz: e6af1a297fb42858352914040f4d7d75923e3d6e88ed0ae14b85243252d58d169a8eddc900fd0ad1f5506a86bfc24f576e8d321fd7f2b4a01afa040ac9861ebc
7
+ data.tar.gz: fcb7590bd3fbe1eef4c8d5ea4f72e1cf04db96005034f74f9e764cb3853f1e0d39d73a6ba3c77416be69853f01a3c248d880997ae474534f5c8f2e7724a86ff6
@@ -15,7 +15,7 @@ jobs:
15
15
  uses: actions/setup-ruby@v1
16
16
  with:
17
17
  ruby-version: ${{ matrix.ruby }}
18
- - name: Build
18
+ - name: Install gems
19
19
  run: |
20
20
  gem install bundler -v ">= 1.10"
21
21
  bundle install --jobs 4 --retry 3
@@ -13,9 +13,9 @@ jobs:
13
13
  uses: actions/setup-ruby@v1
14
14
  with:
15
15
  ruby-version: 2.7
16
- - name: Build
16
+ - name: Install gems
17
17
  run: |
18
- gem install bundler -v "=> 1.10"
18
+ gem install bundler -v ">= 1.10"
19
19
  gem install rubocop
20
- - name: Run tests
20
+ - name: Run checks
21
21
  run: rubocop -F --fail-level C -f s
@@ -5,6 +5,39 @@ AllCops:
5
5
 
6
6
  Metrics/LineLength:
7
7
  Max: 120
8
+ Exclude:
9
+ - 'lib/cvss_suite/cvss3/cvss3_environmental.rb'
10
+ - 'lib/cvss_suite/cvss31/cvss31_environmental.rb'
11
+
12
+ Metrics/ClassLength:
13
+ Exclude:
14
+ - 'lib/cvss_suite/cvss3/cvss3_environmental.rb'
15
+ - 'lib/cvss_suite/cvss31/cvss31_environmental.rb'
16
+
17
+ Metrics/MethodLength:
18
+ Exclude:
19
+ - 'lib/cvss_suite/cvss3/cvss3_environmental.rb'
20
+ - 'lib/cvss_suite/cvss31/cvss31_environmental.rb'
21
+
22
+ Metrics/BlockLength:
23
+ Exclude:
24
+ - 'spec/cvss3/cvss3_spec.rb'
25
+ - 'spec/cvss31/cvss31_spec.rb'
26
+
27
+ Style/IfUnlessModifier:
28
+ Exclude:
29
+ - 'lib/cvss_suite/cvss3/cvss3_environmental.rb'
30
+ - 'lib/cvss_suite/cvss31/cvss31_environmental.rb'
31
+
32
+ Style/GuardClause:
33
+ Exclude:
34
+ - 'lib/cvss_suite/cvss3/cvss3_environmental.rb'
35
+ - 'lib/cvss_suite/cvss31/cvss31_environmental.rb'
36
+
37
+ Style/ConditionalAssignment:
38
+ Exclude:
39
+ - 'lib/cvss_suite/cvss3/cvss3_environmental.rb'
40
+ - 'lib/cvss_suite/cvss31/cvss31_environmental.rb'
8
41
 
9
42
  Style/FrozenStringLiteralComment:
10
43
  Enabled: false
data/CHANGES.md CHANGED
@@ -2,6 +2,11 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ## [2.0.1] - 2020-07-19
6
+
7
+ ### Fixes
8
+ Fixed an error that resulted in incorrect environmental score if modified attributes were not defined.
9
+
5
10
  ## [2.0.0] - 2020-05-10
6
11
 
7
12
  ### Breaking Changes
data/README.md CHANGED
@@ -104,8 +104,6 @@ Properties (Access Vector, Remediation Level, etc) do have a position attribute,
104
104
 
105
105
  Currently it is not possible to leave an attribute blank instead of ND/X. If you don't have a value for an attribute, please use ND/X instead.
106
106
 
107
- Because the documentation isn't clear on how to calculate the score if Modified Scope (CVSS 3.0 Environmental) is not defined, Modified Scope has to have a valid value (S/U).
108
-
109
107
  There is a possibility of implementations generating different scores (+/- 0,1) due to small floating-point inaccuracies. This can happen due to differences in floating point arithmetic between different languages and hardware platforms.
110
108
 
111
109
  ## Changelog
@@ -36,5 +36,5 @@ Besides calculating the Base, Temporal and Environmental Score, you are able to
36
36
  spec.add_development_dependency 'bundler', '>= 1.10'
37
37
  spec.add_development_dependency 'rspec', '~> 3.4'
38
38
  spec.add_development_dependency 'rspec-its', '~> 1.2'
39
- spec.add_development_dependency 'simplecov', '~> 0.11'
39
+ spec.add_development_dependency 'simplecov', '~> 0.18'
40
40
  end
@@ -41,33 +41,33 @@ module CvssSuite
41
41
  @properties.push(@access_vector =
42
42
  CvssProperty.new(name: 'Access Vector', abbreviation: 'AV', position: [0],
43
43
  values: [{ name: 'Network', abbreviation: 'N', weight: 1.0 },
44
- { name: 'Adjacent Network', abbreviation: 'A', weight: 0.646 },
45
- { name: 'Local', abbreviation: 'L', weight: 0.395 }]))
44
+ { name: 'Adjacent Network', abbreviation: 'A', weight: 0.646 },
45
+ { name: 'Local', abbreviation: 'L', weight: 0.395 }]))
46
46
  @properties.push(@access_complexity =
47
47
  CvssProperty.new(name: 'Access Complexity', abbreviation: 'AC', position: [1],
48
48
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.71 },
49
- { name: 'Medium', abbreviation: 'M', weight: 0.61 },
50
- { name: 'High', abbreviation: 'H', weight: 0.35 }]))
49
+ { name: 'Medium', abbreviation: 'M', weight: 0.61 },
50
+ { name: 'High', abbreviation: 'H', weight: 0.35 }]))
51
51
  @properties.push(@authentication =
52
52
  CvssProperty.new(name: 'Authentication', abbreviation: 'Au', position: [2],
53
53
  values: [{ name: 'None', abbreviation: 'N', weight: 0.704 },
54
- { name: 'Single', abbreviation: 'S', weight: 0.56 },
55
- { name: 'Multiple', abbreviation: 'M', weight: 0.45 }]))
54
+ { name: 'Single', abbreviation: 'S', weight: 0.56 },
55
+ { name: 'Multiple', abbreviation: 'M', weight: 0.45 }]))
56
56
  @properties.push(@confidentiality_impact =
57
57
  CvssProperty.new(name: 'Confidentiality Impact', abbreviation: 'C', position: [3],
58
58
  values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
59
- { name: 'Partial', abbreviation: 'P', weight: 0.275 },
60
- { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
59
+ { name: 'Partial', abbreviation: 'P', weight: 0.275 },
60
+ { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
61
61
  @properties.push(@integrity_impact =
62
62
  CvssProperty.new(name: 'Integrity Impact', abbreviation: 'I', position: [4],
63
63
  values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
64
- { name: 'Partial', abbreviation: 'P', weight: 0.275 },
65
- { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
64
+ { name: 'Partial', abbreviation: 'P', weight: 0.275 },
65
+ { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
66
66
  @properties.push(@availability_impact =
67
67
  CvssProperty.new(name: 'Availability Impact', abbreviation: 'A', position: [5],
68
68
  values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
69
- { name: 'Partial', abbreviation: 'P', weight: 0.275 },
70
- { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
69
+ { name: 'Partial', abbreviation: 'P', weight: 0.275 },
70
+ { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
71
71
  end
72
72
 
73
73
  def calc_impact(sr_cr_score, sr_ir_score, sr_ar_score)
@@ -37,36 +37,36 @@ module CvssSuite
37
37
  @properties.push(@collateral_damage_potential =
38
38
  CvssProperty.new(name: 'Collateral Damage Potential', abbreviation: 'CDP', position: [6, 9],
39
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 }]))
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
45
  @properties.push(@target_distribution =
46
46
  CvssProperty.new(name: 'Target Distribution', abbreviation: 'TD', position: [7, 10],
47
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 }]))
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
52
  @properties.push(@security_requirements_cr =
53
53
  CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR', position: [8, 11],
54
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 }]))
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
58
  @properties.push(@security_requirements_ir =
59
59
  CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR', position: [9, 12],
60
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 }]))
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
64
  @properties.push(@security_requirements_ar =
65
65
  CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR', position: [10, 13],
66
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 }]))
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
70
  end
71
71
  end
72
72
  end
@@ -33,24 +33,24 @@ module CvssSuite
33
33
  @properties.push(@exploitability =
34
34
  CvssProperty.new(name: 'Exploitability', abbreviation: 'E', position: [6],
35
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 }]))
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
40
  @properties.push(@remediation_level =
41
41
  CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL', position: [7],
42
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 }]))
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
47
 
48
48
  @properties.push(@report_confidence =
49
49
  CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC', position: [8],
50
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 }]))
51
+ { name: 'Unconfirmed', abbreviation: 'UC', weight: 0.9 },
52
+ { name: 'Uncorroborated', abbreviation: 'UR', weight: 0.95 },
53
+ { name: 'Confirmed', abbreviation: 'C', weight: 1 }]))
54
54
  end
55
55
  end
56
56
  end
@@ -41,7 +41,7 @@ module CvssSuite
41
41
  def environmental_score
42
42
  return temporal_score unless @environmental.valid?
43
43
 
44
- Cvss3Helper.round_up(@environmental.score(@temporal.score))
44
+ Cvss3Helper.round_up(@environmental.score(@base, @temporal))
45
45
  end
46
46
 
47
47
  private
@@ -52,41 +52,41 @@ module CvssSuite
52
52
  @properties.push(@attack_vector =
53
53
  CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV', position: [0],
54
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 }]))
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
58
  @properties.push(@attack_complexity =
59
59
  CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC', position: [1],
60
60
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
61
- { name: 'High', abbreviation: 'H', weight: 0.44 }]))
61
+ { name: 'High', abbreviation: 'H', weight: 0.44 }]))
62
62
  @properties.push(@privileges_required =
63
63
  CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR', position: [2],
64
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 }]))
65
+ { name: 'Low', abbreviation: 'L', weight: 0.62 },
66
+ { name: 'High', abbreviation: 'H', weight: 0.27 }]))
67
67
  @properties.push(@user_interaction =
68
68
  CvssProperty.new(name: 'User Interaction', abbreviation: 'UI', position: [3],
69
69
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
70
- { name: 'Required', abbreviation: 'R', weight: 0.62 }]))
70
+ { name: 'Required', abbreviation: 'R', weight: 0.62 }]))
71
71
  @properties.push(@scope =
72
72
  CvssProperty.new(name: 'Scope', abbreviation: 'S', position: [4],
73
73
  values: [{ name: 'Unchanged', abbreviation: 'U' },
74
- { name: 'Changed', abbreviation: 'C' }]))
74
+ { name: 'Changed', abbreviation: 'C' }]))
75
75
  @properties.push(@confidentiality =
76
76
  CvssProperty.new(name: 'Confidentiality', abbreviation: 'C', position: [5],
77
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 }]))
78
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
79
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
80
80
  @properties.push(@integrity =
81
81
  CvssProperty.new(name: 'Integrity', abbreviation: 'I', position: [6],
82
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 }]))
83
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
84
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
85
85
  @properties.push(@availability =
86
86
  CvssProperty.new(name: 'Availability', abbreviation: 'A', position: [7],
87
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 }]))
88
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
89
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
90
90
  end
91
91
  end
92
92
  end
@@ -26,8 +26,20 @@ module CvssSuite
26
26
  ##
27
27
  # Returns score of this metric
28
28
 
29
- def score(temporal_score)
30
- privilege_score = Cvss3Helper.privileges_required_score(@modified_privileges_required, @modified_scope)
29
+ def score(base, temporal)
30
+ @base = base
31
+
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
36
+
37
+ merged_modified_scope = @modified_scope
38
+ if @modified_scope.selected_value[:name] == 'Not Defined'
39
+ merged_modified_scope = @base.scope
40
+ end
41
+
42
+ privilege_score = Cvss3Helper.privileges_required_score(merged_modified_privileges_required, merged_modified_scope)
31
43
 
32
44
  modified_exploitability_sub_score = modified_exploitability_sub(privilege_score)
33
45
 
@@ -35,7 +47,7 @@ module CvssSuite
35
47
 
36
48
  return 0 if modified_impact_sub_score <= 0
37
49
 
38
- calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
50
+ calculate_score modified_impact_sub_score, modified_exploitability_sub_score, temporal.score
39
51
  end
40
52
 
41
53
  private
@@ -44,70 +56,79 @@ module CvssSuite
44
56
  @properties.push(@confidentiality_requirement =
45
57
  CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR', position: [8, 11],
46
58
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
47
- { name: 'Medium', abbreviation: 'M', weight: 1.0 },
48
- { name: 'High', abbreviation: 'H', weight: 1.5 },
49
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
59
+ { name: 'Medium', abbreviation: 'M', weight: 1.0 },
60
+ { name: 'High', abbreviation: 'H', weight: 1.5 },
61
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
50
62
  @properties.push(@integrity_requirement =
51
63
  CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR', position: [9, 12],
52
64
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
53
- { name: 'Medium', abbreviation: 'M', weight: 1.0 },
54
- { name: 'High', abbreviation: 'H', weight: 1.5 },
55
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
65
+ { name: 'Medium', abbreviation: 'M', weight: 1.0 },
66
+ { name: 'High', abbreviation: 'H', weight: 1.5 },
67
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
56
68
 
57
69
  @properties.push(@availability_requirement =
58
70
  CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR', position: [10, 13],
59
71
  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 }]))
72
+ { name: 'Medium', abbreviation: 'M', weight: 1.0 },
73
+ { name: 'High', abbreviation: 'H', weight: 1.5 },
74
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
63
75
  @properties.push(@modified_attack_vector =
64
76
  CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV', position: [11, 14],
65
77
  values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
66
- { name: 'Adjacent Network', abbreviation: 'A', weight: 0.62 },
67
- { name: 'Local', abbreviation: 'L', weight: 0.55 },
68
- { name: 'Physical', abbreviation: 'P', weight: 0.2 },
69
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
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 }]))
70
82
  @properties.push(@modified_attack_complexity =
71
83
  CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC', position: [12, 15],
72
84
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
73
- { name: 'High', abbreviation: 'H', weight: 0.44 },
74
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
85
+ { name: 'High', abbreviation: 'H', weight: 0.44 },
86
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
75
87
  @properties.push(@modified_privileges_required =
76
88
  CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR', position: [13, 16],
77
89
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
78
- { name: 'Low', abbreviation: 'L', weight: 0.62 },
79
- { name: 'High', abbreviation: 'H', weight: 0.27 },
80
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
90
+ { name: 'Low', abbreviation: 'L', weight: 0.62 },
91
+ { name: 'High', abbreviation: 'H', weight: 0.27 },
92
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
81
93
  @properties.push(@modified_user_interaction =
82
94
  CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI', position: [14, 17],
83
95
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
84
- { name: 'Required', abbreviation: 'R', weight: 0.62 },
85
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
96
+ { name: 'Required', abbreviation: 'R', weight: 0.62 },
97
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
86
98
  @properties.push(@modified_scope =
87
99
  CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS', position: [15, 18],
88
100
  values: [{ name: 'Changed', abbreviation: 'C' },
89
- { name: 'Unchanged', abbreviation: 'U' }]))
101
+ { name: 'Unchanged', abbreviation: 'U' },
102
+ { name: 'Not Defined', abbreviation: 'X' }]))
90
103
  @properties.push(@modified_confidentiality =
91
104
  CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC', position: [16, 19],
92
105
  values: [{ name: 'None', abbreviation: 'N', weight: 0 },
93
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
94
- { name: 'High', abbreviation: 'H', weight: 0.56 },
95
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
106
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
107
+ { name: 'High', abbreviation: 'H', weight: 0.56 },
108
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
96
109
  @properties.push(@modified_integrity =
97
110
  CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI', position: [17, 20],
98
111
  values: [{ name: 'None', abbreviation: 'N', weight: 0 },
99
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
100
- { name: 'High', abbreviation: 'H', weight: 0.56 },
101
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
112
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
113
+ { name: 'High', abbreviation: 'H', weight: 0.56 },
114
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
102
115
  @properties.push(@modified_availability =
103
116
  CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA', position: [18, 21],
104
117
  values: [{ name: 'None', abbreviation: 'N', weight: 0 },
105
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
106
- { name: 'High', abbreviation: 'H', weight: 0.56 },
107
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
118
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
119
+ { name: 'High', abbreviation: 'H', weight: 0.56 },
120
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
108
121
  end
109
122
 
110
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
+
111
132
  if @modified_scope.selected_value[:name] == 'Changed'
112
133
  7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified - 0.02)**15
113
134
  else
@@ -116,20 +137,54 @@ module CvssSuite
116
137
  end
117
138
 
118
139
  def isc_modified
119
- confidentiality_score = 1 - @modified_confidentiality.score * @confidentiality_requirement.score
120
- integrity_score = 1 - @modified_integrity.score * @integrity_requirement.score
121
- availability_score = 1 - @modified_availability.score * @availability_requirement.score
140
+ merged_modified_confidentiality = @modified_confidentiality
141
+ if @modified_confidentiality.selected_value[:name] == 'Not Defined'
142
+ merged_modified_confidentiality = @base.confidentiality
143
+ end
144
+
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
122
158
 
123
159
  [0.915, (1 - confidentiality_score * integrity_score * availability_score)].min
124
160
  end
125
161
 
126
162
  def modified_exploitability_sub(privilege_score)
127
- 8.22 * @modified_attack_vector.score * @modified_attack_complexity.score *
128
- privilege_score * @modified_user_interaction.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
167
+
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
172
+
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
177
+
178
+ 8.22 * merged_modified_attack_vector.score * merged_modified_attack_complexity.score *
179
+ privilege_score * merged_modified_user_interaction.score
129
180
  end
130
181
 
131
182
  def calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
132
- factor = @modified_scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
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
133
188
 
134
189
  Cvss3Helper.round_up(
135
190
  [factor * (modified_impact_sub_score + modified_exploitability_sub_score), 10].min
@@ -33,24 +33,24 @@ module CvssSuite
33
33
  @properties.push(@exploit_code_maturity =
34
34
  CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E', position: [8],
35
35
  values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
36
- { name: 'Unproven', abbreviation: 'U', weight: 0.91 },
37
- { name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
38
- { name: 'Functional', abbreviation: 'F', weight: 0.97 },
39
- { name: 'High', abbreviation: 'H', weight: 1.0 }]))
36
+ { name: 'Unproven', abbreviation: 'U', weight: 0.91 },
37
+ { name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
38
+ { name: 'Functional', abbreviation: 'F', weight: 0.97 },
39
+ { name: 'High', abbreviation: 'H', weight: 1.0 }]))
40
40
  @properties.push(@remediation_level =
41
41
  CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL', position: [9],
42
42
  values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
43
- { name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
44
- { name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
45
- { name: 'Workaround', abbreviation: 'W', weight: 0.97 },
46
- { name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
43
+ { name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
44
+ { name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
45
+ { name: 'Workaround', abbreviation: 'W', weight: 0.97 },
46
+ { name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
47
47
 
48
48
  @properties.push(@report_confidence =
49
49
  CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC', position: [10],
50
50
  values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
51
- { name: 'Unknown', abbreviation: 'U', weight: 0.92 },
52
- { name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
53
- { name: 'Confirmed', abbreviation: 'C', weight: 1.0 }]))
51
+ { name: 'Unknown', abbreviation: 'U', weight: 0.92 },
52
+ { name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
53
+ { name: 'Confirmed', abbreviation: 'C', weight: 1.0 }]))
54
54
  end
55
55
  end
56
56
  end
@@ -46,7 +46,7 @@ module CvssSuite
46
46
  def environmental_score
47
47
  return temporal_score unless @environmental.valid?
48
48
 
49
- Cvss31Helper.round_up(@environmental.score(@temporal.score))
49
+ Cvss31Helper.round_up(@environmental.score(@base, @temporal))
50
50
  end
51
51
 
52
52
  private
@@ -53,41 +53,41 @@ module CvssSuite
53
53
  @properties.push(@attack_vector =
54
54
  CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV', position: [0],
55
55
  values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
56
- { name: 'Adjacent', abbreviation: 'A', weight: 0.62 },
57
- { name: 'Local', abbreviation: 'L', weight: 0.55 },
58
- { name: 'Physical', abbreviation: 'P', weight: 0.2 }]))
56
+ { name: 'Adjacent', abbreviation: 'A', weight: 0.62 },
57
+ { name: 'Local', abbreviation: 'L', weight: 0.55 },
58
+ { name: 'Physical', abbreviation: 'P', weight: 0.2 }]))
59
59
  @properties.push(@attack_complexity =
60
60
  CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC', position: [1],
61
61
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
62
- { name: 'High', abbreviation: 'H', weight: 0.44 }]))
62
+ { name: 'High', abbreviation: 'H', weight: 0.44 }]))
63
63
  @properties.push(@privileges_required =
64
64
  CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR', position: [2],
65
65
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
66
- { name: 'Low', abbreviation: 'L', weight: 0.62 },
67
- { name: 'High', abbreviation: 'H', weight: 0.27 }]))
66
+ { name: 'Low', abbreviation: 'L', weight: 0.62 },
67
+ { name: 'High', abbreviation: 'H', weight: 0.27 }]))
68
68
  @properties.push(@user_interaction =
69
69
  CvssProperty.new(name: 'User Interaction', abbreviation: 'UI', position: [3],
70
70
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
71
- { name: 'Required', abbreviation: 'R', weight: 0.62 }]))
71
+ { name: 'Required', abbreviation: 'R', weight: 0.62 }]))
72
72
  @properties.push(@scope =
73
73
  CvssProperty.new(name: 'Scope', abbreviation: 'S', position: [4],
74
74
  values: [{ name: 'Unchanged', abbreviation: 'U' },
75
- { name: 'Changed', abbreviation: 'C' }]))
75
+ { name: 'Changed', abbreviation: 'C' }]))
76
76
  @properties.push(@confidentiality =
77
77
  CvssProperty.new(name: 'Confidentiality', abbreviation: 'C', position: [5],
78
78
  values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
79
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
80
- { name: 'High', abbreviation: 'H', weight: 0.56 }]))
79
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
80
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
81
81
  @properties.push(@integrity =
82
82
  CvssProperty.new(name: 'Integrity', abbreviation: 'I', position: [6],
83
83
  values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
84
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
85
- { name: 'High', abbreviation: 'H', weight: 0.56 }]))
84
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
85
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
86
86
  @properties.push(@availability =
87
87
  CvssProperty.new(name: 'Availability', abbreviation: 'A', position: [7],
88
88
  values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
89
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
90
- { name: 'High', abbreviation: 'H', weight: 0.56 }]))
89
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
90
+ { name: 'High', abbreviation: 'H', weight: 0.56 }]))
91
91
  end
92
92
  end
93
93
  end
@@ -26,8 +26,20 @@ module CvssSuite
26
26
 
27
27
  ##
28
28
  # Returns score of this metric
29
- def score(temporal_score)
30
- privilege_score = Cvss3Helper.privileges_required_score(@modified_privileges_required, @modified_scope)
29
+ def score(base, temporal)
30
+ @base = base
31
+
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
36
+
37
+ merged_modified_scope = @modified_scope
38
+ if @modified_scope.selected_value[:name] == 'Not Defined'
39
+ merged_modified_scope = @base.scope
40
+ end
41
+
42
+ privilege_score = Cvss3Helper.privileges_required_score(merged_modified_privileges_required, merged_modified_scope)
31
43
 
32
44
  modified_exploitability_sub_score = modified_exploitability_sub(privilege_score)
33
45
 
@@ -35,7 +47,7 @@ module CvssSuite
35
47
 
36
48
  return 0 if modified_impact_sub_score <= 0
37
49
 
38
- calculate_score modified_impact_sub_score, modified_exploitability_sub_score, temporal_score
50
+ calculate_score modified_impact_sub_score, modified_exploitability_sub_score, temporal.score
39
51
  end
40
52
 
41
53
  private
@@ -44,70 +56,79 @@ module CvssSuite
44
56
  @properties.push(@confidentiality_requirement =
45
57
  CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR', position: [8, 11],
46
58
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
47
- { name: 'Medium', abbreviation: 'M', weight: 1.0 },
48
- { name: 'High', abbreviation: 'H', weight: 1.5 },
49
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
59
+ { name: 'Medium', abbreviation: 'M', weight: 1.0 },
60
+ { name: 'High', abbreviation: 'H', weight: 1.5 },
61
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
50
62
  @properties.push(@integrity_requirement =
51
63
  CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR', position: [9, 12],
52
64
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
53
- { name: 'Medium', abbreviation: 'M', weight: 1.0 },
54
- { name: 'High', abbreviation: 'H', weight: 1.5 },
55
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
65
+ { name: 'Medium', abbreviation: 'M', weight: 1.0 },
66
+ { name: 'High', abbreviation: 'H', weight: 1.5 },
67
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
56
68
 
57
69
  @properties.push(@availability_requirement =
58
70
  CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR', position: [10, 13],
59
71
  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 }]))
72
+ { name: 'Medium', abbreviation: 'M', weight: 1.0 },
73
+ { name: 'High', abbreviation: 'H', weight: 1.5 },
74
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
63
75
  @properties.push(@modified_attack_vector =
64
76
  CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV', position: [11, 14],
65
77
  values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
66
- { name: 'Adjacent Network', abbreviation: 'A', weight: 0.62 },
67
- { name: 'Local', abbreviation: 'L', weight: 0.55 },
68
- { name: 'Physical', abbreviation: 'P', weight: 0.2 },
69
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
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 }]))
70
82
  @properties.push(@modified_attack_complexity =
71
83
  CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC', position: [12, 15],
72
84
  values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
73
- { name: 'High', abbreviation: 'H', weight: 0.44 },
74
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
85
+ { name: 'High', abbreviation: 'H', weight: 0.44 },
86
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
75
87
  @properties.push(@modified_privileges_required =
76
88
  CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR', position: [13, 16],
77
89
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
78
- { name: 'Low', abbreviation: 'L', weight: 0.62 },
79
- { name: 'High', abbreviation: 'H', weight: 0.27 },
80
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
90
+ { name: 'Low', abbreviation: 'L', weight: 0.62 },
91
+ { name: 'High', abbreviation: 'H', weight: 0.27 },
92
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
81
93
  @properties.push(@modified_user_interaction =
82
94
  CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI', position: [14, 17],
83
95
  values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
84
- { name: 'Required', abbreviation: 'R', weight: 0.62 },
85
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
96
+ { name: 'Required', abbreviation: 'R', weight: 0.62 },
97
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
86
98
  @properties.push(@modified_scope =
87
99
  CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS', position: [15, 18],
88
100
  values: [{ name: 'Changed', abbreviation: 'C' },
89
- { name: 'Unchanged', abbreviation: 'U' }]))
101
+ { name: 'Unchanged', abbreviation: 'U' },
102
+ { name: 'Not Defined', abbreviation: 'X' }]))
90
103
  @properties.push(@modified_confidentiality =
91
104
  CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC', position: [16, 19],
92
105
  values: [{ name: 'None', abbreviation: 'N', weight: 0 },
93
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
94
- { name: 'High', abbreviation: 'H', weight: 0.56 },
95
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
106
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
107
+ { name: 'High', abbreviation: 'H', weight: 0.56 },
108
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
96
109
  @properties.push(@modified_integrity =
97
110
  CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI', position: [17, 20],
98
111
  values: [{ name: 'None', abbreviation: 'N', weight: 0 },
99
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
100
- { name: 'High', abbreviation: 'H', weight: 0.56 },
101
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
112
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
113
+ { name: 'High', abbreviation: 'H', weight: 0.56 },
114
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
102
115
  @properties.push(@modified_availability =
103
116
  CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA', position: [18, 21],
104
117
  values: [{ name: 'None', abbreviation: 'N', weight: 0 },
105
- { name: 'Low', abbreviation: 'L', weight: 0.22 },
106
- { name: 'High', abbreviation: 'H', weight: 0.56 },
107
- { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
118
+ { name: 'Low', abbreviation: 'L', weight: 0.22 },
119
+ { name: 'High', abbreviation: 'H', weight: 0.56 },
120
+ { name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
108
121
  end
109
122
 
110
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.9731 - 0.02)**13
127
+ else
128
+ return 6.42 * isc_modified
129
+ end
130
+ end
131
+
111
132
  if @modified_scope.selected_value[:name] == 'Changed'
112
133
  7.52 * (isc_modified - 0.029) - 3.25 * (isc_modified * 0.9731 - 0.02)**13
113
134
  else
@@ -116,20 +137,54 @@ module CvssSuite
116
137
  end
117
138
 
118
139
  def isc_modified
119
- confidentiality_score = 1 - @modified_confidentiality.score * @confidentiality_requirement.score
120
- integrity_score = 1 - @modified_integrity.score * @integrity_requirement.score
121
- availability_score = 1 - @modified_availability.score * @availability_requirement.score
140
+ merged_modified_confidentiality = @modified_confidentiality
141
+ if @modified_confidentiality.selected_value[:name] == 'Not Defined'
142
+ merged_modified_confidentiality = @base.confidentiality
143
+ end
144
+
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
122
158
 
123
159
  [0.915, (1 - confidentiality_score * integrity_score * availability_score)].min
124
160
  end
125
161
 
126
162
  def modified_exploitability_sub(privilege_score)
127
- 8.22 * @modified_attack_vector.score * @modified_attack_complexity.score *
128
- privilege_score * @modified_user_interaction.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
167
+
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
172
+
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
177
+
178
+ 8.22 * merged_modified_attack_vector.score * merged_modified_attack_complexity.score *
179
+ privilege_score * merged_modified_user_interaction.score
129
180
  end
130
181
 
131
182
  def calculate_score(modified_impact_sub_score, modified_exploitability_sub_score, temporal_score)
132
- factor = @modified_scope.selected_value[:name] == 'Changed' ? 1.08 : 1.0
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
133
188
 
134
189
  Cvss31Helper.round_up(
135
190
  [factor * (modified_impact_sub_score + modified_exploitability_sub_score), 10].min
@@ -33,24 +33,24 @@ module CvssSuite
33
33
  @properties.push(@exploit_code_maturity =
34
34
  CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E', position: [8],
35
35
  values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
36
- { name: 'Unproven', abbreviation: 'U', weight: 0.91 },
37
- { name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
38
- { name: 'Functional', abbreviation: 'F', weight: 0.97 },
39
- { name: 'High', abbreviation: 'H', weight: 1.0 }]))
36
+ { name: 'Unproven', abbreviation: 'U', weight: 0.91 },
37
+ { name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
38
+ { name: 'Functional', abbreviation: 'F', weight: 0.97 },
39
+ { name: 'High', abbreviation: 'H', weight: 1.0 }]))
40
40
  @properties.push(@remediation_level =
41
41
  CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL', position: [9],
42
42
  values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
43
- { name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
44
- { name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
45
- { name: 'Workaround', abbreviation: 'W', weight: 0.97 },
46
- { name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
43
+ { name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
44
+ { name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
45
+ { name: 'Workaround', abbreviation: 'W', weight: 0.97 },
46
+ { name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
47
47
 
48
48
  @properties.push(@report_confidence =
49
49
  CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC', position: [10],
50
50
  values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
51
- { name: 'Unknown', abbreviation: 'U', weight: 0.92 },
52
- { name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
53
- { name: 'Confirmed', abbreviation: 'C', weight: 1.0 }]))
51
+ { name: 'Unknown', abbreviation: 'U', weight: 0.92 },
52
+ { name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
53
+ { name: 'Confirmed', abbreviation: 'C', weight: 1.0 }]))
54
54
  end
55
55
  end
56
56
  end
@@ -9,5 +9,5 @@
9
9
  # See the LICENSE.md file in the top-level directory.
10
10
 
11
11
  module CvssSuite
12
- VERSION = '2.0.0'.freeze
12
+ VERSION = '2.0.1'.freeze
13
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cvss-suite
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Hamboerger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-10 00:00:00.000000000 Z
11
+ date: 2020-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.11'
61
+ version: '0.18'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.11'
68
+ version: '0.18'
69
69
  description: |-
70
70
  This Ruby gem helps you to process the vector of the Common Vulnerability Scoring System (https://www.first.org/cvss/specification-document).
71
71
  Besides calculating the Base, Temporal and Environmental Score, you are able to extract the selected option.