利用 phantom $Version cookie 绕过 WAF

360影视 2025-01-08 08:21 3

摘要:HTTP cookie 通常控制着网站的关键功能,但它们漫长而复杂的历史使它们容易受到解析器差异漏洞的影响。在这篇文章中,我将探讨现代 Cookie 解析器的一些危险的、鲜为人知的功能,并展示如何滥用它们来绕过 Web 应用程序防火墙。这是关于 Cookie

HTTP cookie 通常控制着网站的关键功能,但它们漫长而复杂的历史使它们容易受到解析器差异漏洞的影响。在这篇文章中,我将探讨现代 Cookie 解析器的一些危险的、鲜为人知的功能,并展示如何滥用它们来绕过 Web 应用程序防火墙。这是关于 Cookie 解析的系列博客文章的第一部分。

从第一个官方标准RFC2109 开始,人们曾多次尝试标准化 HTTP Cookie 。尽管现代浏览器不支持旧版 RFC,但许多 Web 服务器仍然支持。以下是有效Cookie标头的示例:

Cookie:$Version=1; foo="bar"; $Path="/"; $Domain=abc;

$Version是必需属性,用于标识 cookie 所遵循的状态管理规范的版本。其他有趣的属性包括$Domain和$Path,我们将在后面讨论。根据标准,Cookie 值可以包含特殊字符,例如空格、分号和等号(如果它们括在双引号中):

许多 HTTP/1.1 标头字段值由 LWS(线性空格)或特殊字符分隔的单词组成。这些特殊字符必须放在引号字符串中才能在参数值中使用。- RFC 2068。

现代框架通过下列方式分析该标头:

Flask: {"foo":"bar","$Version":"1","$Path":"/","$Domain":"abc"}Django: {"foo":"bar","$Version":"1","$Path":"/","$Domain":"abc"}PHP: {"foo":"\"bar\"","$Version":"1","$Path":"\"\/\"","$Domain":"abc"}Ruby: {"foo":"\"bar\"","$Version":"1","$Path":"\"\/\"","$Domain":"abc"}Spring: { "foo": "\"bar\""} SimpleCookie: { "foo": "bar"}

我们可以看到,结果很混乱。这种混乱让我们有机会寻找安全漏洞。我们首先关注 Spring Boot Starter Web 2.xx。它默认使用 Apache Tomcat v. 9.0.83,它以以下方式处理 cookie 标头:

它同时处理 RFC6265 和 RFC2109 标准,如果字符串以特殊的$Version属性开头,则默认采用传统的解析逻辑。它还支持$Path和$Domain属性,如果在响应之前没有正确检查,这可能会让用户更改反映的 cookie 属性。解析器还将取消转义以反斜杠(\)开头的任何字符,如下例所示。Cookie: $Version=1; foo="\b\a\r"; $Path=/abc; $Domain=example.com =>Set-Cookie: foo="bar"; Path=/abc; Domain=example.com

另一个很好的例子是 Python SimpleCookie 解析器,它支持后跟键值对的旧式 cookie 请求属性。这样就可以以前面演示的相同方式注入恶意 cookie 属性。所有基于 Python 的框架(Flask、Django 等)都允许带引号的 cookie 值,但无法识别魔术字符串(如$Version),而是将其视为普通的 cookie 名称。它们还会自动解码带引号的字符串中的八进制转义序列,如下所示:

任何非文本字符都会被转换成 4 个字符的序列:一个正斜杠,后跟该字符的三位八进制数字。-
Cookies.py

例如:

"\012" \n"\015" \r"\073" ;

许多 WAF 不具备检测上述技术的功能,从而允许恶意负载隐藏在引号字符串中。

此外,带引号的 cookie 还可能引发注入漏洞,例如SQL 注入或命令注入。这些类型的攻击通常使用特殊的命令分隔符 - 例如分号 ( ; )、逗号 、换行符 ( \n ) 和反斜杠 ( \ )。虽然这些分隔符通常限制在 cookie 值中,但有时可以操纵它们来触发漏洞。使用带有HttpHandler 接口的 Burp Suite 扩展可以轻松实现这种带引号的 cookie 编码:

def handleHttprequestToBeSent(requestToBeSent):result = "$Version=1; "for param in requestToBeSent.parameters:result += f"{param.name}=\""for char in param.value:result += f"\\{char}"result += "\"; "return continueWith(requestToBeSent.withAddedHeader("Cookie",result))例如,Amazon Web Services WAF 会阻止任何包含不允许的函数内的任何参数的请求:eval => allowedeval('test') => forbidden"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed"\145\166\141\154\050\047\164\145\163\164\047\051" => allowed

RFC2109 的另一个重要方面是:服务器还应接受逗号 作为 cookie 值之间的分隔符。这可被用来绕过简单的 WAF 签名,因为这些签名可能无法预料到 cookie 名称会隐藏在值中。此外,该规范允许在注入的属性值对中的等号前后使用任意数量的空格或制表符,这也可用于避免检测。请考虑Cookie标头示例:

与许多其他 HTTP 标头一样,Cookie标头可以在单个请求中多次发送。服务器处理多个相同标头的方式可能会有所不同。例如,我发送了以下 GET 请求:GET / HTTP/1.1 Host: example.com Cookie:param1=value1;Cookie:param2=value2;

并得到以下返回:

Flask: { "param1": "value1", ",param2": "value2"}Django: { "param1": "value1", ",param2": "value2"}PHP: { "param1": "value1", ",_param2": "value2"}Ruby: { "param1": "value1", ", param2": "value2"}Spring: { "param1": "value1", "param2": "value2"}

我们可以看到,Ruby、PHP 以及 Python 框架 Django 和 Flask 将标头组合成单个逗号分隔的字符串(参数之间可选有空格)。还支持带引号的 cookie 值,这允许通过使用Cookie标头作为多行标头延续来隐藏恶意负载。

不幸的是,带引号的字符串技术不适用于 PHP 和 Ruby。要绕过上述 AWS 签名,可以使用以下请求:

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

我们在Param Miner中为您实现了这些最佳技术:

确保在 Web 服务器上禁用对 RFC2109 的旧版支持,除非明确要求。严格验证所有用户输入,以识别和缓解潜在的危险数据。这有助于确保输入在应用程序内或与其他系统组件交互时是安全的。避免依赖对用户输入中特定字符的存在或不存在的假设,以降低意外行为的风险。

来源:Web3软件开发

相关推荐