HTTP请求走私漏洞
HTTP请求走私漏洞
hihopkc什么是HTTP请求走私
HTTP请求走私攻击,顾名思义,就会像走私一样在一个HTTP请求包中夹带另一个或多个HTTP请求包,在前端看来是一个HTTP请求包,但是到了后端可能会被解析器分解开从而导致夹带的HTTP请求包也会被解析,最终可以导致未授权访问敏感数据或攻击其他用户。
原理
keep-alive 与 pipeline
为了缓解源站的压力,一般会在用户和后端服务器(源站)之间加设前置服务器,用以缓存、简单校验、负载均衡等,而前置服务器与后端服务器往往是在可靠的网络域中,ip 也是相对固定的,所以可以重用 TCP 连接来减少频繁 TCP 握手带来的开销。这里就用到了 HTTP1.1 中的 Keep-Alive 和Pipeline 特性:
所谓 Keep-Alive,就是在 HTTP 请求中增加一个特殊的请求头 Connection: Keep-Alive,告诉服务器,接收完这次 HTTP 请求后,不要关闭 TCP 链接,后面对相同目标服务器的 HTTP 请求,重用这一个 TCP 链接,这样只需要进行一次 TCP 握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。这个特性在 HTTP1.1 中是默认开启的。
有了 Keep-Alive 之后,后续就有了 Pipeline,在这里呢,客户端可以像流水线一样发送自己的HTTP 请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。现如今,浏览器默认是不启用 Pipeline的,但是一般的服务器都提供了对 Pipleline 的支持。
当我们向代理服务器发送一个比较模糊的 HTTP 请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个 HTTP 请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了 HTTP 走私攻击。
- pipline
在1个Tcp连接中发送多个请求
- Content-Length
HTTP包的一个标头,用来指明发送给接收方的消息的大小
- Transfer-Encoding
传输编码
漏洞成因
大多数HTTP请求走私漏洞的出现是因为HTTP规范提供了两种不同的方法指定请求的结束位置。
Content-Length头以字节为单位指定消息正文的长度,例如:
1 | POST /search HTTP/1.1 |
Transfer-Encoding头一般指定正文使用分块编码,例如:
1 | POST /search HTTP/1.1 |
每个块之间以换行符(\r\n)分割开,直到块大小为0字节时视为正文的结束,就是因为这两种不同的方法来指定HTTP消息的长度,就导致如果同时使用这两个头会造成冲突,HTTP规范中规定,如果两个头同时存在则忽略Content-Length头。
HTTP请求走私的几种方式
根据前后端判断数据包是否结束的http头不同,可以分为如下三种情况
CL.TE:前端服务器使用Content-Lengthheader,后端服务器使用Transfer-Encodingheader。
TE.CL:前端服务器使用Transfer-Encodingheader,后端服务器使用Content-Lengthheader。
TE.TE:前端服务器和后端服务器都支持Transfer-Encodingheader,但是可以通过某种方式混淆header来诱导其中一台服务器不处理它。
CL.TE
前置服务器认为 Content-Length 优先级更高(或者根本就不支持 Transfer-Encoding ) ,后端认为Transfer-Encoding 优先级更高。
例如:
1 | POST / HTTP/1.1 |
从上面这一个HTTP请求包来看,CL头设置的是13,即从正文开始算包含13个字节的内容为止算是一个请求包,但是当这个请求包发到后端服务器时会采用TE头来处理请求包,此时会因为0的下一行是空行而认为该请求包已经结束了,那么多出来的内容怎么办呢?会被认为是下一个请求包的开始,此时则会产生HTTP请求走私攻击。
练习靶场:使用portswigger提供的靶场进行学习。
CL头的值为6,就是包含三行共六个字节(包括换行符),TE头指定了使用分块编码,发送两次请求包,成功因为前后端处理方式不同而导致HTTP走私攻击。
TE.CL漏洞
这一种就是前端服务器使用TE头处理,而后端服务器使用CL头处理,我们参考如下示例
1 | POST / HTTP/1.1 |
原理就是前端服务器通过使用TE头指定的分块编码来分割处理请求包,既然是分块编码,就得指定每个分块的大小,就如上述代码所示,第一个分块大小为8字节长,第二个分块大小为0,分块编码会一直读取直到分块大小为0,所以以上的请求包会被前端当成一个请求包转发到后端服务器,但是到了后端服务器会因为CL头指定的长度仅包括了8及后面的CLRF字符而将这个请求包分割成两个处理,这就导致了HTTP请求走私漏洞。
练习靶场:使用portswigger提供的靶场进行学习。
这里有一个需要注意的,就是在0的后面要添加两个空行,然后就也会因为前后端对HTTP请求方式不同而导致HTTP走私攻击
TE.TE漏洞:混淆TE头
现在的场景是虽然前后端都支持TE头,但是可以通过某种混淆手段让某一端不处理TE头,例如
1 | Transfer-Encoding: xchunked |
我们看到有两个TE头,但是有一个TE头是做了混淆的,所以就会导致在后端的时候不使用TE头来处理此时会转而采用CL头处理,从而将一个HTTP请求拆分成两个,导致HTTP走私攻击。
漏洞发现
利用延时方式发现
利用服务器响应延时方式发现CL.TE漏洞
当同时存在CL头和TE头时,如果请求包正文的长度大于CL头指定的长度,则会导致请求包只有CL头指定长度内的内容,从而导致后端服务器因为采用TE头处理而一直等待后续请求包,最终会导致超时,故可以证明存在CL.TE漏洞,例如
1 | POST / HTTP/1.1 |
漏洞利用
练习靶场:使用portswigger提供的靶场进行学习。
实验的最终目的是获取其他用户的Cookie用来访问其他账号。
我们首先去寻找一个能够将传入的信息存储到网站中的POST请求表单,很容易就能发现网站中有一个用户评论的地方。
抓取POST请求并构造数据包
…
漏洞修复
禁用后端连接的重用,防止多个请求拼接
使用HTTP/2用于后端连接,该协议可以防止请求之间的界限模糊不清
前后端使用完全相同的中间件,以保证对请求处理方式的一致性