commit
6eedf6ac03
|
@ -0,0 +1,103 @@
|
|||
load Metasploit::Framework.root.join('tools/egghunter.rb').to_path
|
||||
|
||||
require 'stringio'
|
||||
|
||||
describe Egghunter do
|
||||
|
||||
describe Egghunter::Driver do
|
||||
|
||||
subject do
|
||||
Egghunter::Driver.new
|
||||
end
|
||||
|
||||
let(:egg) {
|
||||
'W00T'
|
||||
}
|
||||
|
||||
describe '#run' do
|
||||
|
||||
def get_stdout(&block)
|
||||
out = $stdout
|
||||
$stdout = fake = StringIO.new
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
$stdout = out
|
||||
end
|
||||
fake.string
|
||||
end
|
||||
|
||||
let(:default_opts) {
|
||||
{ :platform => 'windows', :format => 'c', :eggtag => egg, :arch => 'x86' }
|
||||
}
|
||||
|
||||
before(:each) do
|
||||
allow(Egghunter::OptsConsole).to receive(:parse).with(any_args).and_return(options)
|
||||
end
|
||||
|
||||
context 'when the platform is windows' do
|
||||
let(:options) { default_opts }
|
||||
|
||||
it 'returns a windows egghunter' do
|
||||
output = get_stdout { subject.run }
|
||||
expect(output).to include("\\x66\\x81\\xca\\xff")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the platform is linux' do
|
||||
let(:options) do
|
||||
{ :platform => 'linux', :format => 'c', :eggtag => egg, :arch => 'x86' }
|
||||
end
|
||||
|
||||
it 'returns a linux egghunter' do
|
||||
output = get_stdout { subject.run }
|
||||
expect(output).to include("\\xfc\\x66\\x81\\xc9\\xff")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the egg is WOOT' do
|
||||
let(:options) { default_opts }
|
||||
|
||||
it 'includes W00T in the egghunter' do
|
||||
output = get_stdout { subject.run }
|
||||
expect(output).to include("\\x57\\x30\\x30\\x54")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe Egghunter::OptsConsole do
|
||||
subject do
|
||||
Egghunter::OptsConsole
|
||||
end
|
||||
|
||||
context 'when no options are given' do
|
||||
it 'raises OptionParser::MissingArgument' do
|
||||
expect{subject.parse([])}.to raise_error(OptionParser::MissingArgument)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no format is specified and --list-formats isn\'t used' do
|
||||
it 'raises OptionParser::MissingArgument' do
|
||||
args = '-e AAAA'.split
|
||||
expect{subject.parse(args)}.to raise_error(OptionParser::MissingArgument)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no egg is specified and --list-formats isn\'t used' do
|
||||
it 'raises OptionParser::MissingArgument' do
|
||||
args = '-f python'.split
|
||||
expect{subject.parse(args)}.to raise_error(OptionParser::MissingArgument)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :depsize is a string' do
|
||||
it 'raises OptionParser::InvalidOption' do
|
||||
args = '-e AAAA -f c --depsize STRING'.split
|
||||
expect{subject.parse(args)}.to raise_error(OptionParser::InvalidOption)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,156 @@
|
|||
#!/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')))
|
||||
require 'msfenv'
|
||||
require 'rex'
|
||||
require 'msf/core'
|
||||
require 'msf/base'
|
||||
require 'optparse'
|
||||
|
||||
module Egghunter
|
||||
class OptsConsole
|
||||
def self.parse(args)
|
||||
options = {}
|
||||
parser = OptionParser.new do |opt|
|
||||
opt.banner = "Usage: #{__FILE__} [options]\nExample: #{__FILE__} -f python -e W00T"
|
||||
opt.separator ''
|
||||
opt.separator 'Specific options:'
|
||||
|
||||
opt.on('-f', '--format <String>', "See --list-formats for a list of supported output formats") do |v|
|
||||
options[:format] = v
|
||||
end
|
||||
|
||||
opt.on('-b', '--badchars <String>', "(Optional) Bad characters to avoid for the egg") do |v|
|
||||
options[:badchars] = v
|
||||
end
|
||||
|
||||
opt.on('-e', '--egg <String>', "The egg (Please give 4 bytes)") do |v|
|
||||
options[:eggtag] = v
|
||||
end
|
||||
|
||||
opt.on('-p', '--platform <String>', "(Optional) Platform") do |v|
|
||||
options[:platform] = v
|
||||
end
|
||||
|
||||
opt.on('--startreg <String>', "(Optional) The starting register") do |v|
|
||||
# Do not change this key. This should matching the one in Rex::Exploitation::Egghunter
|
||||
options[:startreg] = v
|
||||
end
|
||||
|
||||
opt.on('--forward', "(Optional) To search forward") do |v|
|
||||
# Do not change this key. This should matching the one in Rex::Exploitation::Egghunter
|
||||
options[:searchforward] = true
|
||||
end
|
||||
|
||||
opt.on('--depreg <String>', "(Optional) The DEP register") do |v|
|
||||
# Do not change this key. This should matching the one in Rex::Exploitation::Egghunter
|
||||
options[:depreg] = v
|
||||
end
|
||||
|
||||
opt.on('--depdest <String>', "(Optional) The DEP destination") do |v|
|
||||
# Do not change this key. This should matching the one in Rex::Exploitation::Egghunter
|
||||
options[:depdest] = v
|
||||
end
|
||||
|
||||
opt.on('--depsize <Fixnum>', "(Optional) The DEP size") do |v|
|
||||
# Do not change this key. This should matching the one in Rex::Exploitation::Egghunter
|
||||
options[:depsize] = v
|
||||
end
|
||||
|
||||
opt.on('--depmethod <String>', "(Optional) The DEP method to use (virtualprotect/virtualalloc/copy/copy_size)") do |v|
|
||||
# Do not change this key. This should matching the one in Rex::Exploitation::Egghunter
|
||||
options[:depmethod] = v
|
||||
end
|
||||
|
||||
opt.on('-a', '--arch <String>', "(Optional) Architecture") do |v|
|
||||
# Although this is an option, this is currently useless because we don't have x64 egghunters
|
||||
options[:arch] = v
|
||||
end
|
||||
|
||||
opt.on('--list-formats', "List all supported output formats") do
|
||||
options[:list_formats] = true
|
||||
end
|
||||
|
||||
opt.on('-v', '--var-name <name>', String, '(Optional) Specify a custom variable name to use for certain output formats') do |v|
|
||||
options[:var_name] = v
|
||||
end
|
||||
|
||||
opt.on_tail('-h', '--help', 'Show this message') do
|
||||
$stdout.puts opt
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
parser.parse!(args)
|
||||
|
||||
if options.empty?
|
||||
raise OptionParser::MissingArgument, 'No options set, try -h for usage'
|
||||
elsif options[:format].blank? && !options[:list_formats]
|
||||
raise OptionParser::MissingArgument, '-f is required'
|
||||
elsif options[:eggtag].blank? && !options[:list_formats]
|
||||
raise OptionParser::MissingArgument, '-e is required'
|
||||
elsif options[:format] && !::Msf::Simple::Buffer.transform_formats.include?(options[:format])
|
||||
raise OptionParser::InvalidOption, "#{options[:format]} is not a valid format"
|
||||
elsif options[:depsize] && options[:depsize] !~ /^\d+$/
|
||||
raise OptionParser::InvalidOption, "--depsize must be a Fixnum"
|
||||
end
|
||||
|
||||
options[:badchars] = '' unless options[:badchars]
|
||||
options[:platform] = 'windows' unless options[:platform]
|
||||
options[:arch] = ARCH_X86 unless options[:arch]
|
||||
options[:var_name] = 'buf' unless options[:var_name]
|
||||
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
class Driver
|
||||
def initialize
|
||||
begin
|
||||
@opts = OptsConsole.parse(ARGV)
|
||||
rescue OptionParser::ParseError => e
|
||||
$stderr.puts "[x] #{e.message}"
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
# list_formats should check first
|
||||
if @opts[:list_formats]
|
||||
list_formats
|
||||
return
|
||||
end
|
||||
|
||||
egghunter = Rex::Exploitation::Egghunter.new(@opts[:platform], @opts[:arch])
|
||||
raw_code = egghunter.hunter_stub('', @opts[:badchars], @opts)
|
||||
output_stream = $stdout
|
||||
output_stream.binmode
|
||||
output_stream.write ::Msf::Simple::Buffer.transform(raw_code, @opts[:format], @opts[:var_name])
|
||||
$stderr.puts
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def list_formats
|
||||
$stderr.puts "[*] Supported output formats:"
|
||||
$stderr.puts ::Msf::Simple::Buffer.transform_formats.join(", ")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if __FILE__ == $PROGRAM_NAME
|
||||
driver = Egghunter::Driver.new
|
||||
begin
|
||||
driver.run
|
||||
rescue ::Exception => e
|
||||
elog("#{e.class}: #{e.message}\n#{e.backtrace * "\n"}")
|
||||
$stderr.puts "[x] #{e.class}: #{e.message}"
|
||||
$stderr.puts "[*] If necessary, please refer to framework.log for more details."
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue