0x00 发展线
最早在2005年,由Chaim Linhart,Amit Klein,Ronen Heled和Steve Orrin共同完成了一篇关于HTTP Request Smuggling这一攻击方式的报告。通过对整个RFC文档的分析以及丰富的实例,证明了这一攻击方式的危害性。
https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf
在2016年的DEFCON 24 上,@regilero在他的议题——Hiding Wookiees in HTTP中对前面报告中的攻击方式进行了丰富和扩充。
https://media.defcon.org/DEF CON 24/DEF CON 24 presentations/DEF CON 24 - Regilero-Hiding-Wookiees-In-Http.pdf
在2019年的BlackHat USA 2019上,PortSwigger的James Kettle在他的议题——HTTP Desync Attacks: Smashing into the Cell Next Door中针对当前的网络环境,展示了使用分块编码来进行攻击的攻击方式,扩展了攻击面,并且提出了完整的一套检测利用流程。
https://www.blackhat.com/us-19/briefings/schedule/#http-desync-attacks-smashing-into-the-cell-next-door-15153
0x01 相关知识介绍
我们先来介绍一下如今使用最广泛的HTTP 1.1协议的特性,HTTP 1.1主要增加了 Keep-Alive 和 Pipeline特性。
Keep-Alive
Keep-Alive就是在HTTP请求中增加一个特殊的请求头Connection:Keep-Alive,以此来告诉服务器,在接收完请求后,不要关闭TCP连接。
后面对相同目标服务器的HTTP请求,重用这个TCP连接,这样只需要进行一次TCP握手的过程,以此来减少服务器的开销,节省资源。
Pipeline
Pipeline出现在Keep-Alive之后,他可以让客户端像流水线一样发送自己的请求。
在没有使用Pipeline时,TCP传输http请求是这样实现的
使用Pipeline后,TCP传输http请求是这样实现的
Pipeline的出现改变了http请求后必须得到响应再发起下一个请求的现状
网站结构
当前很多的web站点都采用一个代理服务器来提升用户体验效果,由此当前大多数的web站点结构如下图所示
反向代理服务器用来实现静态文件缓存,使得用户可以直接从反向代理服务器获取前端静态文件,从而加快访问速度等。
LAMP1/2用来跑WEB服务。
0x02 漏洞原理
HTTP请求走私的产生主要是由于反向代理服务器和后端服务器对HTTP解析的不一致
它和Content-Length与Transfer-Encoding有关,反向代理服务器和后端服务器对这两个请求头解析不一致导致HTTP请求走私的产生
反向代理服务器和后端服务器需对结束位置达成一致。否则,攻击者发送一个模棱两可的请求被反向代理服务器解析为一个请求,被后端服务器解析为两个请求。
攻击者发送的被后端解析成两个的请求,如果解析成的第二个满足成为新的请求的条件则直接响应该请求,如果解析成的第二个不满足成为新的请求的条件则拼接到下一个新请求中。(如上图橙色部分)
0x03 漏洞分类
CL不为0的GET请求
所有不携带请求体的HTTP请求都有可能受此影响。这里用GET请求举例。
当前端服务器允许GET请求携带请求体,而后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的 Content-Length 头,不进行处理。例如下面这个例子:
GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 44\r\n
GET /secret HTTP/1.1\r\n
Host: example.com\r\n
\r\n
前端服务器处理了 Content-Length ,而后端服务器没有处理 Content-Length ,基于pipeline机制认为这是两个独立的请求,就造成了漏洞的发生。
CL-CL
根据RFC 7230,当服务器收到的请求中包含两个 Content-Length ,而且两者的值不同时,需要返回400错误,但是有的服务器并没有严格实现这个规范。这种情况下,当前后端各取不同的 Content-Length 值时,就会出现漏洞。例如:
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n
12345\r\n
a
这个例子中a就会被带入下一个请求,变为 aGET / HTTP/1.1\r\n 。
前端服务器按照第一个CL(Content-Length)进行解析,后端服务器按照第二个CL进行解析。
前端服务器将整个数据包转发给后端服务器,后端服务器进行解析时,读取请求体中的7位字符(\r和\n都算一个字符)进行响应,
但是后端服务器内存中还有一个a没有进行使用,a将自动拼接到一下个请求中,造成如上结果。
CL-TE
RFC2616规范
如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length。
所以请求包中同时包含这两个请求头并不算违规,服务器也不需要返回400错误。导致服务器在这里的实现更容易出问题。
CL-TE指前端服务器处理 Content-Length 这一请求头,而后端服务器遵守RFC2616的规定,忽略掉 Content-Length ,处理 Transfer-Encoding 。例如:
POST / HTTP/1.1\r\n
Host: example.com\r\n
...
Connection: keep-alive\r\n
Content-Length: 6\r\n
Transfer-Encoding: chunked\r\n
\r\n
0\r\n
\r\n
a
这个例子中a同样会被带入下一个请求,变为 aGET / HTTP/1.1\r\n
TE-CL
TE-CL指前端服务器处理 Transfer-Encoding 请求头,而后端服务器处理 Content-Length 请求头。例如:
POST / HTTP/1.1\r\n
Host: example.com\r\n
...
Content-Length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
12\r\n
aPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n
TE-TE
TE-TE指前后端服务器都处理 Transfer-Encoding 请求头,但是在容错性上表现不同,例如有的服务器可能会处理 Transfer-encoding ,测试例如:
POST / HTTP/1.1\r\n
Host: example.com\r\n
...
Content-length: 4\r\n
Transfer-Encoding: chunked\r\n
Transfer-encoding: cow\r\n
\r\n
5c\r\n
aPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n
0x04 漏洞利用
HTTP走私主要有如下几个利用点:
- 绕过WAF
- XSS(使用条件比较极端)
- 获取其他用户的请求信息(一般出现在存在输入框的界面)
- 缓存投毒
0x05 漏洞预防
- 禁用代理服务器与后端服务器之间的TCP连接重用。
- 使用HTTP/2协议。
- 保持前后端web容器的配置一致。