253 lines
6.9 KiB
Ruby
253 lines
6.9 KiB
Ruby
#!/usr/bin/env ruby
|
|
|
|
msfbase = __FILE__
|
|
while File.symlink?(msfbase)
|
|
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
|
end
|
|
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
|
|
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
|
|
|
require 'nokogiri'
|
|
|
|
module CVE
|
|
class XRefTable
|
|
|
|
attr_reader :module_full_name_ref
|
|
attr_reader :edb_ref
|
|
attr_reader :bid_ref
|
|
attr_reader :osvdb_ref
|
|
attr_reader :msb_ref
|
|
attr_reader :zdi_ref
|
|
attr_reader :url_refs
|
|
|
|
def initialize(refs)
|
|
@module_full_name_ref = refs['fullname']
|
|
@edb_ref = refs['EDB']
|
|
@bid_ref = refs['BID']
|
|
@osvdb_ref = refs['OSVDB']
|
|
@msb_ref = refs['MSB']
|
|
@zdi_ref = refs['ZDI']
|
|
@url_refs = refs['URL']
|
|
end
|
|
|
|
def has_match?(ref_match)
|
|
if (
|
|
(module_full_name_ref && ref_match.match(/#{module_full_name_ref}/)) ||
|
|
(edb_ref && ref_match.match(/EXPLOIT\-DB:#{edb_ref}$/)) ||
|
|
(osvdb_ref && ref_match.match(/OSVDB:#{osvdb_ref}$/)) ||
|
|
(bid_ref && ref_match.match(/BID:#{bid_ref}$/)) ||
|
|
(msb_ref && ref_match.match(/http:\/\/technet\.microsoft\.com\/security\/bulletin\/#{msb_ref}$/)) ||
|
|
(zdi_ref && ref_match.match(/zerodayinitiative\.com\/advisories\/ZDI\-#{zdi_ref}/)) ||
|
|
(url_refs_match?(ref_match))
|
|
)
|
|
return true
|
|
end
|
|
|
|
false
|
|
end
|
|
|
|
private
|
|
|
|
def url_refs_match?(ref_match)
|
|
return false unless url_refs
|
|
return false unless ref_match.match(/^http/)
|
|
|
|
url_refs.each do |url|
|
|
return true if url == ref_match
|
|
end
|
|
|
|
false
|
|
end
|
|
end
|
|
|
|
class Database
|
|
attr_reader :database
|
|
|
|
def initialize(db_path)
|
|
@database = normalize(db_path)
|
|
end
|
|
|
|
def cross_reference(reference_matches)
|
|
return nil if reference_matches.empty?
|
|
xref_table = XRefTable.new(reference_matches)
|
|
|
|
database.each_pair do |cve_name, references|
|
|
references.each do |cve_ref|
|
|
if xref_table.has_match?(cve_ref)
|
|
return cve_name
|
|
end
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
private
|
|
|
|
def normalize(db_path)
|
|
html = load_cve_html_file(db_path)
|
|
normalize_html_to_hash(html)
|
|
end
|
|
|
|
def load_cve_html_file(db_path)
|
|
puts "[*] Loading database..."
|
|
raw_data = File.read(db_path)
|
|
Nokogiri::HTML(raw_data)
|
|
end
|
|
|
|
def normalize_html_to_hash(html)
|
|
puts "[*] Normalizing database..."
|
|
|
|
db = {}
|
|
current_cve = nil
|
|
metasploit_refs = []
|
|
html.traverse do |element|
|
|
if current_cve
|
|
if element.text =~ /(https*:\/\/.*metasploit.+)/
|
|
metasploit_refs << $1
|
|
elsif element.text =~ /(http:\/\/www\.exploit\-db\.com\/.+)/
|
|
metasploit_refs << $1
|
|
elsif element.text =~ /(BID:\d+)/
|
|
metasploit_refs << $1
|
|
elsif element.text =~ /(OSVDB:\d+)/
|
|
metasploit_refs << $1
|
|
elsif element.text =~ /http:\/\/technet\.microsoft\.com\/security\/bulletin\/(MS\d+\-\d+)$/
|
|
metasploit_refs << $1
|
|
elsif element.text =~ /zerodayinitiative\.com\/advisories\/(ZDI\-\d+\-\d+)/
|
|
metasploit_refs << $1
|
|
elsif element.text =~ /URL:(http.+)/
|
|
metasploit_refs << $1
|
|
end
|
|
end
|
|
|
|
if element.text =~ /^Name: (CVE\-\d+\-\d+)$/
|
|
current_cve = $1
|
|
elsif element.text =~ /^Votes:/
|
|
unless metasploit_refs.empty?
|
|
db[current_cve] = metasploit_refs
|
|
end
|
|
current_cve = nil
|
|
metasploit_refs = []
|
|
end
|
|
end
|
|
|
|
db
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
class Utility
|
|
def self.ignore_module?(module_full_name)
|
|
[
|
|
'exploit/multi/handler'
|
|
].include?(module_full_name)
|
|
end
|
|
|
|
def self.collect_references_from_module!(module_references, ref_ids, mod)
|
|
if ref_ids.include?('EDB')
|
|
edb_ref = mod.references.select { |r| r.ctx_id == 'EDB' }.first.ctx_val
|
|
module_references['EDB'] = edb_ref
|
|
end
|
|
|
|
if ref_ids.include?('BID')
|
|
bid_ref = mod.references.select { |r| r.ctx_id == 'BID' }.first.ctx_val
|
|
module_references['BID'] = bid_ref
|
|
end
|
|
|
|
if ref_ids.include?('OSVDB')
|
|
osvdb_ref = mod.references.select { |r| r.ctx_id == 'OSVDB' }.first.ctx_val
|
|
module_references['OSVDB'] = osvdb_ref
|
|
end
|
|
|
|
if ref_ids.include?('MSB')
|
|
msb_ref = mod.references.select { |r| r.ctx_id == 'MSB' }.first.ctx_val
|
|
module_references['MSB'] = msb_ref
|
|
end
|
|
|
|
if ref_ids.include?('ZDI')
|
|
zdi_ref = mod.references.select { |r| r.ctx_id == 'ZDI' }.first.ctx_val
|
|
module_references['ZDI'] = zdi_ref
|
|
end
|
|
|
|
if ref_ids.include?('URL')
|
|
url_refs = mod.references.select { |r| r.ctx_id == 'URL' }.collect { |r| r.ctx_val if r }
|
|
module_references['URL'] = url_refs
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
require 'msfenv'
|
|
require 'msf/base'
|
|
|
|
def main
|
|
filter = 'All'
|
|
filters = ['all','exploit','payload','post','nop','encoder','auxiliary']
|
|
type = 'CVE'
|
|
db_path = nil
|
|
|
|
opts = Rex::Parser::Arguments.new(
|
|
"-h" => [ false, 'Help menu.' ],
|
|
"-f" => [ true, 'Filter based on Module Type [All,Exploit,Payload,Post,NOP,Encoder,Auxiliary] (Default = ALL).'],
|
|
"-d" => [ true, 'Source of CVE database in HTML (allitems.html)'],
|
|
)
|
|
|
|
opts.parse(ARGV) { |opt, idx, val|
|
|
case opt
|
|
when "-h"
|
|
puts "\nMetasploit script for finding CVEs from other references."
|
|
puts "=========================================================="
|
|
puts opts.usage
|
|
exit
|
|
when "-f"
|
|
unless filters.include?(val.downcase)
|
|
puts "Invalid Filter Supplied: #{val}"
|
|
puts "Please use one of these: #{filters.map{|f|f.capitalize}.join(", ")}"
|
|
exit
|
|
end
|
|
filter = val
|
|
when "-d"
|
|
unless File.exists?(val.to_s)
|
|
raise RuntimeError, "#{val} not found"
|
|
end
|
|
|
|
db_path = val
|
|
end
|
|
}
|
|
|
|
framework_opts = { 'DisableDatabase' => true }
|
|
framework_opts[:module_types] = [ filter.downcase ] if filter.downcase != 'all'
|
|
$framework = Msf::Simple::Framework.create(framework_opts)
|
|
cve_database = CVE::Database.new(db_path)
|
|
|
|
puts "[*] Going through Metasploit modules for missing references..."
|
|
$framework.modules.each { |name, mod|
|
|
if mod.nil?
|
|
elog("Unable to load #{name}")
|
|
next
|
|
end
|
|
|
|
elog "Loading #{name}"
|
|
m = mod.new
|
|
next if Utility.ignore_module?(m.fullname)
|
|
|
|
ref_ids = m.references.collect { |r| r.ctx_id }
|
|
next if ref_ids.include?(type)
|
|
|
|
elog "Checking references for #{m.fullname}"
|
|
module_references = {}
|
|
module_references['fullname'] = m.fullname
|
|
Utility.collect_references_from_module!(module_references, ref_ids, m)
|
|
cve_match = cve_database.cross_reference(module_references)
|
|
if cve_match
|
|
puts "[*] #{m.fullname}: Found #{cve_match}"
|
|
end
|
|
}
|
|
end
|
|
|
|
if __FILE__ == $PROGRAM_NAME
|
|
main
|
|
end
|
|
|