HTTP请求走私

在一次比赛中,了解到了HTTP请求走私漏洞,目前我只接触到django和Nginx一起组合,实现负载均衡,所以靠近于代理端,即前端控件的我没怎么了解过。

0x01 漏洞成因

​ 漏洞成因是由于前端控件(一般指代理服务器)对HTTP协议的长度截取和后端服务器的截取不同导致。HTTP规范提供了两种不同的方法来指定请求的结束位置:Content-Length标头和Transfer-Encoding标头,若同一请求前端与后端所使用的规范不同就可能导致解析差异,从而造成请求走私。一般服务器有三种解析方式:

1
2
3
CL.TE:前端服务器使用Content-Length标头,而后端服务器使用Transfer-Encoding标头。
TE.CL:前端服务器使用Transfer-Encoding标头,而后端服务器使用Content-Length标头。
TE.TE:前端服务器和后端服务器都支持Transfer-Encoding标头,但是可以通过对标头进行某种方式的混淆来诱导其中一台服务器不对其进行处理。

这里的解析错误主要取决于HTTP1.1中的两个特性:keep-alive 与 pipeline

Keep-Alive:是在 HTTP 请求中增加一个特殊的请求头 Connection: Keep-Alive,告诉服务器,接收完这次 HTTP 请求后,不要关闭 TCP 链接,后面对相同目标服务器的 HTTP 请求,重用这一个 TCP 链接,这样只需要进行一次 TCP 握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。这个特性在 HTTP1.1 中是默认开启的。

Pipeline(http管线化):http管线化是一项实现了多个http请求但不需要等待响应就能够写进同一个socket的技术,仅有http1.1规范支持http管线化。在这里,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。

示例如下:

1
2
3
4
5
6
GET / HTTP/1.1
Host: Sentiment.com
Content-Length: 44

GET /secret HTTP/1.1
Host: Sentiment.com

在前端控件中会对监测到是一个请求,而后端则可能是认为两个请求。

前端控件认为GET能带body,后端控件认为不带body,分解成两个请求然后返回两个响应,那么第二个响应就绕过了前端的检测,造成了走私。

0x02 Gunicorn 20.0.4 请求走私

当代理使用Haproxy,服务器用的是Gunicorn并且版本高于20.0时,就有了这种新的利用方式。它是由对标头的特殊解析引起的。Sec-Websocket-Key1

同样的原理,前端控件通过Content-Length识别报文的大小,而后端通过Sec-Websocket-Key来识别报文的长度,

image-20220514011038059

在这里我们是无法访问到fl4g的,但是

https://blog.csdn.net/sycamorelg/article/details/122229190

https://blog.csdn.net/weixin_54902210/article/details/124580510