cisa-kev 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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'