17 KiB
Raw Blame History

Cookies Hacking

{{#include ../../banners/hacktricks-training.md}}

Cookies 具有几个属性,控制它们在用户浏览器中的行为。以下是这些属性的概述:

Expires and Max-Age

Cookie 的过期日期由 Expires 属性决定。相反,Max-age 属性定义了在删除 cookie 之前的秒数。选择 Max-age,因为它反映了更现代的做法。

Domain

接收 cookie 的主机由 Domain 属性指定。默认情况下,这设置为发出 cookie 的主机,不包括其子域。然而,当 Domain 属性被显式设置时,它也包括子域。这使得 Domain 属性的指定成为一个不那么严格的选项,适用于需要跨子域共享 cookie 的场景。例如,设置 Domain=mozilla.org 使得在其子域如 developer.mozilla.org 上可以访问 cookie。

Path

Path 属性指示必须在请求的 URL 中存在的特定 URL 路径,以便发送 Cookie 头。此属性将 / 字符视为目录分隔符,允许在子目录中匹配。

Ordering Rules

当两个 cookie 具有相同的名称时,选择发送的 cookie 基于:

  • 与请求的 URL 中最长路径匹配的 cookie。
  • 如果路径相同,则选择最近设置的 cookie。

SameSite

  • SameSite 属性决定 cookie 是否在来自第三方域的请求中发送。它提供三种设置:
  • Strict:限制 cookie 在第三方请求中发送。
  • Lax:允许 cookie 与由第三方网站发起的 GET 请求一起发送。
  • 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

表格来自 Invicti 并稍作修改。
具有 SameSite 属性的 cookie 将 减轻 CSRF 攻击,其中需要登录会话。

*请注意,从 Chrome802019年2月开始未设置 cookie samesite 属性的 cookie 的默认行为将是 lax (https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/).
请注意临时情况下在应用此更改后Chrome 中 没有 SameSite **策略的 cookie 将在 前 2 分钟内被 视为 None,然后在顶级跨站点 POST 请求中视为 Lax。

Cookies Flags

HttpOnly

这避免了 客户端 访问 cookie例如通过 Javascriptdocument.cookie

Bypasses

  • 如果页面 将 cookie 作为请求的响应发送(例如在 PHPinfo 页面中),可以利用 XSS 发送请求到此页面并 窃取响应中的 cookie(请查看 https://hackcommander.github.io/posts/2022/11/12/bypass-httponly-via-php-info-page/ 中的示例)。
  • 这可以通过 TRACE HTTP 请求绕过,因为服务器的响应将反映发送的 cookie如果此 HTTP 方法可用)。此技术称为 Cross-Site Tracking
  • 现代浏览器通过不允许从 JS 发送 TRACE 请求来避免此技术。然而,在特定软件中发现了一些绕过方法,例如向 IE6.0 SP2 发送 \r\nTRACE 而不是 TRACE
  • 另一种方法是利用浏览器的零日漏洞。
  • 通过执行 Cookie Jar 溢出攻击,可以 覆盖 HttpOnly cookies

{{#ref}} cookie-jar-overflow.md {{#endref}}

Secure

请求将 在通过安全通道(通常是 HTTPS)传输时发送 cookie。

Cookies Prefixes

__Secure- 开头的 cookie 必须与通过 HTTPS 保护的页面的 secure 标志一起设置。

对于以 __Host- 开头的 cookie必须满足几个条件

  • 必须设置 secure 标志。
  • 必须来自通过 HTTPS 保护的页面。
  • 禁止指定域,防止其传输到子域。
  • 这些 cookie 的路径必须设置为 /

重要的是要注意,以 __Host- 开头的 cookie 不允许发送到超级域或子域。此限制有助于隔离应用程序 cookie。因此使用 __Host- 前缀为所有应用程序 cookie 被视为增强安全性和隔离性的良好做法。

Overwriting cookies

因此,__Host- 前缀 cookie 的保护之一是防止它们被子域覆盖。例如,防止 Cookie Tossing attacks。在演讲 Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (paper) 中,展示了可以通过欺骗解析器设置 __HOST- 前缀的 cookie例如在开头或结尾添加 "="

或者在 PHP 中,可以在 cookie 名称的开头添加 其他字符,这些字符将被 替换为下划线 字符,从而允许覆盖 __HOST- cookies

Cookies Attacks

如果自定义 cookie 包含敏感数据,请检查它(特别是如果您正在进行 CTF因为它可能存在漏洞。

Decoding and Manipulating Cookies

嵌入 cookie 的敏感数据应始终受到审查。以 Base64 或类似格式编码的 cookie 通常可以被解码。这种漏洞允许攻击者更改 cookie 的内容,并通过将其修改后的数据重新编码回 cookie 来冒充其他用户。

Session Hijacking

此攻击涉及窃取用户的 cookie以获得对其在应用程序中的帐户的未经授权访问。通过使用被盗的 cookie攻击者可以冒充合法用户。

Session Fixation

在这种情况下,攻击者诱使受害者使用特定的 cookie 登录。如果应用程序在登录时不分配新 cookie攻击者持有原始 cookie可以冒充受害者。此技术依赖于受害者使用攻击者提供的 cookie 登录。

如果您在子域中发现 XSS 或您 控制一个子域,请阅读:

{{#ref}} cookie-tossing.md {{#endref}}

Session Donation

在这里,攻击者说服受害者使用攻击者的会话 cookie。受害者相信他们已登录自己的帐户将无意中在攻击者的帐户上下文中执行操作。

如果您在子域中发现 XSS 或您 控制一个子域,请阅读:

{{#ref}} cookie-tossing.md {{#endref}}

JWT Cookies

点击上面的链接访问解释 JWT 可能存在缺陷的页面。

用于 cookie 的 JSON Web Tokens (JWT) 也可能存在漏洞。有关潜在缺陷及其利用方式的深入信息,建议访问有关黑客 JWT 的链接文档。

Cross-Site Request Forgery (CSRF)

此攻击迫使已登录用户在他们当前已认证的 Web 应用程序上执行不必要的操作。攻击者可以利用自动随每个请求发送到易受攻击站点的 cookie。

Empty Cookies

(请查看原始研究中的更多详细信息)浏览器允许创建没有名称的 cookie这可以通过 JavaScript 进行演示,如下所示:

document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2"

在发送的 cookie 头中的结果是 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 头,每个 web 服务器将其解释为名为 a,值为 b 的 cookie。

Chrome Bug: Unicode Surrogate Codepoint Issue

在 Chrome 中,如果 Unicode 代理代码点是设置的 cookie 的一部分,document.cookie 将变得损坏,随后返回一个空字符串:

document.cookie = "\ud800=meep"

这导致 document.cookie 输出一个空字符串,表明永久性损坏。

(查看原始研究的更多细节) 一些网络服务器,包括 JavaJetty, TomCat, Undertow和 PythonZope, cherrypy, web.py, aiohttp, bottle, webob由于对过时的 RFC2965 支持,错误处理 cookie 字符串。它们将双引号括起来的 cookie 值视为单个值,即使它包含分号,而分号通常应分隔键值对:

RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";

(查看原始研究的更多细节) 服务器对 cookies 的错误解析,特别是 Undertow、Zope 以及使用 Python 的 http.cookie.SimpleCookiehttp.cookie.BaseCookie 的服务器,创造了 cookie 注入攻击的机会。这些服务器未能正确分隔新 cookie 的开始,允许攻击者伪造 cookies

  • Undertow 期望在带引号的值后立即出现新 cookie而不需要分号。
  • Zope 寻找逗号以开始解析下一个 cookie。
  • Python 的 cookie 类在空格字符上开始解析。

这种漏洞在依赖基于 cookie 的 CSRF 保护的 web 应用程序中尤其危险,因为它允许攻击者注入伪造的 CSRF-token cookies可能绕过安全措施。这个问题因 Python 对重复 cookie 名称的处理而加剧,最后一个出现的名称会覆盖之前的名称。它还引发了对不安全上下文中 __Secure-__Host- cookies 的担忧,并可能导致在将 cookies 传递给易受伪造影响的后端服务器时发生授权绕过。

Cookies $version

WAF Bypass

根据这篇博客,可能可以使用 cookie 属性 $Version=1 使后端使用旧逻辑解析 cookie原因是 RFC2109。此外,其他值如 $Domain$Path 可以用来修改后端对 cookie 的行为。

根据这篇博客,可以使用 cookie 三明治技术来窃取 HttpOnly cookies。以下是要求和步骤

  • 找到一个明显无用的 cookie 在响应中被反射 的地方
  • 创建一个名为 $Version 的 cookie值为 1(你可以在 JS 的 XSS 攻击中做到这一点),并使用更具体的路径以获取初始位置(一些框架如 Python 不需要这一步)
  • 创建被反射的 cookie,其值留有 开放的双引号,并使用特定路径以便在 cookie 数据库中位于前一个 cookie ($Version) 之后
  • 然后,合法的 cookie 将按顺序排在后面
  • 创建一个虚拟 cookie 来关闭双引号 在其值中

这样,受害者的 cookie 就会被困在新的 cookie 版本 1 中,并将在每次反射时被反射。 例如,来自帖子:

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 绕过

Cookies $version

查看上一节。

使用引号字符串编码绕过值分析

此解析指示在 cookies 内部取消转义已转义的值,因此 "\a" 变为 "a"。这对于绕过 WAFS 很有用,例如:

  • eval('test') => forbidden
  • "\e\v\a\l\(\'\t\e\s\t\'\)" => allowed

在 RFC2109 中指出 逗号可以用作 cookie 值之间的分隔符。并且在等号前后也可以添加 空格和制表符。因此,像 $Version=1; foo=bar, abc = qux 的 cookie 不会生成 cookie "foo":"bar, admin = qux",而是生成 cookies foo":"bar""admin":"qux"。注意生成了 2 个 cookies以及 admin 在等号前后去掉了空格。

最后,不同的后门会将不同的 cookie 头中传递的不同 cookies 连接成一个字符串,如下所示:

GET / HTTP/1.1
Host: example.com
Cookie: param1=value1;
Cookie: param2=value2;

这可能允许绕过像这个例子中的WAF

Cookie: name=eval('test//
Cookie: comment')

Resulting cookie: name=eval('test//, comment') => allowed

基本检查

  • cookie 每次 登录 时都是 相同 的。
  • 登出并尝试使用相同的 cookie。
  • 尝试在 2 个设备(或浏览器)上使用相同的 cookie 登录同一账户。
  • 检查 cookie 中是否有任何信息并尝试修改它。
  • 尝试创建多个几乎相同用户名的账户,并检查是否可以看到相似之处。
  • 检查是否存在 "记住我" 选项以查看其工作原理。如果存在且可能存在漏洞,请始终使用 "记住我" 的 cookie而不使用其他 cookie。
  • 检查即使在更改密码后,之前的 cookie 是否仍然有效。

如果在登录时 cookie 保持不变(或几乎不变),这可能意味着该 cookie 与您账户的某个字段相关(可能是用户名)。然后您可以:

  • 尝试创建许多非常 相似 的用户名的 账户,并尝试 猜测 算法的工作原理。
  • 尝试 暴力破解用户名。如果 cookie 仅作为您用户名的身份验证方法保存,那么您可以创建一个用户名为 "Bmin" 的账户,并 暴力破解 您的 cookie 的每一个 ,因为您尝试的其中一个 cookie 将是属于 "admin" 的。
  • 尝试 Padding Oracle(您可以解密 cookie 的内容)。使用 padbuster

Padding Oracle - Padbuster 示例

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 将进行多次尝试,并会询问您哪个条件是错误条件(无效的条件)。

然后它将开始解密 cookie可能需要几分钟

如果攻击成功执行,则您可以尝试加密您选择的字符串。例如,如果您想要 encrypt user=administrator

padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator

此执行将正确加密和编码包含字符串 user=administrator 的 cookie。

CBC-MAC

也许一个 cookie 可以有某个值,并且可以使用 CBC 签名。然后,值的完整性是使用相同值的 CBC 创建的签名。由于建议使用空向量作为 IV这种完整性检查可能会受到攻击。

攻击

  1. 获取用户名 administ 的签名 = t
  2. 获取用户名 rator\x00\x00\x00 XOR t 的签名 = t'
  3. 在 cookie 中设置值 administrator+t' t' 将是 (rator\x00\x00\x00 XOR t) XOR t 的有效签名 = rator\x00\x00\x00

ECB

如果 cookie 使用 ECB 加密,则可能会受到攻击。
当您登录时,您收到的 cookie 必须始终相同。

如何检测和攻击:

创建 2 个几乎相同数据的用户(用户名、密码、电子邮件等),并尝试发现给定 cookie 中的某些模式。

创建一个名为 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 的用户,并检查 cookie 中是否有任何模式(由于 ECB 使用相同的密钥加密每个块,如果用户名被加密,则相同的加密字节可能会出现)。

应该有一个模式(与使用的块的大小相同)。因此,知道一堆 "a" 是如何加密的,您可以创建一个用户名: "a"*(块的大小)+"admin"。然后,您可以从 cookie 中删除一个块的 "a" 的加密模式。您将拥有用户名 "admin" 的 cookie。

参考

{{#include ../../banners/hacktricks-training.md}}