diff --git a/scripts/showHTMLTitle.nse b/scripts/showHTMLTitle.nse
index 502af9c4a..313f02b14 100644
--- a/scripts/showHTMLTitle.nse
+++ b/scripts/showHTMLTitle.nse
@@ -42,13 +42,9 @@ action = function(host, port)
if data and data.status and tostring( data.status ):match( "30%d" ) and data.header and data.header.location then
redir = ("Did not follow redirect to %s"):format( data.header.location )
local url = url.parse( data.header.location )
- local loc = {}
- -- test the redirect to see if we're allowed to go there
- for i, rule in ipairs( rules ) do
- if not rule( loc, url, host, port ) then break end
- end
- -- follow redirect
- if loc.host and loc.port and loc.path then
+ local loc = redirect_ok( url, host, port )
+ if loc then
+ -- follow redirect
redir = ("Requested resource was %s://%s%s"):format( url.scheme or port.service, loc.host, loc.path )
data = http.get( loc.host, loc.port, loc.path )
else
@@ -83,63 +79,78 @@ action = function(host, port)
end
+-- Check if the given URL is okay to redirect to. Return a table with keys
+-- "host", "port", and "path" if okay, nil otherwise.
+function redirect_ok(url, host, port)
+ -- A battery of tests a URL is subjected to in order to decide if it may be
+ -- redirected to. They incrementally fill in loc.host, loc.port, and loc.path.
+ local rules = {
+ function (loc, url, host, port)
+ -- if url.scheme is present then it must match the scanned port
+ if url.scheme and url.scheme ~= port.service then return false end
+ return true
+ end,
-rules = {
- function (loc, url, host, port)
- -- if url.scheme is present then it must match the scanned port
- if url.scheme and url.scheme ~= port.service then return false end
- return true
- end,
+ function (loc, url, host, port)
+ -- bail if userinfo is present
+ return ( url.userinfo and false ) or true
+ end,
- function (loc, url, host, port)
- -- bail if userinfo is present
- return ( url.userinfo and false ) or true
- end,
+ function (loc, url, host, port)
+ -- if present, url.host must be the same scanned target
+ -- loc.host must be set if returning true
+ if not url.host then
+ loc.host = ( host.targetname or host.ip )
+ return true
+ end
+ if url.host and
+ url.host == host.ip or
+ url.host == host.targetname or
+ url.host == ( host.name ~= '' and host.name ) or
+ is_vhost( url.host, host ) then -- dns lookup as last resort
+ loc.host = url.host
+ return true
+ end
+ return false
+ end,
- function (loc, url, host, port)
- -- if present, url.host must be the same scanned target
- -- loc.host must be set if returning true
- if not url.host then
- loc.host = ( host.targetname or host.ip )
- return true
- end
- if url.host and
- url.host == host.ip or
- url.host == host.targetname or
- url.host == ( host.name ~= '' and host.name ) or
- is_vhost( url.host, host ) then -- dns lookup as last resort
- loc.host = url.host
- return true
- end
- return false
- end,
+ function (loc, url, host, port)
+ -- if present, url.port must be the same as the scanned port
+ -- loc.port must be set if returning true
+ if (not url.port) or url.port == port.number then
+ loc.port = port
+ return true
+ end
+ return false
+ end,
- function (loc, url, host, port)
- -- if present, url.port must be the same as the scanned port
- -- loc.port must be set if returning true
- if (not url.port) or url.port == port.number then
- loc.port = port
- return true
- end
- return false
- end,
+ function (loc, url, host, port)
+ -- path cannot be unchanged unless host has changed
+ -- loc.path must be set if returning true
+ if ( not url.path or url.path == "/" ) and url.host == ( host.targetname or host.ip) then return false end
+ if not url.path then loc.path = "/"; return true end
+ loc.path = ( ( url.path:sub(1,1) == "/" and "" ) or "/" ) .. url.path -- ensuring leading slash
+ return true
+ end,
- function (loc, url, host, port)
- -- path cannot be unchanged unless host has changed
- -- loc.path must be set if returning true
- if ( not url.path or url.path == "/" ) and url.host == ( host.targetname or host.ip) then return false end
- if not url.path then loc.path = "/"; return true end
- loc.path = ( ( url.path:sub(1,1) == "/" and "" ) or "/" ) .. url.path -- ensuring leading slash
- return true
- end,
+ function (loc, url, host, port)
+ -- always true - jut add the query to loc.path
+ if url.query then loc.path = ("%s?%s"):format( loc.path, url.query ) end
+ return true
+ end
+ }
- function (loc, url, host, port)
- -- always true - jut add the query to loc.path
- if url.query then loc.path = ("%s?%s"):format( loc.path, url.query ) end
- return true
- end
- }
+ local loc = {}
+ for i, rule in ipairs( rules ) do
+ if not rule( loc, url, host, port ) then return nil end
+ end
+ if loc.host and loc.port and loc.path then
+ return loc
+ else
+ return nil
+ end
+end
function is_vhost( rhost, host )