1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
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 <target>
--
-- @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
-- <table key="/">
-- <table key="PHPSESSID">
-- <elem>secure flag not set and HTTPS in use</elem>
-- </table>
-- </table>
-- <table key="/admin/">
-- <table key="session_id">
-- <elem>secure flag not set and HTTPS in use</elem>
-- <elem>httponly flag not set</elem>
-- </table>
-- </table>
-- <table key="/mail/">
-- <table key="ASPSESSIONIDASDF">
-- <elem>httponly flag not set</elem>
-- </table>
-- <table key="ASP.NET_SessionId">
-- <elem>secure flag not set and HTTPS in use</elem>
-- </table>
-- </table>
--
-- @see http-enum.nse
-- @see http-security-headers.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
|