Nmap Development mailing list archives
[RFC] NSE script - HTTP authentication
From: Thomas Buchanan <tbuchanan () thecompassgrp net>
Date: Fri, 25 May 2007 14:19:11 -0500
I've been playing around with this script internally for a few weeks now, and would love to get some feedback from the nmap-dev community on it. I also have some questions, but I'll get to those after some background on the script itself
Description: A NSE script to detect when a HTTP service requires authentication. It attempts to extract some information about the authentication request, such as the authentication type (Basic/Digest/NTLM/etc.) as well as the authorization realm presented, in the case of Basic or Digest auth types.
Bonus: If the script detects that Basic authentication is used, it will try two common default username and password combinations, and checks to see if the server responds with response code other than 401 Unauthorized or 403 Forbidden. This is a quick and dirty method for finding HTTP services with admin as the username with a blank password, or admin as both the username and the password.
Example output:nmap# NMAPDIR=. ./nmap -sSV --script=httpAuth.nse -p 80,280,8080 192.168.xxx.yy
Starting Nmap 4.21ALPHA5 ( http://insecure.org ) at 2007-05-25 13:33 CDT Interesting ports on 192.168.xxx.yy: PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS webserver 5.1 | HTTP Auth: HTTP Service requires authentication | Auth type: Negotiate | Auth type: NTLM | Auth type: Basic, realm = local |_ Auth type: Digest, realm = local 280/tcp filtered http-mgmt 8080/tcp open http Apache httpd 2.2.4 | HTTP Auth: HTTP Service requires authentication | Auth type: Basic, realm = Restricted|_ HTTP server may accept user="admin" with password="admin" for Basic authentication
Service Info: OS: WindowsService detection performed. Please report any incorrect results at http://insecure.org/nmap/submit/ .
Nmap finished: 1 IP address (1 host up) scanned in 24.848 secondsThis script can be very helpful in identifying SOHO gateway routers / wireless access points, as they often identify themselves in the HTTP auth realm field. An example:
PORT STATE SERVICE VERSION 80/tcp open tcpwrapped | HTTP Auth: HTTP Service requires authentication |_ Auth type: Basic, realm = Linksys BEFVP41 V2This is my first experience programming in Lua, and I'd be glad to get some pointers to how my coding style / efficiency could be improved.
Now on to some of the questions that came up while I was working on this script.
1. Does the NSE system provide a method to access the original host argument that was given to the nmap command? I know you can get the reverse DNS name of a host, but when talking to HTTP services that do virtual name-based hosting, you might not get the same results as when using the original forward DNS name. For example, the IP address for scanme.insecure.org has the reverse DNS name of scanme.nmap.org. This doesn't always make a difference, but if possible, it would be nice to stay as close to possible to the original target presented to the nmap command. By the way, right now the script uses the IP address and port number of the target as the Host specification in the HTTP requests.
2. Does the NSE system provide any indication about the verbosity level that's been given to the nmap command? Personally I think it would be helpful to be able to give different levels of output from NSE scripts based on indicated verbosity levels.
3. What is the general opinion of writing scripts that attempt to log in with known username/password combinations? I suspect that in certain cases, this type of activity could be construed as illegal if permission has not been obtained from the owner / operator of the targeted systems. I also don't want to see nmap become overburdened doing tasks that are better suited to other tools. In this specific instance, hydra would probably be a much better choice for trying to determine authentication credentials for HTTP services, but I found it convenient to be able to try one or two common combinations without having to use a separate tool.
Well, this is starting to turn into a rather long email, so I'll wrap it up and wait for responses.
Thanks, Thomas
-- HTTP authentication information gathering script
-- rev 1.1 (2007-05-25)
id = "HTTP Auth"
description = "If a web server requires authentication, prints the authentication scheme and realm"
author = "Thomas Buchanan <tbuchanan () thecompassgrp net>"
license = "See nmaps COPYING for licence"
-- uncomment the following line to enable safe category
-- categories = {"safe"}
categories = {"intrusive"}
portrule = function(host, port)
if
( port.number == 80
or port.number == 8080
or port.service == "http")
and port.protocol == "tcp"
and port.state == "open"
then
return true
else
return false
end
end
action = function(host, port)
local socket
local catch = function()
socket:close()
end
local try = nmap.new_try(catch)
local get_http_headers = function(dst, dst_port, query_string)
socket = nmap.new_socket()
try(socket:connect(dst, dst_port))
try(socket:send(query_string))
local response = ""
local lines
local status
while true do
status, lines = socket:receive_lines(1)
if not status then
break
end
response = response .. lines
end
try(socket:close())
local tags = {"(.-)<![Dd][Oo][Cc][Tt][Yy][Pp][Ee]", "(.-)<[Hh][Tt][Mm][Ll]", "(.-)<[Hh][Ee][Aa][Dd]",
"(.-)<[Bb][Oo][Dd][Yy]"}
local hdrs
for I = 1, #tags do
hdrs = string.match(response, tags[I])
if hdrs ~= nil and hdrs ~= response and hdrs ~= "" then
return hdrs
end
end
return response
end
local auth
local value
local realm
local scheme
local result
local basic = false
local query = "GET / HTTP/1.1\r\n"
query = query .. "Accept: */*\r\n"
query = query .. "Accept-Language: en\r\n"
query = query .. "User-Agent: Nmap NSE\r\n"
query = query .. "Host: " .. host.ip .. ":" .. port.number .. "\r\n\r\n"
local headers = get_http_headers(host.ip, port.number, query)
--- check for 401 response code
auth = string.match(headers, "HTTP/1.- 401")
if auth ~= nil then
result = "HTTP Service requires authentication\n"
-- loop through any WWW-Authenticate: headers to determine valid authentication schemes
for value in string.gmatch(headers, "[Aa]uthenticate:(.-)\n") do
result = result .. " Auth type: "
scheme, realm = string.match(value, "(%a+).-[Rr]ealm=\"(.-)\"")
if scheme == "Basic" then
basic = true
end
if realm ~= nil then
result = result .. scheme .. ", realm = " .. realm .. "\n"
else
result = result .. string.match(value, "(%a+)") .. "\n"
end
end
end
if basic then
query = "GET / HTTP/1.1\r\n"
query = query .. "Authorization: Basic YWRtaW46C\r\n"
query = query .. "Accept: */*\r\n"
query = query .. "Accept-Language: en\r\n"
query = query .. "User-Agent: Nmap NSE\r\n"
query = query .. "Host: " .. host.ip .. ":" .. port.number .. "\r\n\r\n"
auth = ""
headers = get_http_headers(host.ip, port.number, query)
auth = string.match(headers, "HTTP/1.- 40[013]")
if auth == nil then
result = result .. " HTTP server may accept user=\"admin\" with blank password for Basic
authentication\n"
end
query = "GET / HTTP/1.1\r\n"
query = query .. "Authorization: Basic YWRtaW46YWRtaW4\r\n"
query = query .. "Accept: */*\r\n"
query = query .. "Accept-Language: en\r\n"
query = query .. "User-Agent: Nmap NSE\r\n"
query = query .. "Host: " .. host.ip .. ":" .. port.number .. "\r\n\r\n"
auth = ""
headers = get_http_headers(host.ip, port.number, query)
auth = string.match(headers, "HTTP/1.- 40[013]")
if auth == nil then
result = result .. " HTTP server may accept user=\"admin\" with password=\"admin\" for Basic
authentication\n"
end
end
return result
end
_______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- [RFC] NSE script - HTTP authentication Thomas Buchanan (May 25)
- Re: [RFC] NSE script - HTTP authentication Thomas Buchanan (May 25)
- RE: [RFC] NSE script - HTTP authentication Sina Bahram (May 25)
- RE: [RFC] NSE script - HTTP authentication Thomas Buchanan (May 25)
- RE: [RFC] NSE script - HTTP authentication Sina Bahram (May 25)
- RE: [RFC] NSE script - HTTP authentication Thomas Buchanan (May 25)
- Re: [RFC] NSE script - HTTP authentication Eddie Bell (May 29)
- Re: [RFC] NSE script - HTTP authentication Thomas Buchanan (May 29)
- Re: [RFC] NSE script - HTTP authentication Eddie Bell (May 30)
- Re: [RFC] NSE script - HTTP authentication Thomas Buchanan (May 29)
