1.产生原因
HTTP请求走私漏洞的出现是因为:HTTP规范提供了两种不同的方法来指定请求的结束位置:Content-Length
标头和Transfer-Encoding
标头。
Transfer-Encoding
如果一个HTTP消息(请求消息或应答消息)的Transfer-Encoding
消息头的值为chunked
,那么,消息体由数量未定的块组成,并以最后一个大小为0的块为结束。
例如:
POST / HTTP/1.1
Host: test.com
......
Connection: keep-alive
Transfer-Encoding: chunked
0\r\n
\r\n//回车
1\r\n
这里的post数据服务器解析到回车的时候结束。1将被舍弃。
Content-Length
如果一个HTTP消息,消息头是Content-Length
,那么,消息体字符数量将由其值决定。
例如:
POST / HTTP/1.1
Host: test.com
......
Connection: keep-alive
Content-Length:4
0\r\n
1\r\n
2
这里的post数据服务器解析到2的时候结束。2将被舍弃。
实现过程
如下为拓扑结构:
用户向目标网站发送一个网络请求,但是这个请求是由反向代理服务器帮忙转发。一般情况下,反向代理服务器会实现一些WAF的功能。如果用户想要绕过这个WAF就相当于走私。
由上述两种请求结束位置的解析差异便可以构成HTTP请求走私。
HTTP请求走私攻击将两个标头放在一起进行混淆便有了四种形式以及一种特殊形式:
形式 | 反向代理服务器解析模式 | 服务器解析模式 |
---|---|---|
CL-CL | Content-Length | Content-Length |
TE-CL | Transfer-Encoding | Content-Length |
CL-TE | Content-Length | Transfer-Encoding |
TE-TE | Transfer-Encoding | Transfer-Encoding |
CL不为0 | 允许携带请求体 | 不允许携带请求体 |
一、CL不为0
前端代理服务器允许GET请求携带请求体;后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的Content-Length
头,不进行处理。这就有可能导致请求走私。
GET / HTTP/1.1\r\n
Host: test.com\r\n
Content-Length: 44\r\n
GET / secret HTTP/1.1\r\n
Host: test.com\r\n
\r\n
过程:
①代理服务器允许携带请求体,检验通过并转发给服务器
②服务器不允许携带请求体,忽略Content-Length
由于Pipeline的存在,后端服务器就认为这是收到了两个请求,分别是:
GET / HTTP/1.1\r\n
Host: test.com\r\n
GET / secret HTTP/1.1\r\n
Host: test.com\r\n
二、CL-CL
RFC7230规范
在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。
有些服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误。
但是如果中间代理服务器按照第一个Content-Length的值对请求进行处理,后端源站服务器按照第二个Content-Length的值进行处理就会出现问题。
POST / HTTP/1.1\r\n
Host: test.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n
12345\r\n
a
代理服务器可以全部识别,但是服务器会忽略a,这时a就会保存在缓存中,如果接着有新的请求
GET /index.html HTTP/1.1\r\n
Host: test.com\r\n
便会与后面的请求拼接在一起。形成:
aGET /index.html HTTP/1.1\r\n
Host: test.com\r\n
发送错误。
三、CL-TE,TE-CL
当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length
请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length
,处理Transfer-Encoding
请求头。
具体过程不再分析。
四、TE-TE
TE-TE,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding请求头,确实是实现了RFC的标准。不过前后端服务器不是同一种。这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding进行某种混淆操作(如某个字符改变大小写),从而使其中一个服务器不处理Transfer-Encoding请求头。在某种意义上这还是CL-TE或者TE-CL。
总结
虽然有五种方法但是最好用的还是CL-TE,其他的和它基本都差不多。
参考例题:[RoarCTF 2019]Easy Calc