local http = require "http" local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" description = [[ Examines cookies set by HTTP services. Reports any session cookies set without the httponly flag. Reports any session cookies set over SSL without the secure flag. If http-enum.nse is also run, any interesting paths found by it will be checked in addition to the root. ]] --- -- @usage -- nmap -p 443 --script http-cookie-flags -- -- @output -- 443/tcp open https -- | http-cookie-flags: -- | /: -- | PHPSESSID: -- | secure flag not set and HTTPS in use -- | /admin/: -- | session_id: -- | secure flag not set and HTTPS in use -- | httponly flag not set -- | /mail/: -- | ASPSESSIONIDASDF: -- | httponly flag not set -- | ASP.NET_SessionId: -- |_ secure flag not set and HTTPS in use -- -- @args path Specific URL path to check for session cookie flags. Default: / and those found by http-enum. -- @args cookie Specific cookie name to check flags on. Default: A variety of commonly used session cookie names and patterns. -- -- @xmloutput -- --
-- secure flag not set and HTTPS in use --
-- -- --
-- secure flag not set and HTTPS in use -- httponly flag not set --
-- -- --
-- httponly flag not set --
-- -- secure flag not set and HTTPS in use --
-- -- -- @see http-enum.nse categories = { "default", "safe", "vuln" } author = "Steve Benson" license = "Same as Nmap--See https://nmap.org/book/man-legal.html" dependencies = {"http-enum"} portrule = shortport.http -- a list of patterns indicating cookies which are likely session cookies local session_cookie_patterns = { '^PHPSESSID$', '^CFID$', '^CFTOKEN$', '^VOXSQSESS$', '^CAKEPHP$', '^FedAuth$', '^ASPXAUTH$', '^session$', '[Ss][Ee][Ss][Ss][Ii][Oo][Nn][^%a]*[Ii][Dd]' } -- check cookies set on a particular URL path. returns a table with problem -- cookie names mapped to a table listing each problem found. local check_path = function(is_session_cookie, host, port, path) stdnse.debug1("start check of %s", path) local path_issues = stdnse.output_table() local resp = http.get(host, port, path) if not resp.status then stdnse.debug1("Error retrieving %s: %s", path, resp["status-line"]) return nil end if not resp.cookies then stdnse.debug2("No cookies on %s", path) return nil end for _,cookie in ipairs(resp.cookies) do stdnse.debug2(' cookie: %s', cookie.name) local issues = stdnse.output_table() if is_session_cookie(cookie.name) then stdnse.debug2(' IS a session cookie') if port.service=='https' and not cookie.secure then stdnse.debug2(' * no secure flag and https') issues[#issues+1] = 'secure flag not set and HTTPS in use' end if not cookie.httponly then stdnse.debug2(' * no httponly') issues[#issues+1] = 'httponly flag not set' end end if #issues>0 then path_issues[cookie.name] = issues end end stdnse.debug1("end check of %s : %d issues found", path, #path_issues) if #path_issues>0 then return path_issues else return nil end end action = function(host, port) local all_issues = stdnse.output_table() local specified_path = stdnse.get_script_args(SCRIPT_NAME..".path") local specified_cookie = stdnse.get_script_args(SCRIPT_NAME..".cookie") -- create a function, is_session_cookie, which accepts a cookie name and -- returns true if it is likely a session cookie, based on script-args local is_session_cookie if specified_cookie == nil then is_session_cookie = function(cookie_name) for _, pattern in ipairs(session_cookie_patterns) do if string.find(cookie_name, pattern) then return true end end return false end else is_session_cookie = function(cookie_name) return cookie_name==specified_cookie end end -- build a list of URL paths to check cookies for based on script-args and -- http-enum results. local paths_to_check = {} if specified_path == nil then stdnse.debug2('path script-arg is nil; checking / and anything from http-enum') paths_to_check[#paths_to_check+1] = '/' for _,path in ipairs( stdnse.registry_get({host.ip, 'www', port.number, 'all_pages'}) or {}) do paths_to_check[#paths_to_check+1] = path end else stdnse.verbose1('path script-arg is %s; checking only that path', specified_path) paths_to_check[#paths_to_check+1] = specified_path end -- check desired cookies on all desired paths for _,path in ipairs(paths_to_check) do all_issues[path] = check_path(is_session_cookie, host, port, path) end if #all_issues>0 then return all_issues else return nil end end