cisa-kev 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8791f5387d34ee20d6ac2f885be06187c122fab8de2f87c2bbcd6985f5495089
4
+ data.tar.gz: 3fd6e839977a257810c59e139319bc72974cd1f5ee52e834fffd1bb6afda4aba
5
+ SHA512:
6
+ metadata.gz: b710ad6d6f7aeaf9753967f004947af5cac07531390acf22377a56d3f0934d77ca7c9ada076e593b610ed519d3a8d54677352641e4da4b472ef753a712a59b38
7
+ data.tar.gz: 05a11854d20b358c6eda0053007bf8311cce1a52f9e94d3160aebf9d35dff708a2a95ec7cabad19566e1a6e3fb65e04bf69b16fc2bcfa7aba610cc6085e77b2a
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on: [ push, pull_request ]
4
+
5
+ jobs:
6
+ tests:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby:
12
+ - '3.0'
13
+ - '3.1'
14
+ - '3.2'
15
+ - '3.3'
16
+ - jruby
17
+ - truffleruby
18
+ name: Ruby ${{ matrix.ruby }}
19
+ steps:
20
+ - uses: actions/checkout@v2
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ - name: Install dependencies
26
+ run: bundle install --jobs 4 --retry 3
27
+ - name: Run tests
28
+ run: bundle exec rake test
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ /.bundle
2
+ /.yardoc/
3
+ /Gemfile.lock
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /vendor/cache/*.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "CISA::KEV Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,6 @@
1
+ ### 0.1.0 / 2024-05-13
2
+
3
+ * Initial release:
4
+ * Supports requesting the CISA KEV catalog via HTTP(s).
5
+ * Supports parsing previously downloaded JSON files.
6
+
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+
9
+ gem 'json'
10
+ gem 'rspec', '~> 3.0'
11
+ gem 'webmock', '~> 3.0'
12
+ gem 'simplecov', '~> 0.20', require: false
13
+
14
+ gem 'kramdown'
15
+ gem 'redcarpet', platform: :mri
16
+ gem 'yard', '~> 0.9'
17
+ gem 'yard-spellcheck', require: false
18
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2024 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # cisa-kev
2
+
3
+ [![CI](https://github.com/postmodern/cisa-kev.rb/actions/workflows/ruby.yml/badge.svg)](https://github.com/postmodern/cisa-kev.rb/actions/workflows/ruby.yml)
4
+ [![Code Climate](https://codeclimate.com/github/postmodern/cisa-kev.rb.svg)](https://codeclimate.com/github/postmodern/cisa-kev.rb)
5
+
6
+ * [Homepage](https://github.com/postmodern/cisa-kev.rb#readme)
7
+ * [Issues](https://github.com/postmodern/cisa-kev.rb/issues)
8
+ * [Documentation](http://rubydoc.info/gems/cisa-kev/frames)
9
+
10
+ ## Description
11
+
12
+ A simple Ruby library for fetching and parsing the [CISA KEV] catalog.
13
+
14
+ ## Features
15
+
16
+ * Supports requesting the CISA KEV catalog via HTTP(s).
17
+ * Supports parsing previously downloaded JSON files.
18
+
19
+ ## Examples
20
+
21
+ ```ruby
22
+ require 'cisa/kev'
23
+
24
+ catalog = CISA::KEV::Catalog.load
25
+ catalog.select(&:known_ransomware_campaign_use).sort_by(&:date_added)
26
+ # =>
27
+ # [
28
+ # ...
29
+ # #<CISA::KEV::Vulnerability:0x00007fc0a6e715f8
30
+ # @cve_id="CVE-2023-24955",
31
+ # @date_added=#<Date: 2024-03-26 ((2460396j,0s,0n),+0s,2299161j)>,
32
+ # @due_date=#<Date: 2024-04-16 ((2460417j,0s,0n),+0s,2299161j)>,
33
+ # @known_ransomware_campaign_use=true,
34
+ # @notes="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-24955",
35
+ # @product="SharePoint Server",
36
+ # @required_action=
37
+ # "Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.",
38
+ # @short_description=
39
+ # "Microsoft SharePoint Server contains a code injection vulnerability that allows an authenticated attacker with Site Owner privileges to execute code remotely.",
40
+ # @vendor_project="Microsoft",
41
+ # @vulnerability_name="Microsoft SharePoint Server Code Injection Vulnerability">]
42
+ ```
43
+
44
+ ## Requirements
45
+
46
+ * [ruby] >= 3.0.0
47
+
48
+ ## Install
49
+
50
+ ```shell
51
+ gem install cisa-kev
52
+ ```
53
+
54
+ ### Gemfile
55
+
56
+ ```ruby
57
+ gem 'cisa-kev', '~> 0.1'
58
+ ```
59
+ ## Copyright
60
+
61
+ Copyright (c) 2024 Hal Brodigan
62
+
63
+ See {file:LICENSE.txt} for details.
64
+
65
+ [CISA KEV]: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
66
+ [ruby]: https://www.ruby-lang.org/
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler/setup'
7
+ rescue LoadError => e
8
+ abort e.message
9
+ end
10
+
11
+ require 'rake'
12
+ require 'rubygems/tasks'
13
+ Gem::Tasks.new
14
+
15
+ require 'rspec/core/rake_task'
16
+ RSpec::Core::RakeTask.new
17
+
18
+ task :test => :spec
19
+ task :default => :spec
20
+
21
+ require 'yard'
22
+ YARD::Rake::YardocTask.new
23
+ task :doc => :yard
data/cisa-kev.gemspec ADDED
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'cisa/kev/version'
14
+ CISA::KEV::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = Array(gemspec['requirements'])
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
53
+ end
54
+ end
55
+
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
data/gemspec.yml ADDED
@@ -0,0 +1,20 @@
1
+ name: cisa-kev
2
+ summary: A simple library for parsing the CISA KEV catalog
3
+ description: |
4
+ A simple Ruby library for parsing the CISA KEV (Known Exploited
5
+ Vulnerabilities) catalog
6
+ license: MIT
7
+ authors: Postmodern
8
+ email: postmodern.mod3@gmail.com
9
+ homepage: https://github.com/postmodern/cisa-kev.rb#readme
10
+
11
+ metadata:
12
+ documentation_uri: https://rubydoc.info/gems/cisa-kev
13
+ source_code_uri: https://github.com/postmodern/cisa-kev.rb
14
+ bug_tracker_uri: https://github.com/postmodern/cisa-kev.rb/issues
15
+ changelog_uri: https://github.com/postmodern/cisa-kev.rb/blob/main/ChangeLog.md
16
+
17
+ required_ruby_version: ">= 3.0.0"
18
+
19
+ development_dependencies:
20
+ bundler: ~> 2.0
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'vulnerability'
4
+
5
+ require 'net/https'
6
+ require 'json'
7
+ require 'time'
8
+
9
+ module CISA
10
+ module KEV
11
+ #
12
+ # Represents the parsed [CISA KEV] catalog.
13
+ #
14
+ # [CISA KEV]: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
15
+ #
16
+ # ## Example
17
+ #
18
+ # catalog = CISA::KEV::Catalog.load
19
+ # catalog.select(&:known_ransomware_campaign_use).sort_by(&:date_added)
20
+ # # =>
21
+ # # [
22
+ # # ...
23
+ # # #<CISA::KEV::Vulnerability:0x00007fc0a6e715f8
24
+ # # @cve_id="CVE-2023-24955",
25
+ # # @date_added=#<Date: 2024-03-26 ((2460396j,0s,0n),+0s,2299161j)>,
26
+ # # @due_date=#<Date: 2024-04-16 ((2460417j,0s,0n),+0s,2299161j)>,
27
+ # # @known_ransomware_campaign_use=true,
28
+ # # @notes="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-24955",
29
+ # # @product="SharePoint Server",
30
+ # # @required_action=
31
+ # # "Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.",
32
+ # # @short_description=
33
+ # # "Microsoft SharePoint Server contains a code injection vulnerability that allows an authenticated attacker with Site Owner privileges to execute code remotely.",
34
+ # # @vendor_project="Microsoft",
35
+ # # @vulnerability_name="Microsoft SharePoint Server Code Injection Vulnerability">]
36
+ #
37
+ class Catalog
38
+
39
+ include Enumerable
40
+
41
+ # Catalog title attribute.
42
+ #
43
+ # @return [String]
44
+ attr_reader :title
45
+
46
+ # Catalog version string.
47
+ #
48
+ # @return [String]
49
+ attr_reader :catalog_version
50
+ alias version catalog_version
51
+
52
+ # Time that the catalog was last updated.
53
+ #
54
+ # @return [Time]
55
+ attr_reader :date_released
56
+
57
+ # Number of vulnerabilities current in the catalog.
58
+ #
59
+ # @return [Integer]
60
+ attr_reader :count
61
+ alias size count
62
+ alias length count
63
+
64
+ # Vulnerabilities in the catalog.
65
+ #
66
+ # @return [Array<Vulnerability>]
67
+ attr_reader :vulnerabilities
68
+ alias vulns vulnerabilities
69
+
70
+ #
71
+ # Initializes the CISA KEV catalog.
72
+ #
73
+ # @param [String] title
74
+ # The catalog title attribute.
75
+ #
76
+ # @param [String] catalog_version
77
+ # The catalog version string.
78
+ #
79
+ # @param [Time] date_released
80
+ # The time that the catalog was last updated.
81
+ #
82
+ # @param [Integer] count
83
+ # The number of vulnerabilities in the catalog.
84
+ #
85
+ # @param [Array<Vulnerability>] vulnerabilities
86
+ # The parsed vulnerabilities.
87
+ #
88
+ # @api private
89
+ #
90
+ def initialize(title: ,
91
+ catalog_version: ,
92
+ date_released: ,
93
+ count: ,
94
+ vulnerabilities: )
95
+ @title = title
96
+ @catalog_version = catalog_version
97
+ @date_released = date_released
98
+ @count = count
99
+
100
+ @vulnerabilities = vulnerabilities
101
+ end
102
+
103
+ # The CISA KEV catalog in JSON format.
104
+ URL = URI.parse('https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json')
105
+
106
+ #
107
+ # Performs an HTTP request for the CISA KEV catalog JSON file.
108
+ #
109
+ # @return [String]
110
+ # The response body containing the CISA KEV catalog JSON.
111
+ #
112
+ # @api public
113
+ #
114
+ def self.request
115
+ Net::HTTP.get(URL)
116
+ end
117
+
118
+ #
119
+ # Loads the CISA KEV list.
120
+ #
121
+ # @return [Catalog]
122
+ # The loaded catalog.
123
+ #
124
+ # @api public
125
+ #
126
+ # @note This method will perform a HTTP request to {URL}.
127
+ #
128
+ def self.load
129
+ parse(request)
130
+ end
131
+
132
+ #
133
+ # Parses a previously downloaded CISA KEV catalog.
134
+ #
135
+ # @param [String] path
136
+ # The file to parse.
137
+ #
138
+ # @return [Catalog]
139
+ # The parsed catalog.
140
+ #
141
+ # @api public
142
+ #
143
+ def self.open(path)
144
+ parse(File.open(path).read)
145
+ end
146
+
147
+ #
148
+ # Parses the CISA KEV JSON contents.
149
+ #
150
+ # @param [String] contents
151
+ #
152
+ # @return [Catalog]
153
+ #
154
+ # @api private
155
+ #
156
+ def self.parse(contents)
157
+ json = JSON.parse(contents)
158
+
159
+ title = json.fetch('title')
160
+ catalog_version = json.fetch('catalogVersion')
161
+ date_released = Time.parse(json.fetch('dateReleased'))
162
+ count = json.fetch('count').to_i
163
+
164
+ vulnerabilities = json.fetch('vulnerabilities').map do |attributes|
165
+ Vulnerability.from_json(attributes)
166
+ end
167
+
168
+ return new(
169
+ title: title,
170
+ catalog_version: catalog_version,
171
+ date_released: date_released,
172
+ count: count,
173
+ vulnerabilities: vulnerabilities
174
+ )
175
+ end
176
+
177
+ #
178
+ # Enumerates over each vulnerability in the CISA KEV list.
179
+ #
180
+ # @yield [vuln]
181
+ # If a block is given, it will be passed every vulnerability in the
182
+ # catalog.
183
+ #
184
+ # @yieldparam [Vulnerability] vuln
185
+ # A parsed vulnerability in the catalog.
186
+ #
187
+ # @return [Enumerator]
188
+ #
189
+ def each(&block)
190
+ @vulnerabilities.each(&block)
191
+ end
192
+
193
+ #
194
+ # Converts the list to a String.
195
+ #
196
+ # @return [String]
197
+ # The string containing the title and date released attributes.
198
+ #
199
+ def to_s
200
+ "#{@title} (#{@date_released})"
201
+ end
202
+
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CISA
4
+ module KEV
5
+ # `cisa-kev` version
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module CISA
6
+ module KEV
7
+ #
8
+ # Represents a parsed vulnerability in the [CISA KEV] catalog.
9
+ #
10
+ # [CISA KEV]: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
11
+ #
12
+ class Vulnerability
13
+
14
+ # The CVE ID of the vulnerability.
15
+ #
16
+ # @return [String]
17
+ attr_reader :cve_id
18
+ alias cve cve_id
19
+
20
+ # The vendor project.
21
+ #
22
+ # @return [String]
23
+ attr_reader :vendor_project
24
+
25
+ # The vendor's product.
26
+ #
27
+ # @return [String]
28
+ attr_reader :product
29
+
30
+ # The vulnerability name or title.
31
+ #
32
+ # @return [String]
33
+ attr_reader :vulnerability_name
34
+ alias name vulnerability_name
35
+
36
+ # The date the vulnerability was added to the CISA KEV catalog.
37
+ #
38
+ # @return [Date]
39
+ attr_reader :date_added
40
+
41
+ # A short description of the vulnerability.
42
+ #
43
+ # @return [String]
44
+ attr_reader :short_description
45
+ alias description short_description
46
+
47
+ # The required action to resolve the vulnerability.
48
+ #
49
+ # @return [String]
50
+ attr_reader :required_action
51
+
52
+ # The due date.
53
+ #
54
+ # @return [Date]
55
+ attr_reader :due_date
56
+
57
+ # Whether the vulnerability is currently being used in ransomware
58
+ # campaigns.
59
+ #
60
+ # @return [Boolean]
61
+ attr_reader :known_ransomware_campaign_use
62
+ alias known_ransomware_campaign_use? known_ransomware_campaign_use
63
+
64
+ # Any additional notes for the vulnerability.
65
+ #
66
+ # @return [String, nil]
67
+ attr_reader :notes
68
+
69
+ #
70
+ # Initializes the vulnerability.
71
+ #
72
+ # @param [String] cve_id
73
+ # The CVE ID of the vulnerability.
74
+ #
75
+ # @param [String] vendor_project
76
+ # The vendor project.
77
+ #
78
+ # @param [String] product
79
+ # The vendor's product.
80
+ #
81
+ # @param [String] vulnerability_name
82
+ # The vulnerability name or title.
83
+ #
84
+ # @param [Date] date_added
85
+ # The date the vulnerability was added to the CISA KEV catalog.
86
+ #
87
+ # @param [String] short_description
88
+ # A short description of the vulnerability.
89
+ #
90
+ # @param [String] required_action
91
+ # The required action to resolve the vulnerability.
92
+ #
93
+ # @param [Date] due_date
94
+ # The due date.
95
+ #
96
+ # @param [Boolean] known_ransomware_campaign_use
97
+ # Indicates whether the vulnerability is currently being used in
98
+ # ransomware campaigns.
99
+ #
100
+ # @param [String, nil] notes
101
+ # Additional notes.
102
+ #
103
+ # @api private
104
+ #
105
+ def initialize(cve_id: ,
106
+ vendor_project: ,
107
+ product: ,
108
+ vulnerability_name: ,
109
+ date_added: ,
110
+ short_description: ,
111
+ required_action: ,
112
+ due_date: ,
113
+ known_ransomware_campaign_use: false,
114
+ notes: nil)
115
+ @cve_id = cve_id
116
+ @vendor_project = vendor_project
117
+ @product = product
118
+ @vulnerability_name = vulnerability_name
119
+ @date_added = date_added
120
+ @short_description = short_description
121
+ @required_action = required_action
122
+ @due_date = due_date
123
+
124
+ @known_ransomware_campaign_use = known_ransomware_campaign_use
125
+ @notes = notes
126
+ end
127
+
128
+ #
129
+ # Loads the vulnerability from a parsed JSON hash.
130
+ #
131
+ # @param [Hash{String => String}] json
132
+ # The parsed JSON hash.
133
+ #
134
+ # @return [Vulnerability]
135
+ #
136
+ # @api private
137
+ #
138
+ def self.from_json(json)
139
+ new(
140
+ cve_id: json.fetch('cveID'),
141
+ vendor_project: json.fetch('vendorProject'),
142
+ product: json.fetch('product'),
143
+ vulnerability_name: json.fetch('vulnerabilityName'),
144
+ date_added: Date.parse(json.fetch('dateAdded')),
145
+ short_description: json.fetch('shortDescription'),
146
+ required_action: json.fetch('requiredAction'),
147
+ due_date: Date.parse(json.fetch('dueDate')),
148
+
149
+ known_ransomware_campaign_use: (json['knownRansomwareCampaignUse'] == 'Known'),
150
+ notes: if (notes = json['notes']) && !notes.empty?
151
+ notes
152
+ end
153
+ )
154
+ end
155
+
156
+ #
157
+ # Converts the vulnerability to a String.
158
+ #
159
+ # @return [String]
160
+ # The {#vulnerability_name}.
161
+ #
162
+ def to_s
163
+ @vulnerability_name
164
+ end
165
+
166
+ end
167
+ end
168
+ end
data/lib/cisa/kev.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cisa/kev/catalog'
4
+ require 'cisa/kev/version'