本文将介绍攻击者是利用漏洞发起HTTP Desync攻击的,目标都是一些知名网站,这些漏洞通过劫持客户端、木马化缓存、还有窃取凭据来发起攻击。
对Netflix的HTTP Desync攻击
由于HTTP/2的数据帧长度字段,Content-Length标头是不需要的。然而,HTTP/2 RFC声明该标头是允许的,只要它是正确的。Netflix使用了一个无需验证内容长度就执行HTTP降级的前端。研究人员发出了以下HTTP/2请求:
在前端将此请求降级为HTTP/1.1后,它到达后端,看起来像这样:
由于 Content-Length 不正确,后端提前停止处理请求,橙色数据被视为另一个请求的开始。这使研究人员能够为下一个请求添加任意前缀,而不管它是谁发送的。
将受害者的请求重定向到研究人员的服务器 02.rs:
通过重定向 JavaScript 包含,研究人员可以执行恶意 JavaScript 来破坏 Netflix 帐户,并窃取密码和信用卡号。通过循环运行这种攻击,研究人员可以在没有用户交互的情况下逐渐攻击网站的所有活跃用户,这种严重程度是请求走私的典型表现。
针对Application Load Balancer(简称ALB)的HTTP Desync攻击
接下来,让研究人员看看一个简单的 H2.TE HTTP Desync。 RFC 状态为“任何包含特定于连接的标头字段的消息都必须被视为格式错误。”
一个特定于连接的标头字段是Transfer-Encoding。Amazon Web Services (AWS)的应用ALB未能遵守此行,并接受包含Transfer-Encoding的请求。这意味着攻击者可以通过 H2.TE HTTP Desync来利用几乎所有使用它的网站。
其中一个易受攻击的网站是Verizon的执法入口网站,位于id.b2b.oath.com。研究人员使用以下请求利用了它:
前端将此请求进行了降级:
降级后,“transfer-encoding: chunked”标头文件优先于前端插入的内容长度。这使得后端提前停止解析请求正文,并使研究人员能够将任意用户重定向到在psres.net的网站。
H2.TE通过请求标头注入
由于HTTP/1是明文协议,所以不可能在某些地方放置某些解析关键字符。例如,你不能在标头文件值中放入\r\n序列,这样你就只会终止标头文件。
在HTTP/2中压缩标头的方式,使你可以把任意字符放在任意位置。一个易受攻击的实现是 Netlify CDN,它在基于它的每个网站上启用了 H2.TE HTTP Desync攻击,包括 Firefox 的 start.mozilla.org 起始页面。研究人员制作了一个在标头值中使用 '\r\n' 的漏洞:
在降级过程中,\r\n触发了一个请求标头注入漏洞,引入了一个名为Transfer-Encoding: chunked额外标头。
这触发了 H2.TE HTTP Desync,其前缀旨在让受害者从自己的 Netlify 域接收恶意内容。由于 Netlify 的缓存设置,有害响应将被保存并持续提供给任何其他试图访问相同 URL 的用户。这样攻击者就可以完全控制 Netlify CDN 上每个网站的每个页面。
H2.TE通过标头名称注入
Atlassian尝试不允许在标头值中使用换行符,但未能过滤标头名称。这很容易被攻击者利用,因为服务器允许在标头名称中使用冒号,这在HTTP/1.1中是不可能实现的。
最初的修复程序也没有过滤伪标头,导致请求行注入漏洞。利用这些很简单,只要可视化注入发生的位置,并确保得到的HTTP/1.1请求有一个有效的请求行:
修复程序的最后一个漏洞是一个典型的错误,即阻止' r\n',而不是阻止' n'本身,后者几乎总是被利用。
隐匿隧道攻击
大多数前端很可以通过任何连接发送任何请求,从而实现跨用户攻击。然而,你会发现你的前缀只会影响来自你自己 IP 的请求。发生这种情况是因为前端为每个客户端 IP 使用与后端的单独连接。这有点麻烦,但你通常可以通过缓存攻击间接攻击其他用户来解决该问题。
其他一些前端在来自客户端的连接和到后端的连接之间强制执行一对一的关系。这是一个更严格的限制,但是常规的缓存攻击和内部标头泄漏技术仍然适用。
当前端选择从不重用与后端的连接时,攻击就会变得非常具有挑战性。此时发送直接影响后续请求的请求是不可能的:
首先是确认漏洞,你可以通过发送一系列请求并查看早期请求是否影响后期请求来确认常规请求走私漏洞。不幸的是,这种技术总是无法确认请求隧道,因此很容易将漏洞误认为是误报。
研究人员需要一种新的确认技术,即简单地走私一个完整的请求,然后看看你是否得到两个响应:
假如你在HTTP/2响应正文中看到HTTP/1标头,你就会发现自己是一个HTTP Desync:
前端服务器通常使用后端响应上的 Content-Length 来决定从套接字读取多少字节。这意味着即使你可以向后端发出两个请求,并从中触发两个响应,前端也只将第一个不太有趣的响应传递给你。
在以下示例中,由于突出显示了 Content-Length,以橙色显示的403响应从未传递给用户:
终端返回的响应太大,导致Burp Repeater稍微滞后,所以研究人员决定将研究人员的方法从POST切换到HEAD来缩短它。这实际上是要求服务器返回响应标头,但省略了响应正文:
果然,这导致后端只服务响应标头,包括未传播正文的Content-Length标头!这使得前端过度读取并提供对第二个走私请求的部分响应:
走私无效请求也会让后端关闭连接,避免意外响应队列攻击的可能性。请注意,如果目标仅易受隧道攻击,则响应队列攻击是不可能的,因此你无需担心。有时,当 HEAD 失败时,其他方法(如 OPTIONS、POST 或 GET)会起作用。研究人员已经将这种技术添加到HTTP Request Smuggler作为检测方法。
请求隧道使你可以使用前端完全未处理的请求到达后端,最明显的利用路径是利用它绕过诸如路径限制之类的前端安全规则。但是,你经常会发现没有任何相关规则可以绕过。幸运的是,还有第二种选择。
前端服务器通常会注入用于关键功能的内部标头,例如指定用户登录的身份。由于前端检测并重写它们,直接利用这些标头的尝试通常会失败。你可以使用请求隧道绕过此重写并成功走私内部标头。
不过有一个问题,攻击者通常看不到内部标头,并且很难利用不知名的标头。只要服务器的内部标头在Param Miner的wordlist中,并且在服务器的响应中引起可见的差异,Param Miner就应该检测到它。
内部标头泄漏
不存在于 Param Miner 的静态词表中或在网站流量中泄露的自定义内部标头可能会逃避检测。常规请求走私可用于使服务器将其内部标头泄露给攻击者,但这种方法不适用于请求隧道。如果你可以通过 HTTP/2 在标头中注入换行符,那么还有另一种发现内部标头的方法。经典的HTTP Desync攻击依赖于让两个服务器对请求正文的结束位置产生分歧,但是使用换行符,研究人员可以让服务器对正文的开始位置产生分歧!
为了获得bitbucket使用的内部标头,研究人员发出了以下请求:
在降级之后,它看起来是这样的:
可以看到,前端认为's=cow'是标头文件的一部分,所以在此之后插入内部标头。这意味着后端最终将内部标头视为研究人员发送到 Wordpress 搜索功能的 's' POST 参数的一部分,并将它们反射回来:
在 bitbucket.org 上访问不同的路径会导致研究人员的请求被路由到不同的后端,并泄漏不同的标头:
你也许可以使用隧道来进行更强大的各种 Web 缓存攻击。此时你需要通过 H2.X desync 获得请求隧道,HEAD 技术有效,并且存在缓存。这将允许你使用 HEAD 通过混合和匹配任意标头和正文创建的有害响应来攻击缓存。
经过一番挖掘,研究人员发现获取 /wp-admin 会触发一个重定向,该重定向反映了 Location 标头内的用户输入,而不对其进行编码。就其本身而言,这是完全无害的 - Location 标头不需要 HTML 编码。然而,通过将它与来自 /blog/404 的响应标头配对,研究人员可以欺骗浏览器来呈现它,并执行任意的JavaScript:
HTTP / 2漏洞利用原语
接下来,让研究人员看看一些HTTP/2利用原语,本节不提供完整的案例研究。
模糊性和 HTTP/2
在HTTP/1中,重复标头对于各种攻击都有用,但不可能发送具有多个方法或路径的请求。HTTP/2决定用伪headers替换请求行,这意味着这现在是可能的。研究人员观察到接受多个 :path 标头的真实服务器,并且服务器实现在它们处理的 :path 中不一致:
此外,尽管 HTTP/2 引入了 :authority 标头来替换 Host 标头,但 Host 标头在技术上仍然是允许的。事实上,据研究人员所知,两者都是可选的。这为 Host-header 攻击创造了充足的机会,例如:
URL前缀注入
HTTP/2的另一个不能忽略的特性是:scheme伪标头,这个值意味着'http'或'https',但它支持任意字节。
包括 Netlify 在内的一些系统使用它来构建 URL,而不执行任何验证。这使你可以覆盖路径,并在某些情况下执行缓存攻击:
其他人使用该方案构建请求路由到的 URL,从而创建 SSRF 漏洞。
与本文中使用的其他技术不同,即使目标没有进行 HTTP/2 降级,这些漏洞也会起作用。
标头名称Split
你会发现有些服务器不允许你在标头名称中使用换行符,但允许使用冒号。由于在降级过程中末尾会附加冒号,这很少启用完全HTTP Desync:
它更适合 Host-header 攻击,因为 Host 应该包含一个冒号,并且服务器通常会忽略冒号之后的所有内容:
请求行(Request-Line) 注入
研究人员确实找到了一台服务器,其中标头名称Split启用了HTTP Desync。在测试中,漏洞消失了,服务器横幅报告说他们已经更新了他们的 Apache 前端。为了追踪这个漏洞,研究人员在本地安装了旧版本的Apache。不过研究人员无法复制这个漏洞。
Apache 的 mod_proxy 允许在 :method 中使用空格,从而启用请求行注入。如果后端服务器容忍请求行末尾的垃圾,这可以让你绕过阻止规则:
逃避子文件夹:
标头篡改
HTTP/1.1曾经有一个功能叫做行折叠,你可以在标头值后面加上一个空格,随后的数据就会被折叠起来。
下面是一个正常发送的相同请求:
使用行转移:
该功能后来被弃用,但许多服务器仍然支持它。
如果你发现一个网站的 HTTP/2 前端允许你发送以空格开头的标头名称,而后端支持换行,则你可以篡改其他标头,包括内部标头。这是研究人员篡改了内部标头请求 ID 的示例,它是无害的,但在后端反映了有用的信息:
许多前端不会对传入的标头文件进行排序,所以你会发现通过移动空格标头,你可以篡改不同的内部和外部标头文件。
安全建议
如果你正在设置 Web 应用程序,千万不要让 HTTP/2 降级,这是上述这些漏洞得逞的根本原因。
本文翻译自:https://portswigger.net/research/http2如若转载,请注明原文地址