Nmap Development mailing list archives
[PATCH] showHTMLTitle.nse - bugfix and a few improvements
From: jah <jah () zadkiel plus com>
Date: Wed, 24 Sep 2008 02:38:52 +0100
Hi nmappers, The last time I sent a patch for showHTMLTitle I introduced the ability to follow a redirect from the default page. If the server sends a location header which is not an absolute URI (as per HTML 1.1 spec) a print_debug statement fails, killing script execution. My fault, I should have seen this coming. The attached fixes this by handling relative URIs and making the script much more careful about handling the location header. Additionally there's a few minor improvements: The script now only reports "Site doesn't have a title." when there's a response containing some data and the data doesn't contain title tags or contains an empty title tag. The script will silently exit if it doesn't get some data to play with, but will print some debug info. The pattern to match the title tags is less greedy which means that, should there be more than one title in a response (which happens quite often, would you believe), it will return the first of them rather than everything between the opening of the first and the closing of the last. The pattern will also match title tags if they should have attributes of some form. One thing that I didn't do because I thought it was overkill (?) was to use the dns library to check whether a hostname in a location header resolves to the target IP when the hostname does not match either host.targetname or host.name. Instead, it prints debug info. As a final note, a little gem of useless information: if the script result displays a title surrounded by addition operators it is likely a javascript variable - I haven't yet worked out the best way to get its value. Regards, jah
--- showHTMLTitle.nse.orig 2008-08-31 23:57:37.515625000 +0100 +++ showHTMLTitle.nse 2008-09-24 02:25:57.188625000 +0100 @@ -14,8 +14,9 @@ categories = {"default", "demo", "safe"} -require 'http' -require 'url' +local url = require 'url' +local http = require 'http' +local stdnse = require 'stdnse' portrule = function(host, port) if not (port.service == 'http' or port.service == 'https') then @@ -30,28 +31,48 @@ end action = function(host, port) + local data, result, title, protocol data = http.get( host, port, '/' ) - -- follow ONE redirect if host is not some other host - if data.status == 301 or data.status == 302 then + + -- check for a redirect + if type( data ) == "table" and type( data.status ) == "number" and tostring( data.status ):match( "30%d" ) and type( data.header ) == "table" and type( data.header.location ) == "string" then local url = url.parse( data.header.location ) - if url.host == host.targetname or url.host == ( host.name ~= '' and host.name ) or url.host == host.ip then - stdnse.print_debug("showHTMLTitle.nse: Default page is located at %s://%s%s", url.scheme, url.authority, url.path) - data = http.get( host, port, url.path ) + local loc + -- follow ONE redirect if host is not some other host. Handle absolute Location: URI and non-(HTTP/1.1)-compliant relative ones too. + if type( url.host ) == "string" and url.host == host.targetname or url.host == ( host.name ~= '' and host.name ) or url.host == host.ip then + loc = ( ( type( url.authority ) == "string" and ("%s://%s"):format( url.scheme or "http", url.authority ) ) or "" ) + .. ( ( type( url.path ) == "string" and url.path) or "/" ) + .. ( ( type( url.query ) == "string" and ("?%s"):format( url.query ) ) or "" ) + data = http.get_url( loc ) + elseif type( url.host ) ~= "string" and type( url.path ) == "string" and url.path ~= "/" then + loc = ( ( type( url.path ) == "string" and url.path) or "/" ) + .. ( ( type( url.query ) == "string" and ("?%s"):format( url.query ) ) or "" ) + data = http.get( host, port, loc ) end + stdnse.print_debug("showHTMLTitle.nse: (%s) Default page %s", host.targetname or host.ip, ( type( loc ) == "string" and ("is located at %s."):format( loc ) ) or ("may be located at %s."):format( data.header.location ) ) + end + + if type( data.body ) == "string" and data.body ~= "" then + result = data.body + elseif type( data.status ) ~= "number" and not next( data.header ) and ( type( data.body ) ~= "string" or data.body == "" ) then + stdnse.print_debug( "showHTMLTitle.nse: %s did not respond with an HTTP header or any data.", host.targetname or host.ip ) + return nil + else + stdnse.print_debug( "showHTMLTitle.nse: %s did not respond with any data.", host.targetname or host.ip ) + return nil end - result = data.body -- watch out, this doesn't really work for all html tags result = string.gsub(result, "<(/?%a+)>", function(c) return "<" .. string.lower(c) .. ">" end) - title = string.match(result, "<title>(.+)</title>") + title = string.match(result, "<title[^>]*>([^<]*)</title>") - if title ~= nil then + if type( title ) == "string" and title ~= "" then result = string.gsub(title , "[\n\r\t]", "") if string.len(title) > 65 then - stdnse.print_debug("showHTMLTitle.nse: Title got truncated!"); + stdnse.print_debug("showHTMLTitle.nse: (%s) Title got truncated!", host.targetname or host.ip ); result = string.sub(result, 1, 62) .. "..." end else @@ -59,5 +80,5 @@ end return result -end +end
_______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- [PATCH] showHTMLTitle.nse - bugfix and a few improvements jah (Sep 23)
- Re: [PATCH] showHTMLTitle.nse - bugfix and a few improvements David Fifield (Sep 30)