yavdb 0.1.0.pre.alpha.2

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