HTTP请求走私
HTTP请求走私
简介
HTTP请求走私是一种干扰网站处理从一个或多个用户接收的HTTP请求序列的方式,用以绕过安全控制并获得未经授权的访问,执行恶意活动,最早在 2005 年被提出
成因
在正常情况下用户发出的 HTTP 请求的流动如下图:
可以看到在长度标记正常的情况下,蓝色和绿色的数据包被正确的区分,不同用户的数据在后端被正确还原
在整个过程中,最关键的是前置服务器和后端服务器应当在 HTTP 请求的边界划分上达成一致,否则就会导致下图所示的异常:
(图中橙色的部分为走私的内容)
当我们向代理服务器发送一个比较模糊(接收到的实际长度和报文中标的长度不同)的 HTTP 请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个 HTTP 请求
即前端服务器和后端服务器对客户端传入的数据理解不一致的情况,即 Content-Length
和 Transfer-Encoding
标头。然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了 HTTP 走私攻击
Content-Length和Transfer-Encoding
Content-Length
HTTP状态码,代表 HTTP消息长度, 用十进制数字表示. 若Content-Length比实际消息长度短, 请求被截断, 而且下一个请求解析出现错乱.。Content-Length比实际消息长度长,请求将无响应直到超时
Transfer-Encoding: chunked
代表数据以一系列分块的形式进行发送.。Content-Length 首部在这种情况下应该不被发送。 在每一个分块的开头需要添加当前分块的长度, 以十六进制的形式表示,后面紧跟着 \r\n(回车换行) , 之后是分块本身, 后面也是\r\n。 终止块是一个常规的分块, 不同之处在于其长度为0。后面跟两个\r\n
分类
CL-TE:前端服务器使用
Content-Length
头,后端服务器使用Transfer-Encoding
头前置服务器认为
Content-Length
优先级更高(或者根本就不支持Transfer-Encoding
) ,后端认为Transfer-Encoding
优先级更高
所谓CL-TE,顾名思义就是收到包含Content-Length和Transfer-Encoding这两个请求头的请求时,前端代理服务器按照Content-Length这一请求头定界,而后端服务器则以Transfer-Encoding请求头为标准
1 |
|
前端服务器处理Content-Length头并确定请求主体长度为16个字节,直到chunkedcode结束。此请求将转发到后端服务器
后端服务器处理Transfer-Encoding标头,因此将消息体视为使用分块编码。它处理第一个块,它被称为零长度,因此被视为终止请求。缓冲区内还剩下chunkedcode,由于存在pipeline技术,后端服务器将这些字节视为队列中下一个请求的开始
如果此时其他用户此时发送了一个 GET 请求,就会与 chunkedcode 拼接成一个畸形的 chunkedcodeGET,造成服务器解析异常
- CL-CL:前端和后端服务器都支持
Content-Length
标头
攻击者可以恶意构造一个特殊的请求
1 |
|
后端服务器获取到的数据包长度为5。当读取完前5个字符后,后端服务器认为该请求已经读取完毕,然后发送出去。而此时的缓冲区去还剩余一个字母 A,对于后端服务器来说,这个 A是下一个请求的一部分,但是还没有传输完毕
此时恰巧有一个其他的正常用户对服务器进行了请求,则该A字母会拼凑到下一个正常用户请求的前面,攻击在此展开
- TE-CL:前端服务器使用
Transfer-Encoding
标头,后端服务器使用Content-Length
标头。
这种情况则属于前端服务器处理Transfer-Encoding请求头,而后端服务器处理Content-Length请求头
构造数据包
1 |
|
前端服务器处理Transfer-Encoding请求头,因此将消息体视为使用分块编码,处理第一块时,有11个字节,直到chunkedcodede的最后一个字节。开始处理第二个块,第二块是0个字节,视为终止请求。此时把请求转发到后端。而后端则在11处完成了对第一个数据包的读取,chunkedcodern0为下一个数据包的开始部分
- TE-TE:前端和后端服务器都支持
Transfer-Encoding
标头,但是可以通过以某种方式来诱导其中一个服务器不处理它。
前端服务器处理第一个Transfer-Encoding请求头,后端服务器处理第二个Transfer-Encoding请求头。
构造数据包
1 |
|
这里是用了两个Transfer-Encoding 字段,并且第二个 TE 字段值为错误值,这里 前端服务器选择对第一个 Transfer-Encoding进行处理,整个请求正常,原封不动转发给后端服务器,而后端服务器则以第二个Transfer-Encoding 字段进行优先处理,而第二个Transfer-Encoding 字段非标准值,根据RPC规范,则会取Content-Length字段进行处理,这样这个请求就会被拆分为两个请求。