yavdb 0.1.0.pre.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +48 -0
- data/.gitignore +115 -0
- data/.rspec +3 -0
- data/.rubocop.yml +339 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +85 -0
- data/LICENSE +661 -0
- data/README.md +87 -0
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/bin/vulndb +3 -0
- data/bin/vulnerabilitydb +3 -0
- data/bin/yavdb +5 -0
- data/lib/yavdb.rb +68 -0
- data/lib/yavdb/cli.rb +60 -0
- data/lib/yavdb/constants.rb +34 -0
- data/lib/yavdb/crawler.rb +52 -0
- data/lib/yavdb/database.rb +95 -0
- data/lib/yavdb/dtos/advisory.rb +102 -0
- data/lib/yavdb/source_types/git_repo.rb +35 -0
- data/lib/yavdb/sources/friends_of_php.rb +87 -0
- data/lib/yavdb/sources/nodesecurity_io.rb +120 -0
- data/lib/yavdb/sources/ossindex.rb +137 -0
- data/lib/yavdb/sources/ruby_advisory.rb +117 -0
- data/lib/yavdb/sources/snyk_io.rb +311 -0
- data/lib/yavdb/sources/victims.rb +105 -0
- data/lib/yavdb/utils/cache.rb +96 -0
- data/lib/yavdb/utils/exec.rb +36 -0
- data/lib/yavdb/utils/git.rb +61 -0
- data/lib/yavdb/utils/http.rb +56 -0
- data/lib/yavdb/utils/semver.rb +79 -0
- data/lib/yavdb/utils/zip.rb +64 -0
- data/lib/yavdb/version.rb +21 -0
- data/yavdb.gemspec +44 -0
- metadata +267 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module YAVDB
|
18
|
+
# TODO: Enable `Style/StructInheritance` - check `attr_reader:` or `initialize` method
|
19
|
+
class Advisory <
|
20
|
+
|
21
|
+
Struct.new(
|
22
|
+
:id, # [String]
|
23
|
+
:title, # [String]
|
24
|
+
:description, # [String]
|
25
|
+
:affected_package, # [String]
|
26
|
+
:vulnerable_versions, # [Array<String>] (Optional)
|
27
|
+
:unaffected_versions, # [Array<String>] (Optional)
|
28
|
+
:patched_versions, # [Array<String>] (Optional)
|
29
|
+
:severity, # [String] (Optional)
|
30
|
+
:package_manager, # [String]
|
31
|
+
:cve, # [Array<String>] (Optional)
|
32
|
+
:cwe, # [Array<String>] (Optional)
|
33
|
+
:osvdb, # [String] (Optional)
|
34
|
+
:cvss_v2_vector, # [String] (Optional)
|
35
|
+
:cvss_v2_score, # [String] (Optional)
|
36
|
+
:cvss_v3_vector, # [String] (Optional)
|
37
|
+
:cvss_v3_score, # [String] (Optional)
|
38
|
+
:disclosed_date, # [Date]
|
39
|
+
:created_date, # [Date]
|
40
|
+
:last_modified_date, # [Date]
|
41
|
+
:credit, # [Array<String>]
|
42
|
+
:references, # [Array<String>]
|
43
|
+
:source_url # [String]
|
44
|
+
)
|
45
|
+
|
46
|
+
def self.load(path)
|
47
|
+
data = YAML.load_file(path)
|
48
|
+
|
49
|
+
raise("Advisory data in #{path.dump} was not an Array") unless data.is_a?(Array)
|
50
|
+
|
51
|
+
data.map do |advisory|
|
52
|
+
raise("Advisory data in #{path.dump} was not a Hash") unless advisory.is_a?(Hash)
|
53
|
+
|
54
|
+
new(
|
55
|
+
advisory['id'],
|
56
|
+
advisory['title'],
|
57
|
+
advisory['description'],
|
58
|
+
advisory['affected_package'],
|
59
|
+
advisory['vulnerable_versions'],
|
60
|
+
advisory['unaffected_versions'],
|
61
|
+
advisory['patched_versions'],
|
62
|
+
advisory['severity'],
|
63
|
+
advisory['package_manager'],
|
64
|
+
advisory['cve'],
|
65
|
+
advisory['cwe'],
|
66
|
+
advisory['osvdb'],
|
67
|
+
advisory['cvss_v2_vector'],
|
68
|
+
advisory['cvss_v2_score'],
|
69
|
+
advisory['cvss_v3_vector'],
|
70
|
+
advisory['cvss_v3_score'],
|
71
|
+
advisory['disclosed_date'],
|
72
|
+
advisory['created_date'],
|
73
|
+
advisory['last_modified_date'],
|
74
|
+
advisory['credit'],
|
75
|
+
advisory['references'],
|
76
|
+
advisory['source_url']
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_map
|
82
|
+
map = {}
|
83
|
+
members.each do |m|
|
84
|
+
next unless self[m] && (
|
85
|
+
(self[m].is_a?(String) && !self[m].empty?) ||
|
86
|
+
(self[m].is_a?(Array) && self[m].any?))
|
87
|
+
|
88
|
+
map[m.to_s] = self[m] if self[m]
|
89
|
+
end
|
90
|
+
map
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_json(*args)
|
94
|
+
to_map.to_json(*args)
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_yaml(*args)
|
98
|
+
to_map.to_yaml(*args)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require_relative '../utils/git'
|
18
|
+
|
19
|
+
module YAVDB
|
20
|
+
module SourceTypes
|
21
|
+
module GitRepo
|
22
|
+
|
23
|
+
def self.search(file_pattern, repo_url, repo_branch = 'master', with_cache = true)
|
24
|
+
repo_path = YAVDB::Utils::Git.get_contents(repo_url, repo_branch, with_cache)
|
25
|
+
|
26
|
+
file_paths = Dir.chdir(repo_path) do
|
27
|
+
Dir.glob(file_pattern).select { |f| File.file?(f) }
|
28
|
+
end
|
29
|
+
|
30
|
+
Hash[repo_path => file_paths]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'date'
|
18
|
+
require 'yaml'
|
19
|
+
|
20
|
+
require_relative '../dtos/advisory'
|
21
|
+
require_relative '../source_types/git_repo'
|
22
|
+
|
23
|
+
module YAVDB
|
24
|
+
module Sources
|
25
|
+
module FriendsOfPHP
|
26
|
+
class Client
|
27
|
+
|
28
|
+
REPOSITORY_URLS = [
|
29
|
+
'https://github.com/FriendsOfPHP/security-advisories',
|
30
|
+
'https://github.com/Cotya/magento-security-advisories'
|
31
|
+
].freeze
|
32
|
+
|
33
|
+
PACKAGE_MANAGER = 'packagist'.freeze
|
34
|
+
|
35
|
+
def self.advisories
|
36
|
+
REPOSITORY_URLS.map do |url|
|
37
|
+
YAVDB::SourceTypes::GitRepo.search('*/*/*.yaml', url).map do |repo_path, file_paths|
|
38
|
+
Dir.chdir(repo_path) do
|
39
|
+
file_paths.map do |file_path|
|
40
|
+
advisory_hash = YAML.load_file(file_path)
|
41
|
+
url = "#{url}/blob/master/#{file_path}"
|
42
|
+
create(url, advisory_hash)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end.flatten
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.create(url, advisory_hash)
|
50
|
+
date = Date.parse('1970-01-01')
|
51
|
+
|
52
|
+
versions = advisory_hash['branches'].map do |_, info|
|
53
|
+
date = Date.strptime(info['time'].to_s, '%Y-%m-%d %H:%M:%S %z') if info['time']
|
54
|
+
info['versions'].join(' ')
|
55
|
+
end.flatten
|
56
|
+
|
57
|
+
package_name = advisory_hash['reference'].gsub(%r{composer:\/\/(.*)}, '\1')
|
58
|
+
YAVDB::Advisory.new(
|
59
|
+
"friendsofphp:packagist:#{package_name}:#{date}",
|
60
|
+
advisory_hash['title'],
|
61
|
+
nil, #:description
|
62
|
+
package_name,
|
63
|
+
versions, #:vulnerable_versions
|
64
|
+
nil, #:unaffected_versions
|
65
|
+
nil, #:patched_versions
|
66
|
+
nil, #:severity
|
67
|
+
PACKAGE_MANAGER,
|
68
|
+
[advisory_hash['cve']].reject { |cve| cve == '~' },
|
69
|
+
nil, #:cwe
|
70
|
+
nil, #:osvdb
|
71
|
+
nil, #:cvss_v2_vector
|
72
|
+
nil, #:cvss_v2
|
73
|
+
nil, #:cvss_v3_vector
|
74
|
+
nil, #:cvss_v3
|
75
|
+
date,
|
76
|
+
date,
|
77
|
+
date,
|
78
|
+
['FriendsOfPHP'],
|
79
|
+
[advisory_hash['link']],
|
80
|
+
url
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'oga'
|
18
|
+
require 'oga/xml/entities'
|
19
|
+
require 'date'
|
20
|
+
|
21
|
+
require_relative '../dtos/advisory'
|
22
|
+
require_relative '../utils/http'
|
23
|
+
|
24
|
+
module YAVDB
|
25
|
+
module Sources
|
26
|
+
module NodeSecurityIO
|
27
|
+
class Client
|
28
|
+
|
29
|
+
API_URL = 'https://api.nodesecurity.io/advisories'
|
30
|
+
WEBSITE_URL = 'https://nodesecurity.io/advisories'
|
31
|
+
|
32
|
+
def self.advisories
|
33
|
+
fetch_advisories.map do |advisory_hash|
|
34
|
+
create(advisory_hash)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def fetch_advisories
|
43
|
+
offset = 0
|
44
|
+
advisories = []
|
45
|
+
|
46
|
+
loop do
|
47
|
+
nodesecurity = YAVDB::Utils::HTTP.get_page_contents("#{API_URL}?offset=#{offset}", true, 'nodesecurity.io/advisories')
|
48
|
+
advisories_json = JSON.parse(nodesecurity.join)
|
49
|
+
|
50
|
+
advisories_json['count'].positive? ? advisories = advisories.concat(advisories_json['results']) : break
|
51
|
+
|
52
|
+
offset += advisories_json['count']
|
53
|
+
end
|
54
|
+
|
55
|
+
advisories
|
56
|
+
end
|
57
|
+
|
58
|
+
def create(advisory_hash)
|
59
|
+
publish_date = Date.parse(advisory_hash['publish_date'])
|
60
|
+
created_at = Date.parse(advisory_hash['created_at'])
|
61
|
+
updated_at = Date.parse(advisory_hash['updated_at'])
|
62
|
+
|
63
|
+
vulnerable_versions =
|
64
|
+
if advisory_hash['vulnerable_versions'].nil? || advisory_hash['vulnerable_versions'].empty?
|
65
|
+
'*'
|
66
|
+
else
|
67
|
+
advisory_hash['vulnerable_versions']
|
68
|
+
end
|
69
|
+
|
70
|
+
YAVDB::Advisory.new(
|
71
|
+
"nodesecurity:npm:#{advisory_hash['module_name']}:#{publish_date}",
|
72
|
+
advisory_hash['title'],
|
73
|
+
advisory_hash['overview'],
|
74
|
+
advisory_hash['module_name'],
|
75
|
+
[vulnerable_versions],
|
76
|
+
nil, #:unaffected_versions
|
77
|
+
advisory_hash['patched_versions'],
|
78
|
+
severity(advisory_hash['cvss_score']),
|
79
|
+
'npm',
|
80
|
+
advisory_hash['cves'],
|
81
|
+
nil, #:cwe
|
82
|
+
nil, #:osvdb
|
83
|
+
nil, #:cvss_v2_vector
|
84
|
+
nil, #:cvss_v2_score
|
85
|
+
advisory_hash['cvss_vector'],
|
86
|
+
advisory_hash['cvss_score'],
|
87
|
+
publish_date,
|
88
|
+
created_at,
|
89
|
+
updated_at,
|
90
|
+
[advisory_hash['author']],
|
91
|
+
clean_references(advisory_hash['references']),
|
92
|
+
"#{WEBSITE_URL}/#{advisory_hash['id']}"
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def severity(cvss_score)
|
97
|
+
case cvss_score
|
98
|
+
when 0.0..3.3 then
|
99
|
+
'low'
|
100
|
+
when 3.3..6.6 then
|
101
|
+
'medium'
|
102
|
+
else
|
103
|
+
'high'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def clean_references(references)
|
108
|
+
if references
|
109
|
+
[references.gsub(%r{.*?(http.+)}, '\1')]
|
110
|
+
else
|
111
|
+
[]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# yavdb - The Free and Open Source vulnerability database
|
2
|
+
# Copyright (C) 2017-present Rodrigo Fernandes
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'oga'
|
18
|
+
require 'oga/xml/entities'
|
19
|
+
|
20
|
+
require_relative '../dtos/advisory'
|
21
|
+
require_relative '../utils/http'
|
22
|
+
|
23
|
+
module YAVDB
|
24
|
+
module Sources
|
25
|
+
module OSSIndex
|
26
|
+
class Client
|
27
|
+
|
28
|
+
API_URL = 'https://ossindex.net'
|
29
|
+
PACKAGE_MANAGERS = ['npm', 'maven', 'composer', 'nuget', 'rubygems', 'pypi']
|
30
|
+
PACKAGE_MANAGER_ALIAS = Hash['composer' => 'packagist']
|
31
|
+
|
32
|
+
def self.advisories
|
33
|
+
PACKAGE_MANAGERS.map do |package_manager|
|
34
|
+
packages = fetch_packages(package_manager)
|
35
|
+
parse_vulnerabilities(package_manager, packages)
|
36
|
+
end.flatten
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def fetch_packages(package_manager)
|
44
|
+
next_url = start_url(package_manager)
|
45
|
+
packages = []
|
46
|
+
|
47
|
+
while next_url
|
48
|
+
ossindex = YAVDB::Utils::HTTP.get_page_contents(next_url, true, 'ossindex/advisories')
|
49
|
+
ossindex_json = JSON.parse(ossindex.join)
|
50
|
+
page_packages = ossindex_json['packages']
|
51
|
+
|
52
|
+
packages.concat(page_packages)
|
53
|
+
|
54
|
+
next_url = ossindex_json['next']
|
55
|
+
end
|
56
|
+
|
57
|
+
packages
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_vulnerabilities(package_manager, packages)
|
61
|
+
packages
|
62
|
+
.map do |package|
|
63
|
+
package['vulnerabilities'].map do |advisory|
|
64
|
+
create(package_manager, package, advisory)
|
65
|
+
end
|
66
|
+
end.flatten
|
67
|
+
end
|
68
|
+
|
69
|
+
def create(package_manager, package, advisory)
|
70
|
+
published_date = Date.strptime((advisory['published'] / 1000).to_s, '%s')
|
71
|
+
updated_date = Date.strptime((advisory['updated'] / 1000).to_s, '%s')
|
72
|
+
|
73
|
+
cve = if advisory['cve']
|
74
|
+
[advisory['cve']].map(&:strip).reject(&:empty?)
|
75
|
+
else
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
|
79
|
+
package_manager = PACKAGE_MANAGER_ALIAS[package_manager] || package_manager
|
80
|
+
|
81
|
+
package_name =
|
82
|
+
if package_manager == 'maven'
|
83
|
+
"#{package['group']}:#{package['name']}"
|
84
|
+
elsif package_manager == 'packagist'
|
85
|
+
"#{package['group']}/#{package['name']}"
|
86
|
+
else
|
87
|
+
package['name']
|
88
|
+
end
|
89
|
+
|
90
|
+
versions = advisory['versions']
|
91
|
+
.map { |v| v.split('||') }
|
92
|
+
.flatten
|
93
|
+
.map(&:strip)
|
94
|
+
.reject(&:empty?)
|
95
|
+
.reject { |v| v == '-' }
|
96
|
+
versions = ['*'] unless versions.any?
|
97
|
+
|
98
|
+
YAVDB::Advisory.new(
|
99
|
+
"ossindex:#{package_manager}:#{package_name}:#{published_date}",
|
100
|
+
advisory['title'],
|
101
|
+
advisory['description'],
|
102
|
+
package_name,
|
103
|
+
versions,
|
104
|
+
nil, #:unaffected_versions
|
105
|
+
nil, #:patched_versions
|
106
|
+
nil, #:severity
|
107
|
+
package_manager,
|
108
|
+
cve,
|
109
|
+
nil, #:cwe
|
110
|
+
nil, #:osvdb
|
111
|
+
nil, #:cvss_v2_vector
|
112
|
+
nil, #:cvss_v2_score
|
113
|
+
nil, #:cvss_v3_vector
|
114
|
+
nil, #:cvss_v3_score
|
115
|
+
published_date,
|
116
|
+
published_date,
|
117
|
+
updated_date,
|
118
|
+
['OSSIndex'],
|
119
|
+
advisory['references'],
|
120
|
+
website_url(package['id'])
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def start_url(package_manager)
|
125
|
+
"#{API_URL}/v2.0/vulnerability/pm/#{package_manager}/fromtill/0/-1"
|
126
|
+
end
|
127
|
+
|
128
|
+
def website_url(id)
|
129
|
+
"#{API_URL}/resource/package/#{id}/vulnerabilities"
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|