diff --git a/app/controllers/cisa_known_exploits_controller.rb b/app/controllers/cisa_known_exploits_controller.rb
new file mode 100644
index 0000000..cacbd55
--- /dev/null
+++ b/app/controllers/cisa_known_exploits_controller.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class CisaKnownExploitsController < ApplicationController
+ def index
+ @cisa_known_exploits = CisaKnownExploit.all
+ render json: @cisa_known_exploits.to_json
+ end
+
+ def show
+ @cisa_known_exploit = CisaKnownExploit.find(params[:cve_id])
+ render json: @cisa_known_exploit.to_json
+ end
+end
diff --git a/app/models/cisa_known_exploit.rb b/app/models/cisa_known_exploit.rb
new file mode 100644
index 0000000..48e85f7
--- /dev/null
+++ b/app/models/cisa_known_exploit.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class CisaKnownExploit < ActiveRecord::Base
+ def self.find_by_id(id)
+ find_by(cve_id: id)
+ end
+
+ def self.from_year(year)
+ where('cve_id LIKE ?', "CVE-#{year}-%")
+ end
+end
diff --git a/app/views/cisa_known_exploits/index.html.erb b/app/views/cisa_known_exploits/index.html.erb
new file mode 100644
index 0000000..f2d4aac
--- /dev/null
+++ b/app/views/cisa_known_exploits/index.html.erb
@@ -0,0 +1 @@
+
CisaKnownExploits#index
diff --git a/app/views/cisa_known_exploits/show.html.erb b/app/views/cisa_known_exploits/show.html.erb
new file mode 100644
index 0000000..e69de29
diff --git a/app/workers/cisa_known_exploit_importer_worker.rb b/app/workers/cisa_known_exploit_importer_worker.rb
new file mode 100644
index 0000000..f7ec7fc
--- /dev/null
+++ b/app/workers/cisa_known_exploit_importer_worker.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require '/data_importer/lib/importers/cisa_known_exploit_importer'
+
+class CisaKnownExploitImporterWorker
+ include Faktory::Job
+
+ def perform(*args)
+ puts "Hello, I am #{jid} with args #{args}"
+ CisaKnownExploitImporter.new.import
+ end
+end
diff --git a/crontab.yaml b/crontab.yaml
index 0656b18..d99dcda 100644
--- a/crontab.yaml
+++ b/crontab.yaml
@@ -59,4 +59,10 @@ jobs:
schedule: "@every 4h00m00s"
retries: 1
queue: default
+ priority: 5
+ - job: CisaKnownExploitImporterWorker
+ args: []
+ schedule: "@every 6h00m00s"
+ retries: 1
+ queue: default
priority: 5
\ No newline at end of file
diff --git a/db/migrate/20220427043126_create_cisa_known_exploits.rb b/db/migrate/20220427043126_create_cisa_known_exploits.rb
new file mode 100644
index 0000000..19618d2
--- /dev/null
+++ b/db/migrate/20220427043126_create_cisa_known_exploits.rb
@@ -0,0 +1,13 @@
+class CreateCisaKnownExploits < ActiveRecord::Migration[7.0]
+ def change
+ create_table :cisa_known_exploits do |t|
+ t.string :title
+ t.string :catalog_version
+ t.date :date_released
+ t.index :date_released, unique: true
+ t.integer :count
+ t.jsonb :vulnerabilities
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 3305715..523946e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,10 +10,21 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2022_04_19_203353) do
+ActiveRecord::Schema[7.0].define(version: 2022_04_27_043126) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ create_table "cisa_known_exploits", force: :cascade do |t|
+ t.string "title"
+ t.string "catalog_version"
+ t.date "date_released"
+ t.integer "count"
+ t.jsonb "vulnerabilities"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["date_released"], name: "index_cisa_known_exploits_on_date_released", unique: true
+ end
+
create_table "cnas", force: :cascade do |t|
t.string "short_name"
t.string "cna_id"
diff --git a/db/seeds.rb b/db/seeds.rb
index 3f2dad8..ab6f60f 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -18,6 +18,7 @@ require '/data_importer/lib/importers/cna_importer'
require '/data_importer/lib/importers/github_advisory_importer'
require '/data_importer/lib/importers/github_user_importer'
require '/data_importer/lib/importers/gsd_importer.rb'
+require '/data_importer/lib/importers/cisa_known_exploit_importer.rb'
def line_sep
puts '----------' * 12
@@ -30,6 +31,7 @@ def perform
import_trickest_poc_cves
import_inthewild_cve_exploits
import_cvemon_cves
+ import_cisa_known_exploits
import_cpes
import_cnas
import_github_advisories
@@ -71,6 +73,11 @@ def import_inthewild_cve_exploits
InthewildCveExploitImporter.new.import
end
+def import_cisa_known_exploits
+ line_sep
+ CisaKnownExploitImporter.new.import
+end
+
def import_trickest_poc_cves
line_sep
TrickestPocCveImporter.new.import
diff --git a/lib/importers/cisa_known_exploit_importer.rb b/lib/importers/cisa_known_exploit_importer.rb
new file mode 100644
index 0000000..068d25b
--- /dev/null
+++ b/lib/importers/cisa_known_exploit_importer.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require '/data_importer/lib/json_helper'
+
+class CisaKnownExploitImporter
+ attr_accessor :feed_url
+
+ EXPECTED_KEYS = %i[
+ title
+ catalog_version
+ date_released
+ count
+ vulnerabilities
+ ].freeze
+
+ EMPTY_HASH = EXPECTED_KEYS.map { |k| [k, nil] }.to_h.freeze
+
+ def initialize
+ @feed_url = 'https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json'
+ end
+
+ def get_and_transform_json
+ json = JsonHelper.read_json_from_url(feed_url)
+ json_transformed = JsonHelper.deep_transform_keys(json)
+ #json_transformed.map { |h| h.slice(*EXPECTED_KEYS).reverse_merge(EMPTY_HASH) }
+ end
+
+
+ def import
+ puts "Now starting import Cisa Known Exploits for #{feed_url}."
+ puts '----------' * 12
+ cisa_known_exploits = [ get_and_transform_json ]
+ CisaKnownExploit.upsert_all(cisa_known_exploits, unique_by: :date_released)
+ end
+end
diff --git a/lib/json_helper.rb b/lib/json_helper.rb
index 014b1f1..7bf4d5b 100644
--- a/lib/json_helper.rb
+++ b/lib/json_helper.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+require 'rest-client'
class JsonHelper
def self.deep_transform_keys(json_hash)
@@ -17,4 +18,19 @@ class JsonHelper
s.gsub("`\u0000`", "null_byte")
end
+ def self.read_json_from_file(filename)
+ JSON.parse(File.read(filename), symbolize_names: true)
+ end
+
+ def self.read_json_from_url(url)
+ r = RestClient::Request.execute(
+ :method => :get,
+ :url => url
+ )
+ if r.code == 200
+ JSON.parse(r.body, symobilize_names: true)
+ else
+ puts "Http Code: #{r.code}"
+ end
+ end
end