2015-09-28 23:44:31 +00:00
|
|
|
#!/usr/bin/env ruby
|
|
|
|
|
2018-03-20 11:33:34 +00:00
|
|
|
##
|
|
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
|
|
##
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
require 'patch_finder/core/helper'
|
|
|
|
require 'patch_finder/msu'
|
2015-09-28 23:44:31 +00:00
|
|
|
require 'optparse'
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
class PatchFinderBin
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
include PatchFinder::Helper
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
attr_reader :args
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
def get_parsed_options
|
|
|
|
options = {}
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
parser = OptionParser.new do |opt|
|
|
|
|
opt.separator ''
|
|
|
|
opt.separator 'Specific options:'
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on('-q', '--query <keyword>', 'Find advisories including this keyword') do |v|
|
|
|
|
options[:keyword] = v
|
|
|
|
end
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on('-s', '--search-engine <engine>', '(Optional) The type of search engine to use (Technet or Google). Default: Technet') do |v|
|
|
|
|
case v.to_s
|
|
|
|
when /^google$/i
|
|
|
|
options[:search_engine] = :google
|
|
|
|
when /^technet$/i
|
|
|
|
options[:search_engine] = :technet
|
2015-09-28 23:44:31 +00:00
|
|
|
else
|
2016-03-30 04:21:01 +00:00
|
|
|
fail OptionParser::InvalidOption, "Invalid search engine: #{v}"
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on('-r', '--regex <string>', '(Optional) Specify what type of links you want') do |v|
|
|
|
|
options[:regex] = v
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on('--apikey <key>', '(Optional) Google API key.') do |v|
|
|
|
|
options[:google_api_key] = v
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on('--cx <id>', '(Optional) Google search engine ID.') do |v|
|
|
|
|
options[:google_search_engine_id] = v
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on('-d', '--dir <string>', '(Optional) The directory to save the patches') do |v|
|
|
|
|
unless File.directory?(v)
|
|
|
|
fail OptionParser::InvalidOption, "Directory not found: #{v}"
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
options[:destdir] = v
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
opt.on_tail('-h', '--help', 'Show this message') do
|
|
|
|
$stderr.puts opt
|
|
|
|
exit
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
parser.parse!
|
2015-09-28 23:44:31 +00:00
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
if options.empty?
|
|
|
|
fail OptionParser::MissingArgument, 'No options set, try -h for usage'
|
|
|
|
elsif options[:keyword].nil? || options[:keyword].empty?
|
|
|
|
fail OptionParser::MissingArgument, '-q is required'
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
unless options[:search_engine]
|
|
|
|
options[:search_engine] = :technet
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
if options[:search_engine] == :google
|
|
|
|
if options[:google_api_key].nil? || options[:google_search_engine_id].empty?
|
|
|
|
fail OptionParser::MissingArgument, 'No API key set for Google'
|
|
|
|
elsif options[:google_search_engine_id].nil? || options[:google_search_engine_id].empty?
|
|
|
|
fail OptionParser::MissingArgument, 'No search engine ID set for Google'
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
options
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
def initialize
|
|
|
|
@args = get_parsed_options
|
|
|
|
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
|
|
print_error(e.message)
|
|
|
|
exit
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
|
2016-03-30 04:21:01 +00:00
|
|
|
def main
|
|
|
|
cli = PatchFinder::MSU.new(verbose: true)
|
|
|
|
links = cli.find_msu_download_links(args)
|
|
|
|
if args[:destdir]
|
|
|
|
print_status("Download links found: #{links.length}")
|
|
|
|
print_status('Downloading files, please wait...')
|
|
|
|
download_files(links, args[:destdir])
|
|
|
|
else
|
|
|
|
print_status('Download links found:')
|
|
|
|
print_line(links * "\n")
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if __FILE__ == $PROGRAM_NAME
|
2016-03-30 04:21:01 +00:00
|
|
|
bin = PatchFinderBin.new
|
|
|
|
bin.main
|
2015-09-28 23:44:31 +00:00
|
|
|
end
|