123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- #!/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
|