mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
3bc40b8fe4
That way, people can see why this is if they care to. While we have a link to the blog post at http://r-7.co/msfvenom-2015 , I fear that by the time spring of 2015 rolls around, we'll be on a different blogging platform and the link may be busted. I'm certain we'll still be on GitHub then, though.
307 lines
7.9 KiB
Ruby
Executable File
307 lines
7.9 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
# -*- coding: binary -*-
|
|
#
|
|
# $Id$
|
|
# $Revision$
|
|
#
|
|
|
|
$stderr.puts "[!] ************************************************************************"
|
|
$stderr.puts "[!] * The utility msfencode is deprecated! *"
|
|
$stderr.puts "[!] * It will be removed on or about 2015-06-08 *"
|
|
$stderr.puts "[!] * Please use msfvenom instead *"
|
|
$stderr.puts "[!] * Details: https://github.com/rapid7/metasploit-framework/pull/4333 *"
|
|
$stderr.puts "[!] ************************************************************************"
|
|
|
|
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'
|
|
|
|
|
|
|
|
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
|
|
|
require 'rex'
|
|
require 'msf/ui'
|
|
require 'msf/base'
|
|
|
|
OutStatus = "[*] "
|
|
OutError = "[-] "
|
|
|
|
# Load supported formats
|
|
supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
|
|
|
|
$args = Rex::Parser::Arguments.new(
|
|
"-h" => [ false, "Help banner" ],
|
|
"-l" => [ false, "List available encoders" ],
|
|
"-v" => [ false, "Increase verbosity" ],
|
|
# input/output
|
|
"-i" => [ true, "Encode the contents of the supplied file path" ],
|
|
"-m" => [ true, "Specifies an additional module search path" ],
|
|
"-o" => [ true, "The output file" ],
|
|
# architecture/platform
|
|
"-a" => [ true, "The architecture to encode as" ],
|
|
"-p" => [ true, "The platform to encode for" ],
|
|
# format options
|
|
"-t" => [ true, "The output format: #{supported_formats.join(',')}" ],
|
|
# encoder options
|
|
"-e" => [ true, "The encoder to use" ],
|
|
"-n" => [ false, "Dump encoder information" ],
|
|
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
|
|
"-s" => [ true, "The maximum size of the encoded data" ],
|
|
"-c" => [ true, "The number of times to encode the data" ],
|
|
# EXE generation options
|
|
"-d" => [ true, "Specify the directory in which to look for EXE templates" ],
|
|
"-x" => [ true, "Specify an alternate executable template" ],
|
|
"-k" => [ false, "Keep template working; run payload in new thread (use with -x)" ]
|
|
)
|
|
|
|
#
|
|
# Dump the list of encoders
|
|
#
|
|
def dump_encoders(arch = nil)
|
|
tbl = Rex::Ui::Text::Table.new(
|
|
'Indent' => 4,
|
|
'Header' => "Framework Encoders" + ((arch) ? " (architectures: #{arch})" : ""),
|
|
'Columns' =>
|
|
[
|
|
"Name",
|
|
"Rank",
|
|
"Description"
|
|
])
|
|
cnt = 0
|
|
|
|
$framework.encoders.each_module(
|
|
'Arch' => arch ? arch.split(',') : nil) { |name, mod|
|
|
tbl << [ name, mod.rank_to_s, mod.new.name ]
|
|
|
|
cnt += 1
|
|
}
|
|
|
|
(cnt > 0) ? "\n" + tbl.to_s + "\n" : "\nNo compatible encoders found.\n\n"
|
|
end
|
|
|
|
#
|
|
# Returns the list of encoders to try
|
|
#
|
|
def get_encoders(arch, encoder)
|
|
encoders = []
|
|
|
|
if (encoder)
|
|
encoders << $framework.encoders.create(encoder)
|
|
else
|
|
$framework.encoders.each_module_ranked(
|
|
'Arch' => arch ? arch.split(',') : nil) { |name, mod|
|
|
encoders << mod.new
|
|
}
|
|
end
|
|
|
|
encoders
|
|
end
|
|
|
|
#
|
|
# Nuff said.
|
|
#
|
|
def usage
|
|
$stderr.puts("\n" + " Usage: #{$0} <options>\n" + $args.usage)
|
|
exit
|
|
end
|
|
|
|
def write_encoded(buf)
|
|
if (not $output)
|
|
$stdout.write(buf)
|
|
else
|
|
File.open($output, "wb") do |fd|
|
|
fd.write(buf)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Defaults
|
|
verbose = 0
|
|
cmd = "encode"
|
|
arch = nil
|
|
badchars = ''
|
|
space = nil
|
|
encoder = nil
|
|
fmt = nil
|
|
input = $stdin
|
|
options = ''
|
|
delim = '_|_'
|
|
output = nil
|
|
ecount = 1
|
|
plat = nil
|
|
|
|
altexe = nil
|
|
inject = false
|
|
exedir = nil # use default
|
|
|
|
# Parse the argument and rock it
|
|
$args.parse(ARGV) { |opt, idx, val|
|
|
case opt
|
|
when "-i"
|
|
begin
|
|
input = File.open(val, 'rb')
|
|
rescue
|
|
$stderr.puts(OutError + "Failed to open file #{val}: #{$!}")
|
|
exit
|
|
end
|
|
when "-m"
|
|
$framework.modules.add_module_path(val)
|
|
when "-l"
|
|
cmd = "list"
|
|
when "-n"
|
|
cmd = "dump"
|
|
when "-a"
|
|
arch = val
|
|
when "-c"
|
|
ecount = val.to_i
|
|
when "-b"
|
|
badchars = Rex::Text.hex_to_raw(val)
|
|
when "-p"
|
|
plat = Msf::Module::PlatformList.transform(val)
|
|
when "-s"
|
|
space = val.to_i
|
|
when "-t"
|
|
if supported_formats.include?(val)
|
|
fmt = val
|
|
else
|
|
$stderr.puts(OutError + "Invalid format: #{val}")
|
|
exit
|
|
end
|
|
when "-o"
|
|
$output = val
|
|
when "-e"
|
|
encoder = val
|
|
|
|
when "-d"
|
|
exedir = val
|
|
when "-x"
|
|
altexe = val
|
|
when "-k"
|
|
inject = true
|
|
|
|
when "-h"
|
|
usage
|
|
|
|
when "-v"
|
|
verbose += 1
|
|
|
|
else
|
|
if (val =~ /=/)
|
|
options += ((options.length > 0) ? delim : "") + "#{val}"
|
|
end
|
|
end
|
|
}
|
|
|
|
|
|
if(not fmt and output)
|
|
pre,ext = output.split('.')
|
|
if(ext and not ext.empty?)
|
|
fmt = ext
|
|
end
|
|
end
|
|
|
|
if inject and not altexe
|
|
$stderr.puts "[*] Error: the injection option must use a custom EXE template via -x, otherwise the injected payload will immediately exit when the main process dies."
|
|
exit(1)
|
|
end
|
|
exeopts = {
|
|
:inject => inject,
|
|
:template => altexe,
|
|
:template_path => exedir
|
|
}
|
|
|
|
# Initialize the simplified framework instance.
|
|
$framework = Msf::Simple::Framework.create(
|
|
:module_types => [ Msf::MODULE_ENCODER, Msf::MODULE_NOP ],
|
|
'DisableDatabase' => true
|
|
)
|
|
|
|
# Get the list of encoders to try
|
|
encoders = get_encoders(arch, encoder)
|
|
|
|
# Process the actual command
|
|
case cmd
|
|
when "list"
|
|
$stderr.puts(dump_encoders(arch))
|
|
when "dump"
|
|
enc = encoder ? $framework.encoders.create(encoder) : nil
|
|
|
|
if (enc)
|
|
$stderr.puts(Msf::Serializer::ReadableText.dump_module(enc))
|
|
else
|
|
$stderr.puts(OutError + "Invalid encoder specified.")
|
|
end
|
|
when "encode"
|
|
input.binmode # ensure its in binary mode
|
|
buf = input.read
|
|
|
|
encoders.each { |enc|
|
|
next if not enc
|
|
begin
|
|
# Imports options
|
|
enc.datastore.import_options_from_s(options, delim)
|
|
|
|
skip = false
|
|
eout = buf.dup
|
|
raw = nil
|
|
|
|
1.upto(ecount) do |iteration|
|
|
|
|
# Encode it up
|
|
raw = enc.encode(eout, badchars, nil, plat)
|
|
|
|
# Is it too big?
|
|
if (space and space > 0 and raw.length > space)
|
|
$stderr.puts(OutError + "#{enc.refname} created buffer that is too big (#{raw.length})")
|
|
skip = true
|
|
break
|
|
end
|
|
|
|
# Print it out
|
|
$stderr.puts(OutStatus + "#{enc.refname} succeeded with size #{raw.length} (iteration=#{iteration})\n\n")
|
|
eout = raw
|
|
end
|
|
|
|
next if skip
|
|
|
|
output = Msf::Util::EXE.to_executable_fmt($framework, arch, plat, raw, fmt, exeopts)
|
|
|
|
if not output
|
|
fmt ||= "ruby"
|
|
output = Msf::Simple::Buffer.transform(raw, fmt)
|
|
end
|
|
|
|
if exeopts[:fellback]
|
|
$stderr.puts(OutError + "Warning: Falling back to default template: #{exeopts[:fellback]}")
|
|
end
|
|
|
|
write_encoded(output)
|
|
|
|
exit
|
|
|
|
#
|
|
# These exception codes are fatal, we shouldn't expect them to succeed on the next
|
|
# iteration, nor the next encoder.
|
|
#
|
|
rescue ::Errno::ENOENT, ::Errno::EINVAL
|
|
$stderr.puts(OutError + "#{enc.refname} failed: #{$!}")
|
|
break
|
|
|
|
rescue => e
|
|
$stderr.puts(OutError + "#{enc.refname} failed: #{e}")
|
|
if verbose > 0
|
|
e.backtrace.each { |el|
|
|
$stderr.puts(OutError + el.to_s)
|
|
}
|
|
end
|
|
end
|
|
}
|
|
|
|
$stderr.puts(OutError + "No encoders succeeded.")
|
|
end
|