cvss-suite 3.0.1 → 3.1.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 +4 -4
- data/.github/workflows/rspec.yml +2 -2
- data/CHANGES.md +13 -0
- data/README.md +6 -6
- data/cvss_suite.gemspec +5 -5
- data/lib/cvss_suite/cvss.rb +11 -29
- data/lib/cvss_suite/cvss3/cvss3.rb +7 -1
- data/lib/cvss_suite/cvss3/cvss3_base.rb +8 -8
- data/lib/cvss_suite/cvss3/cvss3_environmental.rb +11 -11
- data/lib/cvss_suite/cvss3/cvss3_temporal.rb +3 -3
- data/lib/cvss_suite/cvss31/cvss31.rb +7 -1
- data/lib/cvss_suite/cvss31/cvss31_base.rb +8 -8
- data/lib/cvss_suite/cvss31/cvss31_environmental.rb +11 -11
- data/lib/cvss_suite/cvss31/cvss31_temporal.rb +3 -3
- data/lib/cvss_suite/cvss_metric.rb +3 -1
- data/lib/cvss_suite/cvss_property.rb +11 -1
- data/lib/cvss_suite/version.rb +2 -2
- data/lib/cvss_suite.rb +37 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9474da7f6ca4ff4f9016d55b23714c1a5ca7e1a6a1fce6e4fb74fddbda9ea757
|
4
|
+
data.tar.gz: a581c242701b79f72ef2b97208ab9a0524942dcba8ddca75a0df7b5ef0b36c71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e3d15e35b59915b919faa4b99d3ff8a43d9b9ab231a9993e6b1876cd8b0c55ead7c73d0078a011245ebf40e6fa88f0abc9936eeb7af48c4972df8252d97e037
|
7
|
+
data.tar.gz: e061ce21c13ad6759b3b54f01d3330b339322213cf103fbe1350185da8dbf621d6a22ba211fd882fc174daec62ea42695a79ae37511adbe863b6b48fc75b4af2
|
data/.github/workflows/rspec.yml
CHANGED
@@ -8,9 +8,9 @@ jobs:
|
|
8
8
|
runs-on: ubuntu-latest
|
9
9
|
strategy:
|
10
10
|
matrix:
|
11
|
-
ruby: [ '2.6', '2.7', '3.0', '3.1' ]
|
11
|
+
ruby: [ '2.6', '2.7', '3.0', '3.1', '3.2' ]
|
12
12
|
steps:
|
13
|
-
- uses: actions/checkout@
|
13
|
+
- uses: actions/checkout@v3
|
14
14
|
- name: Set up ${{ matrix.ruby }}
|
15
15
|
uses: ruby/setup-ruby@v1
|
16
16
|
with:
|
data/CHANGES.md
CHANGED
@@ -2,6 +2,19 @@
|
|
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
|
+
## [3.1.1] - 2023-10-15
|
6
|
+
|
7
|
+
### Fixes
|
8
|
+
* CVSS prefix is missing in v3.1.0. Fixes [#33](https://github.com/0llirocks/cvss-suite/issues/33)
|
9
|
+
|
10
|
+
## [3.1.0] - 2022-09-27
|
11
|
+
|
12
|
+
### Fixes
|
13
|
+
* Metrics are no longer order-dependent. Fixes [#30](https://github.com/0llirocks/cvss-suite/issues/30)
|
14
|
+
|
15
|
+
### Improvements
|
16
|
+
* Temporal and Environmental metrics can now be partly omitted instead of setting them to X.
|
17
|
+
|
5
18
|
## [3.0.1] - 2022-03-13
|
6
19
|
|
7
20
|
### Notes
|
data/README.md
CHANGED
@@ -18,6 +18,12 @@ Add this line to your application's Gemfile:
|
|
18
18
|
gem 'cvss-suite'
|
19
19
|
```
|
20
20
|
|
21
|
+
Since the naming of this gem is not following the naming convention you can also add the following line to automatically require the gem:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'cvss-suite', require: 'cvss_suite'
|
25
|
+
```
|
26
|
+
|
21
27
|
And then execute:
|
22
28
|
|
23
29
|
$ bundle
|
@@ -100,14 +106,8 @@ valid = cvss.valid? # false
|
|
100
106
|
cvss.base_score # will throw CvssSuite::Errors::InvalidVector: Vector is not valid!
|
101
107
|
```
|
102
108
|
|
103
|
-
## Notable Features
|
104
|
-
|
105
|
-
Properties (Access Vector, Remediation Level, etc) do have a position attribute, with this they can be ordered the same way they appear in the vector.
|
106
|
-
|
107
109
|
## Known Issues
|
108
110
|
|
109
|
-
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.
|
110
|
-
|
111
111
|
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.
|
112
112
|
|
113
113
|
## Changelog
|
data/cvss_suite.gemspec
CHANGED
@@ -26,11 +26,11 @@ Gem::Specification.new do |spec|
|
|
26
26
|
Besides calculating the Base, Temporal and Environmental Score, you are able to extract the selected option.'
|
27
27
|
|
28
28
|
spec.metadata = {
|
29
|
-
'bug_tracker_uri'
|
30
|
-
'changelog_uri'
|
31
|
-
'documentation_uri' =>
|
32
|
-
'homepage_uri'
|
33
|
-
'source_code_uri'
|
29
|
+
'bug_tracker_uri' => 'https://github.com/0llirocks/cvss-suite/issues',
|
30
|
+
'changelog_uri' => 'https://github.com/0llirocks/cvss-suite/blob/master/CHANGES.md',
|
31
|
+
'documentation_uri' => "https://www.rubydoc.info/gems/cvss-suite/#{CvssSuite::VERSION}",
|
32
|
+
'homepage_uri' => 'https://cvss-suite.0lli.rocks',
|
33
|
+
'source_code_uri' => 'https://github.com/0llirocks/cvss-suite'
|
34
34
|
}
|
35
35
|
|
36
36
|
spec.required_ruby_version = '>= 2.6.0'
|
data/lib/cvss_suite/cvss.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
3
|
# Copyright (c) 2016-2022 Siemens AG
|
4
|
-
# Copyright (c) 2022 0llirocks
|
4
|
+
# Copyright (c) 2022-2023 0llirocks
|
5
5
|
#
|
6
6
|
# Authors:
|
7
7
|
# 0llirocks <http://0lli.rocks>
|
@@ -17,10 +17,6 @@ module CvssSuite
|
|
17
17
|
# Metric of a CVSS vector.
|
18
18
|
attr_reader :base, :temporal, :environmental
|
19
19
|
|
20
|
-
##
|
21
|
-
# Returns the vector itself.
|
22
|
-
attr_reader :vector
|
23
|
-
|
24
20
|
##
|
25
21
|
# Creates a new CVSS vector by a +vector+.
|
26
22
|
#
|
@@ -37,7 +33,7 @@ module CvssSuite
|
|
37
33
|
##
|
38
34
|
# Returns if CVSS vector is valid.
|
39
35
|
def valid?
|
40
|
-
if @amount_of_properties
|
36
|
+
if @amount_of_properties >= required_amount_of_properties
|
41
37
|
base = @base.valid?
|
42
38
|
temporal = @base.valid? && @temporal.valid?
|
43
39
|
environmental = @base.valid? && @environmental.valid?
|
@@ -80,44 +76,30 @@ module CvssSuite
|
|
80
76
|
base_score
|
81
77
|
end
|
82
78
|
|
79
|
+
##
|
80
|
+
# Returns the vector itself.
|
81
|
+
def vector
|
82
|
+
@vector.to_s
|
83
|
+
end
|
84
|
+
|
83
85
|
private
|
84
86
|
|
85
87
|
def extract_metrics
|
86
|
-
properties =
|
88
|
+
properties = @vector.split('/')
|
87
89
|
@amount_of_properties = properties.size
|
88
90
|
properties.each_with_index do |property, index|
|
89
91
|
property = property.split(':')
|
90
92
|
@properties.push({ name: property[0], selected: property[1], position: index })
|
91
93
|
end
|
94
|
+
@properties = [] if @properties.group_by { |p| p[:name] }.select { |_k, v| v.size > 1 }.length.positive?
|
92
95
|
end
|
93
96
|
|
94
97
|
def check_validity
|
95
98
|
raise CvssSuite::Errors::InvalidVector, 'Vector is not valid!' unless valid?
|
96
99
|
end
|
97
100
|
|
98
|
-
def prepared_vector
|
99
|
-
start_of_vector = @vector.index('AV')
|
100
|
-
|
101
|
-
if start_of_vector.nil?
|
102
|
-
''
|
103
|
-
elsif start_of_vector == 1
|
104
|
-
match_array = @vector.scan(/\((?>[^)(]+|\g<0>)*\)/)
|
105
|
-
if match_array.length == 1 && match_array[0] == @vector
|
106
|
-
@vector.slice!(0)
|
107
|
-
@vector.slice!(@vector.length - 1)
|
108
|
-
@vector
|
109
|
-
else
|
110
|
-
''
|
111
|
-
end
|
112
|
-
else
|
113
|
-
@vector[start_of_vector..]
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
101
|
def required_amount_of_properties
|
118
|
-
total = @base.count
|
119
|
-
total += @temporal.count if @temporal.valid?
|
120
|
-
total += @environmental.count if @environmental.valid?
|
102
|
+
total = @base.count
|
121
103
|
total || 0
|
122
104
|
end
|
123
105
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
3
|
# Copyright (c) 2016-2022 Siemens AG
|
4
|
-
# Copyright (c) 2022 0llirocks
|
4
|
+
# Copyright (c) 2022-2023 0llirocks
|
5
5
|
#
|
6
6
|
# Authors:
|
7
7
|
# 0llirocks <http://0lli.rocks>
|
@@ -45,6 +45,12 @@ module CvssSuite
|
|
45
45
|
Cvss3Helper.round_up(@environmental.score(@base, @temporal))
|
46
46
|
end
|
47
47
|
|
48
|
+
##
|
49
|
+
# Returns the vector itself.
|
50
|
+
def vector
|
51
|
+
"#{CvssSuite::CVSS_VECTOR_BEGINNINGS.find { |beginning| beginning[:version] == version }[:string]}#{@vector}"
|
52
|
+
end
|
53
|
+
|
48
54
|
private
|
49
55
|
|
50
56
|
def init_metrics
|
@@ -51,40 +51,40 @@ module CvssSuite
|
|
51
51
|
|
52
52
|
def init_properties
|
53
53
|
@properties.push(@attack_vector =
|
54
|
-
CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV',
|
54
|
+
CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV',
|
55
55
|
values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
56
56
|
{ name: 'Adjacent', abbreviation: 'A', weight: 0.62 },
|
57
57
|
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
58
58
|
{ name: 'Physical', abbreviation: 'P', weight: 0.2 }]))
|
59
59
|
@properties.push(@attack_complexity =
|
60
|
-
CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC',
|
60
|
+
CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC',
|
61
61
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
62
62
|
{ name: 'High', abbreviation: 'H', weight: 0.44 }]))
|
63
63
|
@properties.push(@privileges_required =
|
64
|
-
CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR',
|
64
|
+
CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR',
|
65
65
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
66
66
|
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
67
67
|
{ name: 'High', abbreviation: 'H', weight: 0.27 }]))
|
68
68
|
@properties.push(@user_interaction =
|
69
|
-
CvssProperty.new(name: 'User Interaction', abbreviation: 'UI',
|
69
|
+
CvssProperty.new(name: 'User Interaction', abbreviation: 'UI',
|
70
70
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
71
71
|
{ name: 'Required', abbreviation: 'R', weight: 0.62 }]))
|
72
72
|
@properties.push(@scope =
|
73
|
-
CvssProperty.new(name: 'Scope', abbreviation: 'S',
|
73
|
+
CvssProperty.new(name: 'Scope', abbreviation: 'S',
|
74
74
|
values: [{ name: 'Unchanged', abbreviation: 'U' },
|
75
75
|
{ name: 'Changed', abbreviation: 'C' }]))
|
76
76
|
@properties.push(@confidentiality =
|
77
|
-
CvssProperty.new(name: 'Confidentiality', abbreviation: 'C',
|
77
|
+
CvssProperty.new(name: 'Confidentiality', abbreviation: 'C',
|
78
78
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
79
79
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
80
80
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
81
81
|
@properties.push(@integrity =
|
82
|
-
CvssProperty.new(name: 'Integrity', abbreviation: 'I',
|
82
|
+
CvssProperty.new(name: 'Integrity', abbreviation: 'I',
|
83
83
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
84
84
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
85
85
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
86
86
|
@properties.push(@availability =
|
87
|
-
CvssProperty.new(name: 'Availability', abbreviation: 'A',
|
87
|
+
CvssProperty.new(name: 'Availability', abbreviation: 'A',
|
88
88
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
89
89
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
90
90
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
@@ -55,66 +55,66 @@ module CvssSuite
|
|
55
55
|
|
56
56
|
def init_properties
|
57
57
|
@properties.push(@confidentiality_requirement =
|
58
|
-
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
58
|
+
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
59
59
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
60
60
|
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
61
61
|
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
62
62
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
63
63
|
@properties.push(@integrity_requirement =
|
64
|
-
CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR',
|
64
|
+
CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR',
|
65
65
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
66
66
|
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
67
67
|
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
68
68
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
69
69
|
|
70
70
|
@properties.push(@availability_requirement =
|
71
|
-
CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR',
|
71
|
+
CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR',
|
72
72
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
73
73
|
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
74
74
|
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
75
75
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
76
76
|
@properties.push(@modified_attack_vector =
|
77
|
-
CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV',
|
77
|
+
CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV',
|
78
78
|
values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
79
79
|
{ name: 'Adjacent Network', abbreviation: 'A', weight: 0.62 },
|
80
80
|
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
81
81
|
{ name: 'Physical', abbreviation: 'P', weight: 0.2 },
|
82
82
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
83
83
|
@properties.push(@modified_attack_complexity =
|
84
|
-
CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC',
|
84
|
+
CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC',
|
85
85
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
86
86
|
{ name: 'High', abbreviation: 'H', weight: 0.44 },
|
87
87
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
88
88
|
@properties.push(@modified_privileges_required =
|
89
|
-
CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR',
|
89
|
+
CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR',
|
90
90
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
91
91
|
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
92
92
|
{ name: 'High', abbreviation: 'H', weight: 0.27 },
|
93
93
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
94
94
|
@properties.push(@modified_user_interaction =
|
95
|
-
CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI',
|
95
|
+
CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI',
|
96
96
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
97
97
|
{ name: 'Required', abbreviation: 'R', weight: 0.62 },
|
98
98
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
99
99
|
@properties.push(@modified_scope =
|
100
|
-
CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS',
|
100
|
+
CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS',
|
101
101
|
values: [{ name: 'Changed', abbreviation: 'C' },
|
102
102
|
{ name: 'Unchanged', abbreviation: 'U' },
|
103
103
|
{ name: 'Not Defined', abbreviation: 'X' }]))
|
104
104
|
@properties.push(@modified_confidentiality =
|
105
|
-
CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC',
|
105
|
+
CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC',
|
106
106
|
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
107
107
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
108
108
|
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
109
109
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
110
110
|
@properties.push(@modified_integrity =
|
111
|
-
CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI',
|
111
|
+
CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI',
|
112
112
|
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
113
113
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
114
114
|
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
115
115
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
116
116
|
@properties.push(@modified_availability =
|
117
|
-
CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA',
|
117
|
+
CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA',
|
118
118
|
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
119
119
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
120
120
|
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
@@ -32,14 +32,14 @@ module CvssSuite
|
|
32
32
|
|
33
33
|
def init_properties
|
34
34
|
@properties.push(@exploit_code_maturity =
|
35
|
-
CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E',
|
35
|
+
CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E',
|
36
36
|
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
37
37
|
{ name: 'Unproven', abbreviation: 'U', weight: 0.91 },
|
38
38
|
{ name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
|
39
39
|
{ name: 'Functional', abbreviation: 'F', weight: 0.97 },
|
40
40
|
{ name: 'High', abbreviation: 'H', weight: 1.0 }]))
|
41
41
|
@properties.push(@remediation_level =
|
42
|
-
CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL',
|
42
|
+
CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL',
|
43
43
|
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
44
44
|
{ name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
|
45
45
|
{ name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
|
@@ -47,7 +47,7 @@ module CvssSuite
|
|
47
47
|
{ name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
|
48
48
|
|
49
49
|
@properties.push(@report_confidence =
|
50
|
-
CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC',
|
50
|
+
CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC',
|
51
51
|
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
52
52
|
{ name: 'Unknown', abbreviation: 'U', weight: 0.92 },
|
53
53
|
{ name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
3
|
# Copyright (c) 2019-2022 Siemens AG
|
4
|
-
# Copyright (c) 2022 0llirocks
|
4
|
+
# Copyright (c) 2022-2023 0llirocks
|
5
5
|
#
|
6
6
|
# Authors:
|
7
7
|
# 0llirocks <http://0lli.rocks>
|
@@ -50,6 +50,12 @@ module CvssSuite
|
|
50
50
|
Cvss31Helper.round_up(@environmental.score(@base, @temporal))
|
51
51
|
end
|
52
52
|
|
53
|
+
##
|
54
|
+
# Returns the vector itself.
|
55
|
+
def vector
|
56
|
+
"#{CvssSuite::CVSS_VECTOR_BEGINNINGS.find { |beginning| beginning[:version] == version }[:string]}#{@vector}"
|
57
|
+
end
|
58
|
+
|
53
59
|
private
|
54
60
|
|
55
61
|
def init_metrics
|
@@ -52,40 +52,40 @@ module CvssSuite
|
|
52
52
|
|
53
53
|
def init_properties
|
54
54
|
@properties.push(@attack_vector =
|
55
|
-
CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV',
|
55
|
+
CvssProperty.new(name: 'Attack Vector', abbreviation: 'AV',
|
56
56
|
values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
57
57
|
{ name: 'Adjacent', abbreviation: 'A', weight: 0.62 },
|
58
58
|
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
59
59
|
{ name: 'Physical', abbreviation: 'P', weight: 0.2 }]))
|
60
60
|
@properties.push(@attack_complexity =
|
61
|
-
CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC',
|
61
|
+
CvssProperty.new(name: 'Attack Complexity', abbreviation: 'AC',
|
62
62
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
63
63
|
{ name: 'High', abbreviation: 'H', weight: 0.44 }]))
|
64
64
|
@properties.push(@privileges_required =
|
65
|
-
CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR',
|
65
|
+
CvssProperty.new(name: 'Privileges Required', abbreviation: 'PR',
|
66
66
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
67
67
|
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
68
68
|
{ name: 'High', abbreviation: 'H', weight: 0.27 }]))
|
69
69
|
@properties.push(@user_interaction =
|
70
|
-
CvssProperty.new(name: 'User Interaction', abbreviation: 'UI',
|
70
|
+
CvssProperty.new(name: 'User Interaction', abbreviation: 'UI',
|
71
71
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
72
72
|
{ name: 'Required', abbreviation: 'R', weight: 0.62 }]))
|
73
73
|
@properties.push(@scope =
|
74
|
-
CvssProperty.new(name: 'Scope', abbreviation: 'S',
|
74
|
+
CvssProperty.new(name: 'Scope', abbreviation: 'S',
|
75
75
|
values: [{ name: 'Unchanged', abbreviation: 'U' },
|
76
76
|
{ name: 'Changed', abbreviation: 'C' }]))
|
77
77
|
@properties.push(@confidentiality =
|
78
|
-
CvssProperty.new(name: 'Confidentiality', abbreviation: 'C',
|
78
|
+
CvssProperty.new(name: 'Confidentiality', abbreviation: 'C',
|
79
79
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
80
80
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
81
81
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
82
82
|
@properties.push(@integrity =
|
83
|
-
CvssProperty.new(name: 'Integrity', abbreviation: 'I',
|
83
|
+
CvssProperty.new(name: 'Integrity', abbreviation: 'I',
|
84
84
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
85
85
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
86
86
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
87
87
|
@properties.push(@availability =
|
88
|
-
CvssProperty.new(name: 'Availability', abbreviation: 'A',
|
88
|
+
CvssProperty.new(name: 'Availability', abbreviation: 'A',
|
89
89
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
|
90
90
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
91
91
|
{ name: 'High', abbreviation: 'H', weight: 0.56 }]))
|
@@ -55,66 +55,66 @@ module CvssSuite
|
|
55
55
|
|
56
56
|
def init_properties
|
57
57
|
@properties.push(@confidentiality_requirement =
|
58
|
-
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
58
|
+
CvssProperty.new(name: 'Confidentiality Requirement', abbreviation: 'CR',
|
59
59
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
60
60
|
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
61
61
|
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
62
62
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
63
63
|
@properties.push(@integrity_requirement =
|
64
|
-
CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR',
|
64
|
+
CvssProperty.new(name: 'Integrity Requirement', abbreviation: 'IR',
|
65
65
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
66
66
|
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
67
67
|
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
68
68
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
69
69
|
|
70
70
|
@properties.push(@availability_requirement =
|
71
|
-
CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR',
|
71
|
+
CvssProperty.new(name: 'Availability Requirement', abbreviation: 'AR',
|
72
72
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.5 },
|
73
73
|
{ name: 'Medium', abbreviation: 'M', weight: 1.0 },
|
74
74
|
{ name: 'High', abbreviation: 'H', weight: 1.5 },
|
75
75
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
76
76
|
@properties.push(@modified_attack_vector =
|
77
|
-
CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV',
|
77
|
+
CvssProperty.new(name: 'Modified Attack Vector', abbreviation: 'MAV',
|
78
78
|
values: [{ name: 'Network', abbreviation: 'N', weight: 0.85 },
|
79
79
|
{ name: 'Adjacent Network', abbreviation: 'A', weight: 0.62 },
|
80
80
|
{ name: 'Local', abbreviation: 'L', weight: 0.55 },
|
81
81
|
{ name: 'Physical', abbreviation: 'P', weight: 0.2 },
|
82
82
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
83
83
|
@properties.push(@modified_attack_complexity =
|
84
|
-
CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC',
|
84
|
+
CvssProperty.new(name: 'Modified Attack Complexity', abbreviation: 'MAC',
|
85
85
|
values: [{ name: 'Low', abbreviation: 'L', weight: 0.77 },
|
86
86
|
{ name: 'High', abbreviation: 'H', weight: 0.44 },
|
87
87
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
88
88
|
@properties.push(@modified_privileges_required =
|
89
|
-
CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR',
|
89
|
+
CvssProperty.new(name: 'Modified Privileges Required', abbreviation: 'MPR',
|
90
90
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
91
91
|
{ name: 'Low', abbreviation: 'L', weight: 0.62 },
|
92
92
|
{ name: 'High', abbreviation: 'H', weight: 0.27 },
|
93
93
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
94
94
|
@properties.push(@modified_user_interaction =
|
95
|
-
CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI',
|
95
|
+
CvssProperty.new(name: 'Modified User Interaction', abbreviation: 'MUI',
|
96
96
|
values: [{ name: 'None', abbreviation: 'N', weight: 0.85 },
|
97
97
|
{ name: 'Required', abbreviation: 'R', weight: 0.62 },
|
98
98
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
99
99
|
@properties.push(@modified_scope =
|
100
|
-
CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS',
|
100
|
+
CvssProperty.new(name: 'Modified Scope', abbreviation: 'MS',
|
101
101
|
values: [{ name: 'Changed', abbreviation: 'C' },
|
102
102
|
{ name: 'Unchanged', abbreviation: 'U' },
|
103
103
|
{ name: 'Not Defined', abbreviation: 'X' }]))
|
104
104
|
@properties.push(@modified_confidentiality =
|
105
|
-
CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC',
|
105
|
+
CvssProperty.new(name: 'Modified Confidentiality', abbreviation: 'MC',
|
106
106
|
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
107
107
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
108
108
|
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
109
109
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
110
110
|
@properties.push(@modified_integrity =
|
111
|
-
CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI',
|
111
|
+
CvssProperty.new(name: 'Modified Integrity', abbreviation: 'MI',
|
112
112
|
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
113
113
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
114
114
|
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
115
115
|
{ name: 'Not Defined', abbreviation: 'X', weight: 1 }]))
|
116
116
|
@properties.push(@modified_availability =
|
117
|
-
CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA',
|
117
|
+
CvssProperty.new(name: 'Modified Availability', abbreviation: 'MA',
|
118
118
|
values: [{ name: 'None', abbreviation: 'N', weight: 0 },
|
119
119
|
{ name: 'Low', abbreviation: 'L', weight: 0.22 },
|
120
120
|
{ name: 'High', abbreviation: 'H', weight: 0.56 },
|
@@ -32,14 +32,14 @@ module CvssSuite
|
|
32
32
|
|
33
33
|
def init_properties
|
34
34
|
@properties.push(@exploit_code_maturity =
|
35
|
-
CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E',
|
35
|
+
CvssProperty.new(name: 'Exploit Code Maturity', abbreviation: 'E',
|
36
36
|
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
37
37
|
{ name: 'Unproven', abbreviation: 'U', weight: 0.91 },
|
38
38
|
{ name: 'Proof-of-Concept', abbreviation: 'P', weight: 0.94 },
|
39
39
|
{ name: 'Functional', abbreviation: 'F', weight: 0.97 },
|
40
40
|
{ name: 'High', abbreviation: 'H', weight: 1.0 }]))
|
41
41
|
@properties.push(@remediation_level =
|
42
|
-
CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL',
|
42
|
+
CvssProperty.new(name: 'Remediation Level', abbreviation: 'RL',
|
43
43
|
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
44
44
|
{ name: 'Official Fix', abbreviation: 'O', weight: 0.95 },
|
45
45
|
{ name: 'Temporary Fix', abbreviation: 'T', weight: 0.96 },
|
@@ -47,7 +47,7 @@ module CvssSuite
|
|
47
47
|
{ name: 'Unavailable', abbreviation: 'U', weight: 1.0 }]))
|
48
48
|
|
49
49
|
@properties.push(@report_confidence =
|
50
|
-
CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC',
|
50
|
+
CvssProperty.new(name: 'Report Confidence', abbreviation: 'RC',
|
51
51
|
values: [{ name: 'Not Defined', abbreviation: 'X', weight: 1.0 },
|
52
52
|
{ name: 'Unknown', abbreviation: 'U', weight: 0.92 },
|
53
53
|
{ name: 'Reasonable', abbreviation: 'R', weight: 0.96 },
|
@@ -41,10 +41,12 @@ module CvssSuite
|
|
41
41
|
def extract_selected_values_from(selected_properties)
|
42
42
|
selected_properties.each do |selected_property|
|
43
43
|
property = @properties.detect do |p|
|
44
|
-
p.abbreviation == selected_property[:name] &&
|
44
|
+
p.abbreviation == selected_property[:name] &&
|
45
|
+
(p.position&.include?(selected_property[:position]) || p.position.nil?)
|
45
46
|
end
|
46
47
|
property&.set_selected_value selected_property[:selected]
|
47
48
|
end
|
49
|
+
@properties.reject(&:valid?).each(&:set_default_value)
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|
@@ -22,7 +22,7 @@ module CvssSuite
|
|
22
22
|
|
23
23
|
def initialize(property)
|
24
24
|
@property = property
|
25
|
-
@property[:default_value] ||= 'Not
|
25
|
+
@property[:default_value] ||= 'Not Defined'
|
26
26
|
end
|
27
27
|
|
28
28
|
##
|
@@ -83,5 +83,15 @@ module CvssSuite
|
|
83
83
|
end
|
84
84
|
@selected_value = values.detect { |value| value[:selected] }
|
85
85
|
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Sets the default value.
|
89
|
+
|
90
|
+
def set_default_value
|
91
|
+
values.each do |value|
|
92
|
+
value[:selected] = value[:abbreviation].eql?('X')
|
93
|
+
end
|
94
|
+
@selected_value = values.detect { |value| value[:selected] }
|
95
|
+
end
|
86
96
|
end
|
87
97
|
end
|
data/lib/cvss_suite/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# CVSS-Suite, a Ruby gem to manage the CVSS vector
|
2
2
|
#
|
3
3
|
# Copyright (c) 2016-2022 Siemens AG
|
4
|
-
# Copyright (c) 2022 0llirocks
|
4
|
+
# Copyright (c) 2022-2023 0llirocks
|
5
5
|
#
|
6
6
|
# Authors:
|
7
7
|
# 0llirocks <http://0lli.rocks>
|
@@ -10,5 +10,5 @@
|
|
10
10
|
# See the LICENSE.md file in the top-level directory.
|
11
11
|
|
12
12
|
module CvssSuite
|
13
|
-
VERSION = '3.
|
13
|
+
VERSION = '3.1.1'.freeze
|
14
14
|
end
|
data/lib/cvss_suite.rb
CHANGED
@@ -34,11 +34,11 @@ module CvssSuite
|
|
34
34
|
@vector_string = vector
|
35
35
|
case version
|
36
36
|
when 2
|
37
|
-
Cvss2.new(@vector_string)
|
37
|
+
Cvss2.new(prepare_vector(@vector_string))
|
38
38
|
when 3.0
|
39
|
-
Cvss3.new(@vector_string)
|
39
|
+
Cvss3.new(prepare_vector(@vector_string))
|
40
40
|
when 3.1
|
41
|
-
Cvss31.new(@vector_string)
|
41
|
+
Cvss31.new(prepare_vector(@vector_string))
|
42
42
|
else
|
43
43
|
InvalidCvss.new
|
44
44
|
end
|
@@ -51,4 +51,38 @@ module CvssSuite
|
|
51
51
|
return beginning[:version] if @vector_string.start_with? beginning[:string]
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
def self.prepare_vector(vector)
|
56
|
+
vector = vector.clone
|
57
|
+
|
58
|
+
return prepare_cvss2_vector(vector) if version == 2
|
59
|
+
|
60
|
+
version_string = CVSS_VECTOR_BEGINNINGS.detect { |v| v[:version] == version } [:string]
|
61
|
+
start_of_vector = vector.index(version_string)
|
62
|
+
|
63
|
+
if start_of_vector.nil?
|
64
|
+
''
|
65
|
+
else
|
66
|
+
vector[version_string.length..]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.prepare_cvss2_vector(vector)
|
71
|
+
start_of_vector = vector.index('AV')
|
72
|
+
|
73
|
+
if start_of_vector.nil?
|
74
|
+
''
|
75
|
+
elsif start_of_vector == 1
|
76
|
+
match_array = vector.scan(/\((?>[^)(]+|\g<0>)*\)/)
|
77
|
+
if match_array.length == 1 && match_array[0] == vector
|
78
|
+
vector.slice!(0)
|
79
|
+
vector.slice!(vector.length - 1)
|
80
|
+
vector
|
81
|
+
else
|
82
|
+
''
|
83
|
+
end
|
84
|
+
else
|
85
|
+
vector[start_of_vector..]
|
86
|
+
end
|
87
|
+
end
|
54
88
|
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: 3.
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0llirocks
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -121,7 +121,7 @@ licenses:
|
|
121
121
|
metadata:
|
122
122
|
bug_tracker_uri: https://github.com/0llirocks/cvss-suite/issues
|
123
123
|
changelog_uri: https://github.com/0llirocks/cvss-suite/blob/master/CHANGES.md
|
124
|
-
documentation_uri: https://www.rubydoc.info/gems/cvss-suite/3.
|
124
|
+
documentation_uri: https://www.rubydoc.info/gems/cvss-suite/3.1.1
|
125
125
|
homepage_uri: https://cvss-suite.0lli.rocks
|
126
126
|
source_code_uri: https://github.com/0llirocks/cvss-suite
|
127
127
|
post_install_message:
|