超详细的HTTP请求走私漏洞教程,看完还不会你来找我。
1. 简介
HTTP请求走私漏洞(HTTP Request Smuggling)发生在前端服务器(也称代理服务器,一般会进行身份验证或访问控制)和后端服务器在解析HTTP请求时,由于对HTTP请求的解析规则不一致,导致攻击者可以将多个请求合并为一个请求,或者将一个请求拆分为多个请求,从而绕过安全措施或未经授权直接与后端服务器进行通信。
说白点就是前端服务器将数据转发给后端,但是如果前端服务器和后端服务器对解析HTTP请求主体长度的规则不一致时,攻击者可以给前端服务器发送一个数据包,但是数据包到后端的时候被解析成了多个数据包,其中的某一个数据包就达到了攻击者的目的。
2. 漏洞危害
HTTP请求走私漏洞可以带来多种严重的安全危害,主要包括以下几点:
- 会话劫持(Session Hijacking)
攻击者可以通过走私请求获取其他用户的会话信息,如会话令牌(session tokens)。这使得攻击者能够冒充合法用户进行操作。 - 缓存投毒(Cache Poisoning)
攻击者可以通过构造特定的HTTP请求将恶意内容缓存到缓存服务器中。随后访问这些缓存内容的用户将收到恶意响应,导致数据篡改或其他恶意行为。 - 跨站脚本攻击(Cross-Site Scripting, XSS)
攻击者可以通过请求走私向目标服务器注入恶意脚本,这些脚本可能被其他用户执行,导致信息泄露或用户会话被劫持。 - 请求伪造(Request Forgery)
攻击者可以通过走私请求伪造合法用户的请求,例如执行未授权的操作、修改数据或访问敏感信息。 - 信息泄露(Information Disclosure)
走私请求可以使攻击者获取不应公开的敏感信息,例如用户数据、系统配置或内部网络结构。 - 拒绝服务攻击(Denial of Service, DoS)
通过请求走私,攻击者可以使目标服务器或其背后的资源超负荷,导致服务中断或性能下降。 - 绕过安全措施
走私请求可能使攻击者绕过Web应用防火墙(WAF)和其他安全设备的检测和防护措施,从而更容易实施其他类型的攻击。 - 任意命令执行(Remote Code Execution)
在某些情况下,攻击者可以利用请求走私漏洞在目标服务器上执行任意代码,完全控制服务器。
3. 漏洞成因
要搞清楚HTTP请求走私漏洞的原理,需要先了解以下概念:
- 前端服务器(Frontend Server):通常是指在网络架构中用来处理客户端请求的服务器,它通常位于客户端和后端服务器之间,以提高性能、安全性和可扩展性,也可理解为代理服务器。特别注意是前端服务器,不是提供用户界面的前端。
- 后端服务器(Backend Server):通常简称为后端,是指在网络应用或网站中负责处理数据存储、业务逻辑和服务器端计算的部分。
HTTP/1协议中获取POST请求主体的方法有2种:
- 根据
Content-Length
值获取请求主体长度(包含\r\n
),然后获取请求主体。 - 根据
Transfer-Encoding
字段来判定请求体的结束位置,然后获取请求主体,使用此请求头的传输方式叫分块传输。
分块传输方式将请求主体分割成若干块,每个块包含一个十六进制数表示的块大小作为前缀,后跟块数据本身和一个CRLF(回车换行)序列。
示例请求:
POST /upload HTTP/1.1\r\n
Host: example.com\r\n
Content-Type: application/json\r\n
Transfer-Encoding: chunked\r\n
\r\n
6\r\n
user=a\r\n
0\r\n
\r\n
Transfer-Encoding: chunked
表示使用分块传输编码。6
表示第一个块的大小(十六进制),不包含\r\n
,对应十进制为 6 字节。user=a
是块的实际数据。0
表示最后一个块的大小为零,这是一个有效的分块传输编码的终止标志。- 最后的
\r\n
表示消息体的结束。
正是因为 HTTP/1 规范提供了两种不同的方法来指定 HTTP 主体的长度,当Web应用的前端服务器和后端服务器获取HTTP请求主体的方法不同时,可能会对连续请求之间的边界产生分歧,从而导致请求走私漏洞。
现在的Web应用通常不是只部署后端服务器,为了提高性能和安全会在用户和后端服务器之间部署前端服务器(负载均衡、反向代理、CDN和Waf等),用户的请求先到达前端服务器,前端服务器根据策略和规则转发到对应的后端服务器。正常情况下前端服务器依次将A数据包和B数据包进行转发:
当前端服务器和后端服务器对HTTP请求的解析处理方式不一致时,会导致HTTP请求走私漏洞。如攻击者可以在A请求中注入部分数据,前端服务器没发现问题后将数据转发给后端服务器,后端服务器以为前端服务器发送了2个请求,把A中注入的数据作为下一个请求的开始或独立作为下一个请求进行处理,从而达到攻击者的目的:
大家可能会想:没有使用前端服务器的Web应用是不是就安全了?
答案是否定的,有些Web应用使用了Nginx反向代理、集成负载均衡、Waf等功能,这些组件相当于前端服务器,仍然有可能存在HTTP请求走私漏洞,如VPN、EDR、WAF等系统在HW时就经常被攻击者利用HTTP请求走私漏洞Getshell。
HTTP请求走私漏洞的成因主要是由于不同服务器在处理和解析HTTP请求时对某些请求头的理解和处理方式不一致。以下是一些常见的成因:
3.1 请求头解析不一致
由于 HTTP/1 规范提供了两种不同的方法来指定 HTTP 消息的长度,当一个请求同时使用这两种方法时。某些服务器会优先解析Content-Length
头,某些服务器会优先解析Transfer-Encoding
头,这是最常见的情况。前端服务器和后端服务器可能对这两个头部的处理方式不同,从而导致解析混乱。攻击者可以利用这种解析不一致来构造恶意请求。
示例请求:
POST / HTTP/1.1
Host: example.com
Content-Length: 13
Transfer-Encoding: chunked
0
GET /malicious HTTP/1.1
Host: example.com
在这个例子中,前端服务器可能认为请求的内容长度为13字节,而后端服务器则根据Transfer-Encoding: chunked
解析请求。由于两者解析方式不同,可能导致后端服务器将GET /malicious HTTP/1.1
作为一个新的请求处理。
3.2 HTTP协议版本不一致
HTTP/1.1和HTTP/2协议在请求解析方面存在细微差别,特别是在多路复用和头部压缩方面,可能导致解析不一致。
3.3 多请求处理机制(HTTP管道化)
HTTP/1.1支持管道化,允许在同一连接中发送多个请求而无需等待响应。不同服务器处理管道化请求的顺序可能不同,导致请求走私。
示例请求:
POST / HTTP/1.1
Host: example.com
Content-Length: 44
POST /api HTTP/1.1
Host: example.com
Content-Length: 11
X: X
GET /malicious HTTP/1.1
Host: example.com
前端服务器可能会将第一个POST请求的内容转发给后端服务器,而后端服务器会将GET /malicious
请求视为一个独立的请求。
3.4 头部解析优先级和规则不同
不同服务器可能按照不同的顺序解析HTTP头部,导致解析不一致。
示例请求:
POST / HTTP/1.1
Host: example.com
Content-Length: 5
0
GET /malicious HTTP/1.1
Host: example.com
前端服务器可能会认为Content-Length: 5
表示请求体长度为5字节,而后端服务器可能会根据实际内容解析,导致解析不一致。
3.5 特殊字符和编码处理
不同服务器对特殊字符(如换行符、回车符)和URI编码的处理方式不同,可能导致解析不一致。
示例请求:
POST / HTTP/1.1
Host: example.com
Content-Length: 15
GET /malicious HTTP/1.1%0D%0A
在这个示例中,特殊字符%0D%0A
(回车和换行)可能导致不同服务器解析方式不同,导致请求走私。
3.6 代理服务器和负载均衡器的特性
代理服务器或负载均衡器在转发请求时可能会重新格式化或修改请求头,导致后端服务器错误地解析请求。
代理服务器可能会根据Transfer-Encoding: chunked
解析请求,而后端服务器根据Content-Length
解析,导致解析不一致。
3.7 缓存机制的影响
缓存服务器对请求进行缓存和优化处理,不同服务器对缓存请求的处理策略不同,可能导致请求走私。
3.8 网络设备的处理差异
防火墙和入侵检测系统(IDS/IPS)在解析HTTP请求时,可能会采取不同的策略,导致请求在通过设备时被修改或重新解释。
4. 漏洞检测
常见的HTTP/1请求走私漏洞有:CL.TE
、TE.CL
、TE.TE
、CL.CL
和CL.0
,常见的HTTP/2请求走私漏洞有:H2.CL
、H2.TE
和H2.0
。通常使用延时和差异响应进行检测,也可以使用Burp自身的扫描功能或HTTP Request Smuggler
插件以及其它工具检测,Burp目前默认使用HTTP/2协议,如果需要测试HTTP/1的漏洞则点击设置,取消默认HTTP/2即可:
使用Burp手工检测HTTP请求走私漏洞时,可以将Repeter中请求添加到Group然后使用Group的发送模式以提高效率和准确性,通常使用Send group(single connection)
发送模式代替手动依次发送数据包。Send group(single connection)
和依次手动发送的区别是:
Send group (single connection)
:使用相同的TCP连接来发送多个HTTP请求,两个请求被几乎同时发送,一个接着一个。适用于测试在同一个连接中连续发送多个请求的情况,更易于发现HTTP请求走私等解析问题。- 依次手动发送:每个请求可能使用不同的TCP连接,具体取决于服务器和客户端的配置。两个请求之间可能会有明显的时间间隔,适合测试普通的HTTP请求和响应行为。
为了更好的理解HTTP请求走私漏洞,本文循序渐进的描述HTTP请求走私漏洞及测试方法,大多数情况下使用手动依次请求的方式,熟悉漏洞后使用Group功能,实际测试中则使用Group功能较多。
4.1 HTTP/1请求走私漏洞
4.1.1 CL.TE 漏洞
当前端服务器用Content-Length
头获取请求主体,后端服务器用Transfer-Encoding
头获取请求主体时,存在此漏洞。
使用Burp提供的漏洞环境:HTTP request smuggling, basic CL.TE vulnerability
使用差异响应检测
访问目标,使用Burp抓包,添加Transfer-Encoding: chunked
请求头和请求主体。第一次请求返回200,第二次请求时返回403,说明漏洞存在:
这是因为前端服务器根据Content-Length
确定请求主体长度为6个字节,即获取整个请求数据,并将此请求转发到后端服务器。但后端服务器用Transfer-Encoding
头获取分块数据,第一个块就为0数据块,因此处理终止,后端服务器将G
视为下一个请求的开始。此时,如果前端服务器继续向后端服务器转发请求,那么后端服务器下一个接收到的请求就会是:
GPOST / HTTP/1.1
Host: xxx
...
还可以这样构造Payload验证,第一次请求返回200,第二次请求返回404,说明漏洞存在:
后端服务器根据Transfer-Encoding
将请求主体中0\r\n\r\n
后的数据解析为第二个请求的开头,后端服务器收到的请求为:
GET /robots.txt HTTP/1.1
A: 1POST / HTTP/1.1
...
使用延时检测
正常请求时,响应速度快:
构造没有结束的分块传输数据包,响应变慢:
这是因为前端服务器正常通过Content-Length
头确定请求主体长度,后端服务器使用Transfer-Encoding
标头,处理第一个块,然后等待下一个块到达,但是下一个块迟迟没有到达,因此响应时间较长。
4.1.2 TE.CL 漏洞
当前端服务器用Transfer-Encoding
头获取请求主体,后端服务器用Content-Length
头获取请求主体时,存在此漏洞。
使用Burp提供的漏洞环境:HTTP request smuggling, basic TE.CL vulnerability
此方式需要关闭Burp自动更新Content-Length
的功能,取消勾选Update Content-Length
即可:
使用差异响应检测
访问目标,使用Burp抓包,添加Transfer-Encoding: chunked
请求头和请求主体,第一次请求返回200,第二次发送的请求为TEST0POST
,返回403,说明漏洞存在:
这是因为前