上一篇文章我们介绍了漏洞利用的过程,这篇文章就介绍一下具体的漏洞。
Akamai
现在是一个更知名的目标,当我在前面展示Akamai公开的缓存密钥时,你是否注意到神秘的“Akamai -transform”参数出现在一些(但不是所有)缓存密钥中? 这种奇怪的行为使我认为该参数可能会从高速缓存密钥中被删除,而且可以肯定的是:
由于Akamai的糟糕的URL解析,你可以使用它对任意参数进行秘密更改:
对于Akamai来说,幸运的是,在任何缓存密钥标头中都没有显示一个不可见的位,如果请求包含Akamai -transform参数,就会设置这个位。这意味着该技术仅适用于有意使用Akamai -transform的Akamai站点。我已将此发现报告给了Akamai,他们现在已经对其进行了修补。
Ruby on Rails
Ruby On Rails最早出来是2004年,十六年前刚出来的时候真是非常惊艳,那时候根本想不到写服务器竟然可以这么简单。Ruby On Rails几乎可以说是PHP的接班人。很多创业公司最开始都是用Ruby On Rails写的,比如Airbnb。(正像当年Facebook开始时用的是PHP)。不过这么多年过去了,Ruby On Rails的优势越来越不那么明显了,NodeJS看起来成为了新一代服务器的主流。
在一个目标上,我的扫描检测到了可疑的行为,但是我没有找到合适的Cache Oracle,所以我转而查找目标缓存的源代码。这导致我们发现Ruby on Rails框架将';'当作参数分隔符,就像'&'一样。这意味着以下url是等效的:
这种解析的怪癖有许多安全隐患,其中之一与此密切相关。在一个被配置为从缓存密钥中删除utm_content的系统上,以下两个请求是相同的,因为它们只有一个密钥参数- callback。
但是,Rails看到了三个参数,回调、utm_content和回调。它优先考虑第二个回调值,以使我们可以完全控制它。
解密方法
从高速缓存密钥隐藏参数的另一种方法是简单地发送POST请求,某些特殊的系统不会在缓存密钥中包括请求方法。使用这种技术,我能够获得持久的XSS在一个在线地图网站的每一页:
Aaron Costello和我差不多在同一时间发现了这个技巧,我建议你查阅他关于这个主题的文章。
使用Fat GET请求
Varnish是一款高性能的开源HTTP加速器,可以有效降低web服务器的负载,提升访问速度。根据官方的说法,Varnish是一个cache型的HTTP反向代理。
Varnish的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多。在1975年时,储存媒介只有两种:内存与硬盘。但现在计算 机系统的内存除了主存外,还包括了cpu内的L1、L2,甚至有L3快取。硬盘上也有自己的快取装置,因此squid cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,这就是Varnish cache设计架构。
对于不使用带有内置invv代码段的Varnish以及支持带有正文的GET请求(以下称为“Fat GET”)的框架的网站,这是个坏消息。
类似的网站有GitHub,在每个可缓存页面上,我可以使用一个fat GET来破坏缓存,并将任何参数更改为我选择的值。例如,如果我发出以下请求,则任何尝试在我的GitHub个人资料上报告滥用行为的人都将最终报告“innocent-victim”:
使用相同的技术,还可以持久地应用和更改漏洞过滤器,拒绝访问主题页面,禁用大多数存储库上的“原始”按钮等,GitHub对此进行了修补。
Zendesk
不仅仅是配置不当的Varnish服务器转发fat GET请求而没有在缓存密钥中包含主体参数,因为所有Cloudflare系统都是这样做的,Rack :: Cache模块也是如此。我最初向Cloudflare报告了这个漏洞,,因为它使许多客户受到攻击,但是他们通过在文档中添加“不信任GET请求主体”来“修补”该漏洞。
一个可行的目标是该警告所在的位置。它使用了基于Rails的Zendesk,以下请求会使他们的登录页面遭受攻击,从而使输入自己的凭据并单击“登录”的任何人都会被发送到一系列重定向中,从而使他们登录到我的帐户中,从而使我保管了其后创建的所有票证:
我已将此事报告给Zendesk,因此它们现在很安全。
gadget
与之前的技术相比,fat GET技术给了我们更多的控制权来控制我们可以攻击哪些输入,但是对GitHub和Zendesk的攻击显然比之前看到的整个站点接管的影响要小。这是因为缓存攻击的影响很大程度上取决于可用的gadget。像“对可缓存页面上的任意参数进行任意无密钥更改”这样强大的原语意味着存在大量潜在gadget,但最终的影响取决于gadget的质量。
这意味着能够识别潜在的小部件对于高强度攻击至关重要,我们已经看到了反射的XSS、本地重定向、login-CSRF和JSONP,除此之外,还有什么发现呢?
像JS和CSS这样的资源文件大多是静态的,但是有些会反映来自查询字符串的输入。这通常是无害的,因为当浏览器直接查看这些文件时,它们不会执行,但这是一个极好的缓存攻击gadget。如果我们可以使用缓存攻击将内容注入到资源文件中,我们就可以控制导入该资源的每个页面,即使它是跨域的。例如,在一个目标上,一个“import”规则反映了当前的查询字符串,可能作为一个高级的版本控制功能:
我们可以使用它注入恶意CSS,该CSS会从加载它的任何页面中泄漏敏感信息。
如果导入CSS文件的页面没有doctype,则该文件甚至不需要text / css内容类型;浏览器将仅浏览文档,直到遇到有效的CSS,然后执行它。这意味着你偶尔会通过触发反映URL的服务器错误来发现自己能够攻击的静态CSS文件:
缓存密钥规范化
当应用到缓存密钥时,即使是像URL规范化这样简单的事情也会产生严重的后果。作为一个案例研究,让我们看看Firefox的更新系统。Firefox会定期向download.mozilla.org发出请求来检查浏览器更新情况:
直到最近,服务器配置看起来是这样的:
这里的proxy_cache_key设置没有漏洞,实际上,它与nginx的默认缓存密钥非常相似。但是如果你查看nginx的proxy_pass文档,你会发现漏洞的线索:
“如果指定的proxy_pass没有URI,则请求URI将以与处理原始请求时客户机发送的相同的形式传递给服务器。”
短语'in The same form'暗示了转发的请求不会被标准化,而存储在缓存密钥中的请求组件可能是标准化的,Nginx应用于缓存密钥的一种标准化形式是一个完整的URL解码。
如果你用一个编码的问号发出更新请求,这将打乱后端并导致重定向中断:
但是多亏了nginx的URL-decode,它将拥有与合法更新请求相同的缓存密钥。所以从那时起,Firefox将无法进行全球范围的更新:
由于Firefox的更新经常包含重要的安全修复程序,这可能是相当严重的。
缓存魔术技巧
我们已经研究了一系列攻击,这些攻击可以让我们利用自然浏览受毒网站的人们进行攻击,但是缓存攻击有时还可以启用原本不可能的“单击此处进行伪造”式攻击。
XSS编码
你可能遇到过这样的情况,这样就可以在Burp Repeater中找到了反射的XSS。
但是你不能在任何Web浏览器中复制它,但可能无法使用Internet Explorer,因为现代浏览器在发出请求之前会对URL编码,而服务器不会对它们进行解码:
这个漏洞过去只影响路径中的XSS,但近年来,浏览器也开始一致地在查询字符串中编码这些字符。
幸运的是,缓存密钥标准化意味着这两个请求有相同的密钥,因此我们可以在将受害者定向到URL之前简单地自行发出未编码的攻击,从而利用任意浏览器:
缓存密钥注入:Akamai
Akamai(阿卡迈)在1998年发明CDN技术架构之后组建公司,诞生于麻省理工学院,是CDN服务提供商,1999年NASDAQ上市。总部位于美国波士顿。
另一个典型的不可利用的漏洞是影响密钥标头的客户端漏洞,例如Origin标头中的XSS:
这确实应该是无法解释的,但是如果像Akamai这样的缓存碰巧将所有秘钥组件捆绑成一个字符串而又不费心地转义分隔符怎么办?我们可以设计两个具有相同缓存秘钥的请求,即使它们在语义上完全不同:
通过自己发出第一个请求,并将受害者定向第二个URL,我们就可以利用这个XSS了。目前,Akamai正在进行修复工作。请注意,如果你发现这个策略在主机标头上有效,则可以使用目标CDN完全控制每个网站。
缓存密钥注入:Cloudflare
在看到这种对Akamai的攻击有多么容易之后,我决定在Cloudflare上进行尝试。他们没有一个简单的标头来显示他们的缓存密钥,所以我参考了他们的文档,里面说默认的密钥是:
这应该意味着以下一对请求具有相同的密钥:
相对路径覆盖
缓存中毒在页面子资源中为我们提供的立足点与相对路径覆盖攻击有着奇妙的共生关系。这些攻击使用服务器端路径规范化来使浏览器混淆解析错误的相对路径样式表导入,例如 ,导致它们将CSS响应执行为HTML,由于攻击者通常无法控制查询字符串,因此他们通常无法将恶意CSS注入HTML页面,从而阻碍了此类攻击。缓存攻击为我们提供了一种提前将恶意CSS注入HTML页面的方法,使这个漏洞更容易被利用。
内部缓存攻击
另一方面,有些攻击太过实际,以至于无法安全执行。在通过以下请求探测到Adobe博客上潜在的缓存攻击漏洞后,我收到了来自Burp Collaborator服务器的大量流量,这些流量来自他们的网站:
原来,他们使用的是一个集成的应用级缓存,称为WP Rocket 缓存。WP-Rocket 是明月一直很推崇的 WordPress 下本地缓存插件,可以说相对于 WP Super Cache 和 W3 Total Cache 短小精悍了很多,设置也没有那么复杂,兼容性很完美,特别是缓存效果几乎就是“立竿见影”。内部的应用程序层缓存通常单独缓存响应的片段,并且实际上没有缓存密钥的概念。因此,通过发送这个请求,我无意攻击害了网站上的每个页面,包括现在每个链接都定向到我域名的主页。
这不是一个理想的结果,由于我无法“撤销”攻击,我关闭了Collaborator服务器,然后联系了Adobe的安全团队,他们在20分钟内解决了这个漏洞。幸运的是,他们能理解,但是当涉及到内部缓存攻击时,合法黑客和不那么合法的黑客之间的区别就变得有点模糊了。
盲目的缓存攻击
由于内部缓存没有缓存密钥,所以有可能攻击你甚至无法访问的页面。我是在评估DoS技术时偶然发现这一点的,该技术普遍失败了,但它触发了来自美国国防部内部网内部管理小组对我服务器的流量。
经过一些调查,我发现该站点只能在内部访问,因此任何从外部访问该站点的尝试都会导致服务器级重定向到内部网。然而,DoS技术破坏了重定向并触发了一个错误页面,攻击了进程中的内部缓存。
识别内部缓存攻击
我曾无数次尝试发明一种安全的方法来搜索内部缓存攻击,攻击效果很大,不过,我们已经看到它很容易被偶然触发。因此,知道如何识别这些影响是值得的,根据经验,错误的分类会导致大量的时间浪费。
由于外部缓存几乎总是保存整个响应,所以内部缓存攻击的一个关键指标是看是否出现“Canary”。Canary主要用于防护栈溢出攻击。我们知道,在32位系统上,对于栈溢出漏洞,攻击者通常是通过溢出栈缓冲区,覆盖栈上保存的函数返回地址来达到劫持程序执行流的目的。Canary出现在不同的页面上,与你注入的Canary不同,这也是另一个指标,就像使用解析为相同应用程序的不一致的主机名一样。
你可以通过一些办法来减少缓存事故,当你指定的主机名不是目标主机名时,请确保它是你控制的站点。除非你是evil.com的幸运所有者,否则你不会希望最终将目标的访问者路由到evil.com。
使用到的工具
为了监测方便,我使用了Param Miner发布的更新版本,一个开源的Burp套件扩展,可以在社区版和专业版上使用。
你可以使用“Add cachebuster”选项将静态或动态的基于标头的缓存Buster 添加到所有流量中。这将有助于揭示动态页面,同时减少意外影响其他用户的机会。Buster 是一个 Firefox 扩展,它通过使用语音识别完成 reCAPTCHA 音频挑战,帮助用户解决困难的验证码。
它还可以扫描我们讨论过的许多缓存密钥漏洞,在GitHub repo中,你可以看到它检测运行Rack::Cache的系统的Fat GET漏洞的视频。
最后,Param Miner的核心功能是发现未链接的参数,现在它将自动探测这些参数,以确定它们是否在缓存密钥中。
缓解措施
缓存的复杂性使得人们很难对它们的安全性有任何信心,不过你可以采取一些常用的方法来避免出现最严重的漏洞。
首先,避免重写缓存密钥。取而代之的是,重写实际的请求,这样可以获得相同的性能提升,同时大量减少缓存攻击漏洞出现的可能性。
其次,确保你的应用程序不支持fat GET请求。
最后,作为深度防御措施,修补由于浏览器限制而被认为不可利用的漏洞,如self-XSS、编码的XSS或资源文件中的输入反射。
总结
多年来,网络缓存一直没有受到严格的审查。本文研究中发现的大量缓存问题表明,还有很多未被发现的漏洞,特别是考虑到我发现的许多漏洞只是基于简单的信息泄漏。
本文翻译自:https://portswigger.net/research/web-cache-entanglement如若转载,请注明原文地址