fidius-cvedb 0.0.2
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.
- data/Gemfile +7 -0
- data/LICENSE +57 -0
- data/README.md +106 -0
- data/Rakefile +15 -0
- data/bin/fidius-cvedb +64 -0
- data/fidius-cvedb.gemspec +22 -0
- data/lib/cveparser/main.rb +31 -0
- data/lib/cveparser/ms_parser.rb +65 -0
- data/lib/cveparser/parser.rb +138 -0
- data/lib/cveparser/parser_model.rb +72 -0
- data/lib/cveparser/rails_store.rb +266 -0
- data/lib/db/migrate/20101122144313_create_impacts.rb +14 -0
- data/lib/db/migrate/20101122145008_create_default_impacts.rb +19 -0
- data/lib/db/migrate/20101122153216_create_cvsses.rb +19 -0
- data/lib/db/migrate/20101122174719_create_products.rb +19 -0
- data/lib/db/migrate/20101122175021_create_vulnerable_softwares.rb +16 -0
- data/lib/db/migrate/20101122175244_create_vulnerable_configurations.rb +14 -0
- data/lib/db/migrate/20101122175402_create_nvd_entries.rb +18 -0
- data/lib/db/migrate/20101125140254_create_vulnerability_references.rb +16 -0
- data/lib/db/migrate/20101202100411_create_xmls.rb +14 -0
- data/lib/db/migrate/20101210141850_create_mscves.rb +14 -0
- data/lib/db/migrate/20110118124541_change_impacts_structure.rb +13 -0
- data/lib/db/migrate/20110118131643_destroy_vulnerable_configurations.rb +13 -0
- data/lib/fidius-cvedb.rb +17 -0
- data/lib/fidius-cvedb/railtie.rb +14 -0
- data/lib/fidius-cvedb/version.rb +5 -0
- data/lib/models/fidius/cve_db/cve_connection.rb +7 -0
- data/lib/models/fidius/cve_db/cvss.rb +5 -0
- data/lib/models/fidius/cve_db/impact.rb +2 -0
- data/lib/models/fidius/cve_db/mscve.rb +3 -0
- data/lib/models/fidius/cve_db/nvd_entry.rb +23 -0
- data/lib/models/fidius/cve_db/product.rb +6 -0
- data/lib/models/fidius/cve_db/vulnerability_reference.rb +3 -0
- data/lib/models/fidius/cve_db/vulnerable_configuration.rb +6 -0
- data/lib/models/fidius/cve_db/vulnerable_software.rb +6 -0
- data/lib/models/fidius/cve_db/xml.rb +2 -0
- data/lib/tasks/db_backup.rake +30 -0
- data/lib/tasks/nvd_migrate.rake +25 -0
- data/lib/tasks/parse_cves.rake +146 -0
- data/test/cve_parser_test.rb +25 -0
- data/test/test_references.xml +9 -0
- data/test/test_v2.xml +3 -0
- metadata +120 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateNvdEntries < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :nvd_entries do |t|
|
4
|
+
t.string :cve
|
5
|
+
t.string :cwe
|
6
|
+
t.string :summary
|
7
|
+
t.datetime :published
|
8
|
+
t.datetime :last_modified
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
add_index :nvd_entries, :cve
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
drop_table :nvd_entries
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateVulnerabilityReferences < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :vulnerability_references do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :link
|
6
|
+
t.string :source
|
7
|
+
t.integer :nvd_entry_id
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :vulnerability_references
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class ChangeImpactsStructure < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :cvsses, :availability_impact_id, :integer
|
4
|
+
add_column :cvsses, :confidentiality_impact_id, :integer
|
5
|
+
add_column :cvsses, :integrity_impact_id, :integer
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
remove_column :cvsses, :availability_impact_id
|
10
|
+
remove_column :cvsses, :confidentiality_impact_id
|
11
|
+
remove_column :cvsses, :integrity_impact_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class DestroyVulnerableConfigurations < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
drop_table :vulnerable_configurations
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.down
|
7
|
+
create_table :vulnerable_configurations do |t|
|
8
|
+
t.integer :nvd_entry_id
|
9
|
+
t.integer :product_id
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/fidius-cvedb.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fidius-cvedb/version'
|
2
|
+
|
3
|
+
module FIDIUS
|
4
|
+
module CveDb
|
5
|
+
GEM_BASE = File.join(ENV['GEM_HOME'], 'gems', "fidius-cvedb-#{VERSION}", 'lib')
|
6
|
+
RAILS_VERSION = Rails.version.to_i
|
7
|
+
|
8
|
+
# If the used Rails version is 3 or beyond we use railties to load the rake
|
9
|
+
# tasks. Otherwise they are symlinked.
|
10
|
+
require 'fidius-cvedb/railtie' unless RAILS_VERSION < 3
|
11
|
+
|
12
|
+
require (File.join GEM_BASE, 'models', 'fidius', 'cve_db', 'cve_connection.rb')
|
13
|
+
Dir.glob(File.join GEM_BASE, 'models', 'fidius', 'cve_db', '*.rb') do |rb|
|
14
|
+
require rb
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class FIDIUS::CveDb::CveConnection < ActiveRecord::Base
|
2
|
+
# If the application is using the cve_db as foreign database this should be
|
3
|
+
# uncommented.
|
4
|
+
database_yml = YAML.load_file('config/database.yml')
|
5
|
+
establish_connection database_yml['cve_db']
|
6
|
+
self.abstract_class = true
|
7
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class FIDIUS::CveDb::NvdEntry < FIDIUS::CveDb::CveConnection
|
2
|
+
|
3
|
+
has_one :cvss
|
4
|
+
has_one :mscve
|
5
|
+
|
6
|
+
has_many :vulnerable_softwares
|
7
|
+
has_many :vulnerable_configurations
|
8
|
+
has_many :vulnerability_references
|
9
|
+
|
10
|
+
validates_uniqueness_of :cve
|
11
|
+
|
12
|
+
def references_string
|
13
|
+
res = ""
|
14
|
+
vulnerability_references.each_with_index do |reference, i|
|
15
|
+
# http://www.foo-bar.de/sub/sub-sub -> www.foo-bar.de
|
16
|
+
link_name = reference.link.scan(/(?:https?|s?ftp):\/\/([^\/]+)/).to_s
|
17
|
+
res += "<a href=\"#{reference.link}\">#{link_name}</a>"
|
18
|
+
res += " | " unless i == vulnerability_references.size-1
|
19
|
+
end
|
20
|
+
res
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
BACKUP_DIR = "db"
|
4
|
+
RAILS_ENV = "development" # TODO improve :D
|
5
|
+
MAX_BACKUPS = 5
|
6
|
+
|
7
|
+
# Source: http://blog.craigambrose.com/articles/2007/03/01/a-rake-task-for-database-backups
|
8
|
+
namespace :db do
|
9
|
+
desc "Backup the database to a file."
|
10
|
+
task :backup => [:environment] do
|
11
|
+
datestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
|
12
|
+
base_path = BACKUP_DIR || "db"
|
13
|
+
backup_base = File.join(base_path, 'backup')
|
14
|
+
backup_folder = File.join(backup_base, datestamp)
|
15
|
+
backup_file = File.join(backup_folder, "#{RAILS_ENV}_dump.sql.gz")
|
16
|
+
FileUtils.mkdir_p(backup_folder)
|
17
|
+
db_config = ActiveRecord::Base.configurations[RAILS_ENV]
|
18
|
+
sh "mysqldump -u #{db_config['username']} -p#{db_config['password']} -Q --add-drop-database --opt #{db_config['database']} | gzip -c > #{backup_file}"
|
19
|
+
dir = Dir.new(backup_base)
|
20
|
+
all_backups = dir.entries[2..-1].sort.reverse
|
21
|
+
puts "Created backup: #{backup_file}"
|
22
|
+
max_backups = MAX_BACKUPS || 20
|
23
|
+
unwanted_backups = all_backups[max_backups..-1] || []
|
24
|
+
for unwanted_backup in unwanted_backups
|
25
|
+
FileUtils.rm_rf(File.join(backup_base, unwanted_backup))
|
26
|
+
puts "deleted #{unwanted_backup}"
|
27
|
+
end
|
28
|
+
puts "Deleted #{unwanted_backups.length} backups, #{all_backups.length - unwanted_backups.length} backups available"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
namespace :nvd do
|
4
|
+
desc 'Execute NVD migrations'
|
5
|
+
task :migrate do
|
6
|
+
db_connect
|
7
|
+
ActiveRecord::Migrator.migrate(File.join FIDIUS::CveDb::GEM_BASE, 'db', 'migrate')
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Drop NVD database"
|
11
|
+
task :drop do
|
12
|
+
#db_connect
|
13
|
+
raise NotImplementedError
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def db_connect
|
19
|
+
db_config = YAML.load_file(File.join(Rails.root.to_s, 'config', 'database.yml'))
|
20
|
+
if db_config["cve_db"]
|
21
|
+
ActiveRecord::Base::establish_connection db_config["cve_db"]
|
22
|
+
else
|
23
|
+
puts "No configuration found for cve_db in config/database.yml!"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'fidius-cvedb'
|
5
|
+
|
6
|
+
BASE_URL = "http://static.nvd.nist.gov/feeds/xml/cve/"
|
7
|
+
DOWNLOAD_URL = "http://nvd.nist.gov/download.cfm"
|
8
|
+
#GEM_BASE = File.join(ENV['GEM_HOME'], 'gems', "fidius-cvedb-#{FIDIUS::CveDb::VERSION}", 'lib')
|
9
|
+
XML_DIR = File.join(Dir.pwd, "cveparser", "xml")
|
10
|
+
ANNUALLY_XML = /nvdcve-2[.]0-\d{4}[.]xml/
|
11
|
+
|
12
|
+
# modified xml includes all recent published and modified cve entries
|
13
|
+
MODIFIED_XML = "nvdcve-2.0-modified.xml"
|
14
|
+
|
15
|
+
namespace :nvd do
|
16
|
+
desc 'Parses local XML-File.'
|
17
|
+
task :parse, :file_name do |t,args|
|
18
|
+
cve_main '-p', args[:file_name]
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Downloads XML-File from NVD. (with names from nvd:list_remote)'
|
22
|
+
task :get, :xml_name do |t,args|
|
23
|
+
if args[:xml_name]
|
24
|
+
wget args[:xml_name]
|
25
|
+
else
|
26
|
+
puts "Please call task with 'rake nvd:get[<xml_name>]'!"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Lists the locally available NVD-XML-Datafeeds.'
|
31
|
+
task :list_local do
|
32
|
+
puts local_xmls
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Lists the remotely available NVD-XML-Datafeeds.'
|
36
|
+
task :list_remote do
|
37
|
+
xmls = remote_xmls
|
38
|
+
if xmls
|
39
|
+
puts "#{xmls.size} XMLs available:\n------"
|
40
|
+
puts xmls
|
41
|
+
else
|
42
|
+
puts "No suitable XMLs found."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Downloads the modified.xml from nvd.org and stores it's content in the database."
|
47
|
+
task :update do
|
48
|
+
wget MODIFIED_XML
|
49
|
+
cve_main '-u', MODIFIED_XML
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Initializes the CVE-DB, parses all annual CVE-XMLs and removes duplicates."
|
53
|
+
task :initialize do
|
54
|
+
init
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "Creates the mapping between CVEs and Microsoft Security Bulletin Notation in the database."
|
58
|
+
task :mscve do
|
59
|
+
cve_main '-m'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# ---------- Helper - Methods ---------- #
|
64
|
+
|
65
|
+
# Initializes the CVE-DB with all CVE data available in the NVD.
|
66
|
+
def init
|
67
|
+
local_x = local_xmls
|
68
|
+
if local_x
|
69
|
+
puts "WARNING: The XML directory already contains XML files. "+
|
70
|
+
"nvd:initialize is intended to be used only once to set up the "+
|
71
|
+
"CVE-Entries. To update the CVE-Entries use nvd:update.\n\n"+
|
72
|
+
"If you don't cancel the task I'll proceed in 20 seconds."
|
73
|
+
sleep 20
|
74
|
+
end
|
75
|
+
puts "[*] Looking for XMLs at #{DOWNLOAD_URL}"
|
76
|
+
remote_x = remote_xmls
|
77
|
+
r_ann_xmls = []
|
78
|
+
remote_x.each do |xml|
|
79
|
+
r_ann_xmls << xml if xml.match ANNUALLY_XML
|
80
|
+
end
|
81
|
+
puts "[*] I've found #{r_ann_xmls.size} annually XML files remotely."
|
82
|
+
puts "[*] Checking locally available XMLs."
|
83
|
+
l_ann_xmls = []
|
84
|
+
if local_x
|
85
|
+
local_x.each do |xml|
|
86
|
+
l_ann_xmls << xml if xml.match ANNUALLY_XML
|
87
|
+
end
|
88
|
+
end
|
89
|
+
puts "[*] I've found #{l_ann_xmls.size} annually XML files locally. I'll "+
|
90
|
+
"download the missing XMLs now."
|
91
|
+
r_ann_xmls.each do |xml|
|
92
|
+
wget xml unless l_ann_xmls.include? xml
|
93
|
+
puts "Downloaded #{xml}."
|
94
|
+
end
|
95
|
+
puts "[*] All available files downloaded, parsing the XMLs now."
|
96
|
+
l_ann_xmls.each do |xml|
|
97
|
+
cve_main '-p', xml
|
98
|
+
end
|
99
|
+
puts "[*] All local XMLs parsed."
|
100
|
+
cve_main '-f'
|
101
|
+
puts "[*] Initializing done."
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns an array of xmls that were previously downloaded
|
105
|
+
def local_xmls
|
106
|
+
if Dir.exists?(XML_DIR)
|
107
|
+
entries = []
|
108
|
+
dir = Dir.new XML_DIR
|
109
|
+
dir.each do |entry|
|
110
|
+
entries << entry if entry =~ /.+\.xml$/
|
111
|
+
end
|
112
|
+
return (entries.empty? ? nil : entries)
|
113
|
+
else
|
114
|
+
puts "ERROR: There is no directory \"#{XML_DIR}\" where I can look for XMLs."
|
115
|
+
return nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns an array of available xmls or nil if none are found.
|
120
|
+
def remote_xmls
|
121
|
+
doc = Nokogiri::HTML(open(DOWNLOAD_URL))
|
122
|
+
links = doc.css("div.rightbar > a")
|
123
|
+
xmls = []
|
124
|
+
links.each do |link|
|
125
|
+
link_name = link.attributes['href'].to_s
|
126
|
+
if link_name
|
127
|
+
xmls << link_name.split("/").last if link_name.include? BASE_URL
|
128
|
+
end
|
129
|
+
end
|
130
|
+
xmls.empty? ? nil : xmls
|
131
|
+
end
|
132
|
+
|
133
|
+
# Calls the main.rb script with appropriate options
|
134
|
+
def cve_main option, file = ''
|
135
|
+
runner_version = Rails.version[0].to_i < 3 ? "ruby script/runner" : "rails runner"
|
136
|
+
main_script = "#{runner_version} #{File.join(FIDIUS::CveDb::GEM_BASE, "cveparser", "main.rb")}"
|
137
|
+
param = file.empty? ? file : " #{File.join(XML_DIR, file)}"
|
138
|
+
puts "Working Dir : #{Dir.pwd}"
|
139
|
+
sh "#{main_script} #{option} #{param}"
|
140
|
+
end
|
141
|
+
|
142
|
+
# Simple wget
|
143
|
+
def wget file
|
144
|
+
FileUtils.mkdir_p(XML_DIR)
|
145
|
+
sh "wget -O#{File.join(XML_DIR, file)} #{BASE_URL + file}"
|
146
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../lib/cveparser/")
|
2
|
+
require 'parser'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class TestCveParser < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include FIDIUS::NVDParser
|
8
|
+
|
9
|
+
def test_should_parse_2_0_only
|
10
|
+
assert_raise(RuntimeError) { FIDIUS::NVDParser.parse_cve_file 'test_v2.xml' }
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_should_find_1_reference
|
14
|
+
entries = FIDIUS::NVDParser.parse_cve_file 'test_references.xml'
|
15
|
+
assert_equal 1, entries.first.references.size, "The test_references.xml " +
|
16
|
+
"contains one reference which should be found."
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_should_find_3_nvd_entries
|
20
|
+
entries = FIDIUS::NVDParser.parse_cve_file 'test_entries.xml'
|
21
|
+
assert_equal 3, entries.size, "The test_entries.xml contains 3 NVD " +
|
22
|
+
"entries which should be returned in an array."
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|