1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-11 02:09:03 +00:00

Added a 'path' script-arg to http-headers.nse. Changed it to use 'HEAD' by default, and fail to using 'GET' the same way other scripts do (also added a 'useget' script-arg to turn it off). Also fixed some print_debugs in http.lua that were prefixed with 'http-enum.nse:'.

This commit is contained in:
ron
2009-08-27 15:39:17 +00:00
parent fc2b575fba
commit 62dedb9dc1
2 changed files with 63 additions and 33 deletions

View File

@@ -1128,39 +1128,48 @@ end
-- --
--@param host The host object. --@param host The host object.
--@param port The port to use -- note that SSL will automatically be used, if necessary. --@param port The port to use -- note that SSL will automatically be used, if necessary.
--@param result_404 [optional] The result when an unknown page is requested. This is returned by <code>identify_404</code>. --@param result_404 [optional] The result when an unknown page is requested. This is returned by
-- If the 404 page returns a '200' code, then we disable HEAD requests. -- <code>identify_404</code>. If the 404 page returns a '200' code, then we
-- disable HEAD requests.
--@param path [optional] The path to request; by default, '/' is used.
--@return A boolean value: true if HEAD is usable, false otherwise. --@return A boolean value: true if HEAD is usable, false otherwise.
function can_use_head(host, port, result_404) --@return If HEAD is usable, the result of the HEAD request is returned (so potentially, a script can
-- avoid an extra call to HEAD
function can_use_head(host, port, result_404, path)
-- If the 404 result is 200, don't use HEAD. -- If the 404 result is 200, don't use HEAD.
if(result_404 == 200) then if(result_404 == 200) then
return false return false
end end
-- Default path
if(path == nil) then
path = '/'
end
-- Perform a HEAD request and see what happens. -- Perform a HEAD request and see what happens.
local data = http.head( host, port, '/' ) local data = http.head( host, port, path )
if data then if data then
if data.status and data.status == 302 and data.header and data.header.location then if data.status and data.status == 302 and data.header and data.header.location then
stdnse.print_debug(1, "http-enum.nse: Warning: Host returned 302 and not 200 when performing HEAD.") stdnse.print_debug(1, "HTTP: Warning: Host returned 302 and not 200 when performing HEAD.")
return false return false
end end
if data.status and data.status == 200 and data.header then if data.status and data.status == 200 and data.header then
-- check that a body wasn't returned -- check that a body wasn't returned
if string.len(data.body) > 0 then if string.len(data.body) > 0 then
stdnse.print_debug(1, "http-enum.nse: Warning: Host returned data when performing HEAD.") stdnse.print_debug(1, "HTTP: Warning: Host returned data when performing HEAD.")
return false return false
end end
stdnse.print_debug(1, "http-enum.nse: Host supports HEAD.") stdnse.print_debug(1, "HTTP: Host supports HEAD.")
return true return true, data
end end
stdnse.print_debug(1, "http-enum.nse: Didn't receive expected response to HEAD request (got %s).", get_status_string(data)) stdnse.print_debug(1, "HTTP: Didn't receive expected response to HEAD request (got %s).", get_status_string(data))
return false return false
end end
stdnse.print_debug(1, "http-enum.nse: HEAD request completely failed.") stdnse.print_debug(1, "HTTP: HEAD request completely failed.")
return false return false
end end
@@ -1278,17 +1287,17 @@ function identify_404(host, port)
data = http.get(host, port, URL_404_1) data = http.get(host, port, URL_404_1)
if(data == nil) then if(data == nil) then
stdnse.print_debug(1, "http-enum.nse: Failed while testing for 404 status code") stdnse.print_debug(1, "HTTP: Failed while testing for 404 status code")
return false, "Failed while testing for 404 error message" return false, "Failed while testing for 404 error message"
end end
if(data.status and data.status == 404) then if(data.status and data.status == 404) then
stdnse.print_debug(1, "http-enum.nse: Host returns proper 404 result.") stdnse.print_debug(1, "HTTP: Host returns proper 404 result.")
return true, 404 return true, 404
end end
if(data.status and data.status == 200) then if(data.status and data.status == 200) then
stdnse.print_debug(1, "http-enum.nse: Host returns 200 instead of 404.") stdnse.print_debug(1, "HTTP: Host returns 200 instead of 404.")
-- Clean up the body (for example, remove the URI). This makes it easier to validate later -- Clean up the body (for example, remove the URI). This makes it easier to validate later
if(data.body) then if(data.body) then
@@ -1296,7 +1305,7 @@ function identify_404(host, port)
local data2 = http.get(host, port, URL_404_2) local data2 = http.get(host, port, URL_404_2)
local data3 = http.get(host, port, URL_404_3) local data3 = http.get(host, port, URL_404_3)
if(data2 == nil or data3 == nil) then if(data2 == nil or data3 == nil) then
stdnse.print_debug(1, "http-enum.nse: Failed while testing for extra 404 error messages") stdnse.print_debug(1, "HTTP: Failed while testing for extra 404 error messages")
return false, "Failed while testing for extra 404 error messages" return false, "Failed while testing for extra 404 error messages"
end end
@@ -1305,7 +1314,7 @@ function identify_404(host, port)
if(data2.status == nil) then if(data2.status == nil) then
data2.status = "<unknown>" data2.status = "<unknown>"
end end
stdnse.print_debug(1, "http-enum.nse: HTTP 404 status changed for second request (became %d).", data2.status) stdnse.print_debug(1, "HTTP: HTTP 404 status changed for second request (became %d).", data2.status)
return false, string.format("HTTP 404 status changed for second request (became %d).", data2.status) return false, string.format("HTTP 404 status changed for second request (became %d).", data2.status)
end end
@@ -1314,7 +1323,7 @@ function identify_404(host, port)
if(data3.status == nil) then if(data3.status == nil) then
data3.status = "<unknown>" data3.status = "<unknown>"
end end
stdnse.print_debug(1, "http-enum.nse: HTTP 404 status changed for third request (became %d).", data3.status) stdnse.print_debug(1, "HTTP: HTTP 404 status changed for third request (became %d).", data3.status)
return false, string.format("HTTP 404 status changed for third request (became %d).", data3.status) return false, string.format("HTTP 404 status changed for third request (became %d).", data3.status)
end end
@@ -1323,28 +1332,28 @@ function identify_404(host, port)
local clean_body2 = clean_404(data2.body) local clean_body2 = clean_404(data2.body)
local clean_body3 = clean_404(data3.body) local clean_body3 = clean_404(data3.body)
if(clean_body ~= clean_body2) then if(clean_body ~= clean_body2) then
stdnse.print_debug(1, "http-enum.nse: Two known 404 pages returned valid and different pages; unable to identify valid response.") stdnse.print_debug(1, "HTTP: Two known 404 pages returned valid and different pages; unable to identify valid response.")
stdnse.print_debug(1, "http-enum.nse: If you investigate the server and it's possible to clean up the pages, please post to nmap-dev mailing list.") stdnse.print_debug(1, "HTTP: If you investigate the server and it's possible to clean up the pages, please post to nmap-dev mailing list.")
return false, string.format("Two known 404 pages returned valid and different pages; unable to identify valid response.") return false, string.format("Two known 404 pages returned valid and different pages; unable to identify valid response.")
end end
if(clean_body ~= clean_body3) then if(clean_body ~= clean_body3) then
stdnse.print_debug(1, "http-enum.nse: Two known 404 pages returned valid and different pages; unable to identify valid response (happened when checking a folder).") stdnse.print_debug(1, "HTTP: Two known 404 pages returned valid and different pages; unable to identify valid response (happened when checking a folder).")
stdnse.print_debug(1, "http-enum.nse: If you investigate the server and it's possible to clean up the pages, please post to nmap-dev mailing list.") stdnse.print_debug(1, "HTTP: If you investigate the server and it's possible to clean up the pages, please post to nmap-dev mailing list.")
return false, string.format("Two known 404 pages returned valid and different pages; unable to identify valid response (happened when checking a folder).") return false, string.format("Two known 404 pages returned valid and different pages; unable to identify valid response (happened when checking a folder).")
end end
return true, 200, clean_body return true, 200, clean_body
end end
stdnse.print_debug(1, "http-enum.nse: The 200 response didn't contain a body.") stdnse.print_debug(1, "HTTP: The 200 response didn't contain a body.")
return true, 200 return true, 200
end end
-- Loop through any expected error codes -- Loop through any expected error codes
for _,code in pairs(bad_responses) do for _,code in pairs(bad_responses) do
if(data.status and data.status == code) then if(data.status and data.status == code) then
stdnse.print_debug(1, "http-enum.nse: Host returns %s instead of 404 File Not Found.", get_status_string(data)) stdnse.print_debug(1, "HTTP: Host returns %s instead of 404 File Not Found.", get_status_string(data))
return true, code return true, code
end end
end end
@@ -1376,17 +1385,17 @@ function page_exists(data, result_404, known_404, page, displayall)
-- If the 404 response is also "200", deal with it (check if the body matches) -- If the 404 response is also "200", deal with it (check if the body matches)
if(string.len(data.body) == 0) then if(string.len(data.body) == 0) then
-- I observed one server that returned a blank string instead of an error, on some occasions -- I observed one server that returned a blank string instead of an error, on some occasions
stdnse.print_debug(1, "http-enum.nse: Page returned a totally empty body; page likely doesn't exist") stdnse.print_debug(1, "HTTP: Page returned a totally empty body; page likely doesn't exist")
return false return false
elseif(clean_404(data.body) ~= known_404) then elseif(clean_404(data.body) ~= known_404) then
stdnse.print_debug(1, "http-enum.nse: Page returned a body that doesn't match known 404 body, therefore it exists (%s)", page) stdnse.print_debug(1, "HTTP: Page returned a body that doesn't match known 404 body, therefore it exists (%s)", page)
return true return true
else else
return false return false
end end
else else
-- If 404s return something other than 200, and we got a 200, we're good to go -- If 404s return something other than 200, and we got a 200, we're good to go
stdnse.print_debug(1, "http-enum.nse: Page was '%s', it exists! (%s)", get_status_string(data), page) stdnse.print_debug(1, "HTTP: Page was '%s', it exists! (%s)", get_status_string(data), page)
return true return true
end end
else else
@@ -1394,7 +1403,7 @@ function page_exists(data, result_404, known_404, page, displayall)
if(data.status ~= 404 and data.status ~= result_404) then if(data.status ~= 404 and data.status ~= result_404) then
-- If this check succeeded, then the page isn't a standard 404 -- it could be a redirect, authentication request, etc. Unless the user -- If this check succeeded, then the page isn't a standard 404 -- it could be a redirect, authentication request, etc. Unless the user
-- asks for everything (with a script argument), only display 401 Authentication Required here. -- asks for everything (with a script argument), only display 401 Authentication Required here.
stdnse.print_debug(1, "http-enum.nse: Page didn't match the 404 response (%s) (%s)", get_status_string(data), page) stdnse.print_debug(1, "HTTP: Page didn't match the 404 response (%s) (%s)", get_status_string(data), page)
if(data.status == 401) then -- "Authentication Required" if(data.status == 401) then -- "Authentication Required"
return true return true
@@ -1409,7 +1418,7 @@ function page_exists(data, result_404, known_404, page, displayall)
end end
end end
else else
stdnse.print_debug(1, "http-enum.nse: HTTP request failed (is the host still up?)") stdnse.print_debug(1, "HTTP: HTTP request failed (is the host still up?)")
return false return false
end end
end end

View File

@@ -17,7 +17,8 @@ Does a GET request for the root folder ("/"), and displays the HTTP headers retu
-- | last-modified: Mon, 19 May 2008 04:49:49 GMT -- | last-modified: Mon, 19 May 2008 04:49:49 GMT
-- |_ server: Apache/2.2.2 (Fedora) -- |_ server: Apache/2.2.2 (Fedora)
-- --
-- --@arg path The path to request, such as '/index.php'. Default: '/'.
--@arg useget Set to force GET requests instead of HEAD.
author = "Ron Bowes <ron@skullsecurity.org>" author = "Ron Bowes <ron@skullsecurity.org>"
@@ -45,25 +46,45 @@ portrule = function(host, port)
end end
action = function(host, port) action = function(host, port)
local result = http.get(host, port, "/") local path = nmap.registry.args.path
local request_type = "HEAD"
if(path == nil) then
path = '/'
end
local status = false
local result
-- Check if the user didn't want HEAD to be used
if(nmap.registry.args.useget == nil) then
-- Try using HEAD first
status, result = http.can_use_head(host, port, path)
end
-- If head failed, try using GET
if(status == false) then
stdnse.print_debug(1, "http-headers.nse: HEAD request failed, falling back to GET")
result = http.get(host, port, path)
request_type = "GET"
end
if(result == nil) then if(result == nil) then
if(nmap.debugging() > 0) then if(nmap.debugging() > 0) then
return "ERROR: GET request failed" return "ERROR: Header request failed"
else else
return nil return nil
end end
end end
if(result.header == nil) then if(result.rawheader == nil) then
if(nmap.debugging() > 0) then if(nmap.debugging() > 0) then
return "ERROR: GET request didn't return a proper header" return "ERROR: Header request didn't return a proper header"
else else
return nil return nil
end end
end end
local response = " \n" local response = "(" .. request_type .. " used)\n"
for _, header in pairs(result.rawheader) do for _, header in pairs(result.rawheader) do
response = response .. header .. "\n" response = response .. header .. "\n"
end end