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 )