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.
Files changed (43) hide show
  1. data/Gemfile +7 -0
  2. data/LICENSE +57 -0
  3. data/README.md +106 -0
  4. data/Rakefile +15 -0
  5. data/bin/fidius-cvedb +64 -0
  6. data/fidius-cvedb.gemspec +22 -0
  7. data/lib/cveparser/main.rb +31 -0
  8. data/lib/cveparser/ms_parser.rb +65 -0
  9. data/lib/cveparser/parser.rb +138 -0
  10. data/lib/cveparser/parser_model.rb +72 -0
  11. data/lib/cveparser/rails_store.rb +266 -0
  12. data/lib/db/migrate/20101122144313_create_impacts.rb +14 -0
  13. data/lib/db/migrate/20101122145008_create_default_impacts.rb +19 -0
  14. data/lib/db/migrate/20101122153216_create_cvsses.rb +19 -0
  15. data/lib/db/migrate/20101122174719_create_products.rb +19 -0
  16. data/lib/db/migrate/20101122175021_create_vulnerable_softwares.rb +16 -0
  17. data/lib/db/migrate/20101122175244_create_vulnerable_configurations.rb +14 -0
  18. data/lib/db/migrate/20101122175402_create_nvd_entries.rb +18 -0
  19. data/lib/db/migrate/20101125140254_create_vulnerability_references.rb +16 -0
  20. data/lib/db/migrate/20101202100411_create_xmls.rb +14 -0
  21. data/lib/db/migrate/20101210141850_create_mscves.rb +14 -0
  22. data/lib/db/migrate/20110118124541_change_impacts_structure.rb +13 -0
  23. data/lib/db/migrate/20110118131643_destroy_vulnerable_configurations.rb +13 -0
  24. data/lib/fidius-cvedb.rb +17 -0
  25. data/lib/fidius-cvedb/railtie.rb +14 -0
  26. data/lib/fidius-cvedb/version.rb +5 -0
  27. data/lib/models/fidius/cve_db/cve_connection.rb +7 -0
  28. data/lib/models/fidius/cve_db/cvss.rb +5 -0
  29. data/lib/models/fidius/cve_db/impact.rb +2 -0
  30. data/lib/models/fidius/cve_db/mscve.rb +3 -0
  31. data/lib/models/fidius/cve_db/nvd_entry.rb +23 -0
  32. data/lib/models/fidius/cve_db/product.rb +6 -0
  33. data/lib/models/fidius/cve_db/vulnerability_reference.rb +3 -0
  34. data/lib/models/fidius/cve_db/vulnerable_configuration.rb +6 -0
  35. data/lib/models/fidius/cve_db/vulnerable_software.rb +6 -0
  36. data/lib/models/fidius/cve_db/xml.rb +2 -0
  37. data/lib/tasks/db_backup.rake +30 -0
  38. data/lib/tasks/nvd_migrate.rake +25 -0
  39. data/lib/tasks/parse_cves.rake +146 -0
  40. data/test/cve_parser_test.rb +25 -0
  41. data/test/test_references.xml +9 -0
  42. data/test/test_v2.xml +3 -0
  43. 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,14 @@
1
+ class CreateXmls < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :xmls do |t|
4
+ t.string :name
5
+ t.datetime :create_time
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :xmls
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ class CreateMscves < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :mscves do |t|
4
+ t.integer :nvd_entry_id
5
+ t.string :name
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :mscves
13
+ end
14
+ 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
@@ -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,14 @@
1
+ require 'fidius-cvedb'
2
+ require 'rails'
3
+
4
+ module FIDIUS
5
+ module CveDb
6
+ class Railtie < Rails::Railtie
7
+ rake_tasks do
8
+ load "tasks/parse_cves.rake"
9
+ load "tasks/db_backup.rake"
10
+ load "tasks/nvd_migrate.rake"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module FIDIUS
2
+ module CveDb
3
+ VERSION = "0.0.2"
4
+ end
5
+ 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,5 @@
1
+ class FIDIUS::CveDb::Cvss < FIDIUS::CveDb::CveConnection
2
+ has_one :confidentiality_impact
3
+ has_one :availability_impact
4
+ has_one :integrity_impact
5
+ end
@@ -0,0 +1,2 @@
1
+ class FIDIUS::CveDb::Impact < FIDIUS::CveDb::CveConnection
2
+ end
@@ -0,0 +1,3 @@
1
+ class FIDIUS::CveDb::Mscve < FIDIUS::CveDb::CveConnection
2
+ belongs_to :nvd_entry
3
+ 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,6 @@
1
+ class FIDIUS::CveDb::Product < FIDIUS::CveDb::CveConnection
2
+
3
+ has_many :vulnerable_softwares
4
+ has_many :nvd_entries, :through => :vulnerable_softwares
5
+
6
+ end
@@ -0,0 +1,3 @@
1
+ class FIDIUS::CveDb::VulnerabilityReference < FIDIUS::CveDb::CveConnection
2
+ belongs_to :nvd_entry
3
+ end
@@ -0,0 +1,6 @@
1
+ class FIDIUS::CveDb::VulnerableConfiguration < FIDIUS::CveDb::CveConnection
2
+
3
+ belongs_to :nvd_entry
4
+ belongs_to :product
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ class FIDIUS::CveDb::VulnerableSoftware < FIDIUS::CveDb::CveConnection
2
+
3
+ belongs_to :nvd_entry
4
+ belongs_to :product
5
+
6
+ end
@@ -0,0 +1,2 @@
1
+ class FIDIUS::CveDb::Xml < FIDIUS::CveDb::CveConnection
2
+ 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