CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/tools/modules/cve_xref.rb
Views: 1904
1
#!/usr/bin/env ruby
2
3
msfbase = __FILE__
4
while File.symlink?(msfbase)
5
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
6
end
7
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
8
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
9
10
require 'nokogiri'
11
12
module CVE
13
class XRefTable
14
15
attr_reader :module_full_name_ref
16
attr_reader :edb_ref
17
attr_reader :bid_ref
18
attr_reader :osvdb_ref
19
attr_reader :msb_ref
20
attr_reader :zdi_ref
21
attr_reader :url_refs
22
23
def initialize(refs)
24
@module_full_name_ref = refs['fullname']
25
@edb_ref = refs['EDB']
26
@bid_ref = refs['BID']
27
@osvdb_ref = refs['OSVDB']
28
@msb_ref = refs['MSB']
29
@zdi_ref = refs['ZDI']
30
@url_refs = refs['URL']
31
end
32
33
def has_match?(ref_match)
34
if (
35
(module_full_name_ref && ref_match.match(/#{module_full_name_ref}/)) ||
36
(edb_ref && ref_match.match(/EXPLOIT\-DB:#{edb_ref}$/)) ||
37
(osvdb_ref && ref_match.match(/OSVDB:#{osvdb_ref}$/)) ||
38
(bid_ref && ref_match.match(/BID:#{bid_ref}$/)) ||
39
(msb_ref && ref_match.match(/http:\/\/technet\.microsoft\.com\/security\/bulletin\/#{msb_ref}$/)) ||
40
(zdi_ref && ref_match.match(/zerodayinitiative\.com\/advisories\/ZDI\-#{zdi_ref}/)) ||
41
(url_refs_match?(ref_match))
42
)
43
return true
44
end
45
46
false
47
end
48
49
private
50
51
def url_refs_match?(ref_match)
52
return false unless url_refs
53
return false unless ref_match.match(/^http/)
54
55
url_refs.each do |url|
56
return true if url == ref_match
57
end
58
59
false
60
end
61
end
62
63
class Database
64
attr_reader :database
65
66
def initialize(db_path)
67
@database = normalize(db_path)
68
end
69
70
def cross_reference(reference_matches)
71
return nil if reference_matches.empty?
72
xref_table = XRefTable.new(reference_matches)
73
74
database.each_pair do |cve_name, references|
75
references.each do |cve_ref|
76
if xref_table.has_match?(cve_ref)
77
return cve_name
78
end
79
end
80
end
81
82
nil
83
end
84
85
private
86
87
def normalize(db_path)
88
html = load_cve_html_file(db_path)
89
normalize_html_to_hash(html)
90
end
91
92
def load_cve_html_file(db_path)
93
puts "[*] Loading database..."
94
raw_data = File.read(db_path)
95
Nokogiri::HTML(raw_data)
96
end
97
98
def normalize_html_to_hash(html)
99
puts "[*] Normalizing database..."
100
101
db = {}
102
current_cve = nil
103
metasploit_refs = []
104
html.traverse do |element|
105
if current_cve
106
if element.text =~ /(https*:\/\/.*metasploit.+)/
107
metasploit_refs << $1
108
elsif element.text =~ /(http:\/\/www\.exploit\-db\.com\/.+)/
109
metasploit_refs << $1
110
elsif element.text =~ /(BID:\d+)/
111
metasploit_refs << $1
112
elsif element.text =~ /(OSVDB:\d+)/
113
metasploit_refs << $1
114
elsif element.text =~ /http:\/\/technet\.microsoft\.com\/security\/bulletin\/(MS\d+\-\d+)$/
115
metasploit_refs << $1
116
elsif element.text =~ /zerodayinitiative\.com\/advisories\/(ZDI\-\d+\-\d+)/
117
metasploit_refs << $1
118
elsif element.text =~ /URL:(http.+)/
119
metasploit_refs << $1
120
end
121
end
122
123
if element.text =~ /^Name: (CVE\-\d+\-\d+)$/
124
current_cve = $1
125
elsif element.text =~ /^Votes:/
126
unless metasploit_refs.empty?
127
db[current_cve] = metasploit_refs
128
end
129
current_cve = nil
130
metasploit_refs = []
131
end
132
end
133
134
db
135
end
136
end
137
138
end
139
140
class Utility
141
def self.ignore_module?(module_full_name)
142
[
143
'exploit/multi/handler'
144
].include?(module_full_name)
145
end
146
147
def self.collect_references_from_module!(module_references, ref_ids, mod)
148
if ref_ids.include?('EDB')
149
edb_ref = mod.references.select { |r| r.ctx_id == 'EDB' }.first.ctx_val
150
module_references['EDB'] = edb_ref
151
end
152
153
if ref_ids.include?('BID')
154
bid_ref = mod.references.select { |r| r.ctx_id == 'BID' }.first.ctx_val
155
module_references['BID'] = bid_ref
156
end
157
158
if ref_ids.include?('OSVDB')
159
osvdb_ref = mod.references.select { |r| r.ctx_id == 'OSVDB' }.first.ctx_val
160
module_references['OSVDB'] = osvdb_ref
161
end
162
163
if ref_ids.include?('MSB')
164
msb_ref = mod.references.select { |r| r.ctx_id == 'MSB' }.first.ctx_val
165
module_references['MSB'] = msb_ref
166
end
167
168
if ref_ids.include?('ZDI')
169
zdi_ref = mod.references.select { |r| r.ctx_id == 'ZDI' }.first.ctx_val
170
module_references['ZDI'] = zdi_ref
171
end
172
173
if ref_ids.include?('URL')
174
url_refs = mod.references.select { |r| r.ctx_id == 'URL' }.collect { |r| r.ctx_val if r }
175
module_references['URL'] = url_refs
176
end
177
end
178
179
end
180
181
require 'msfenv'
182
183
def main
184
filter = 'All'
185
filters = ['all','exploit','payload','post','nop','encoder','auxiliary']
186
type = 'CVE'
187
db_path = nil
188
189
opts = Rex::Parser::Arguments.new(
190
"-h" => [ false, 'Help menu.' ],
191
"-f" => [ true, 'Filter based on Module Type [All,Exploit,Payload,Post,NOP,Encoder,Auxiliary] (Default = ALL).'],
192
"-d" => [ true, 'Source of CVE database in HTML (allitems.html)'],
193
)
194
195
opts.parse(ARGV) { |opt, idx, val|
196
case opt
197
when "-h"
198
puts "\nMetasploit script for finding CVEs from other references."
199
puts "=========================================================="
200
puts opts.usage
201
exit
202
when "-f"
203
unless filters.include?(val.downcase)
204
puts "Invalid Filter Supplied: #{val}"
205
puts "Please use one of these: #{filters.map{|f|f.capitalize}.join(", ")}"
206
exit
207
end
208
filter = val
209
when "-d"
210
unless File.exist?(val.to_s)
211
raise RuntimeError, "#{val} not found"
212
end
213
214
db_path = val
215
end
216
}
217
218
framework_opts = { 'DisableDatabase' => true }
219
framework_opts[:module_types] = [ filter.downcase ] if filter.downcase != 'all'
220
$framework = Msf::Simple::Framework.create(framework_opts)
221
cve_database = CVE::Database.new(db_path)
222
223
puts "[*] Going through Metasploit modules for missing references..."
224
$framework.modules.each { |name, mod|
225
if mod.nil?
226
elog("Unable to load #{name}")
227
next
228
end
229
230
elog "Loading #{name}"
231
m = mod.new
232
next if Utility.ignore_module?(m.fullname)
233
234
ref_ids = m.references.collect { |r| r.ctx_id }
235
next if ref_ids.include?(type)
236
237
elog "Checking references for #{m.fullname}"
238
module_references = {}
239
module_references['fullname'] = m.fullname
240
Utility.collect_references_from_module!(module_references, ref_ids, m)
241
cve_match = cve_database.cross_reference(module_references)
242
if cve_match
243
puts "[*] #{m.fullname}: Found #{cve_match}"
244
end
245
}
246
end
247
248
if __FILE__ == $PROGRAM_NAME
249
main
250
end
251
252
253