最近压力暴大,可能是开始解出一些让我感到困难且无从下手的内容吧(永远讨厌php),所以来学一学http请求走私这块内容(原理等相对简单,给了我很大的放松感)
什么是http请求走私
http请求走私可以通过欺骗代理服务器,负载均衡器或者服务器中的中间节点,利用前后不一致的验证方式实现请求走私危害,可以造成数据泄露,访问控制绕过,会话劫持,跨站脚本攻击等危害
前置知识
CL(Content-Length)
这个也太常见了,我想不用解释大家也知道是什么,这里就不过多解释,不懂的可以google一下
TE(Transfer-Encoding)
这个就是一种传输编码方式,跟它的名字一样,就是在传输过程中对消息体进行编码,然后可以在传输过程中对消息体进行压缩或分块传输等操作。当服务器无法确定响应的大小时,如动态生成的响应或者通过流式传输时,就可以使用Transfer-Encoding来实现分块传输(0就是截断)
漏洞成因
主要就是因为前后端校验不一致造成的,前端与后端的校验方法不一致,前端对包进行校验后交给后端,但是后端校验方法不同,对包进行异常截断,所以这导致请求走私
请求走私分类
CL不为0的GET请求
前端代理服务器允许GET请求携带请求体,但后端服务器不允许GET请求携带请求体,则后端服务器会忽略掉GET请求中的Content-Length,不进行处理,从而导致请求走私,代码演示如下:
1 | GET / HTTP/1.1\r\n |
前端服务器收到该请求,通过读取Content-Length,判断这是一个完整的请求,然后转发给后端服务器,而后端服务器收到后,因为它不对Content-Length进行处理,由于Pipeline的存在,它就认为这是收到了两个请求。
CL-CL
假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误,但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端服务器按照第二个Content-Length的值进行处理。这样有可能引发请求走私
1 | POST / HTTP/1.1\r\n |
前端代理服务器获取的数据包长度为 8,将以上数据包完整转发至后端服务器,但后端服务器仅接收长度为7的数据包。因此读取前7个字符后,后端服务器认为本次请求已经读取完毕,然后返回响应。
但此时缓冲区仍留下一个a,对于后端服务器来讲,这个a是下一个请求的一部分,但没传输完毕。如果此时传来一个请求:
1 | GET / HTTP/1.1 |
那么前端服务器和后端服务器将重用TCP连接,使后端实际接收的请求为:
1 | aGET / HTTP/1.1 |
CL-TE
CL-TE,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length这一请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length,处理Transfer-Encoding这一请求头。
chunk传输数据格式如下,其中size的值由16进制表示
1 | [chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n] |
构造数据包如下
1 | POST / HTTP/1.1\r\n |
在bp靶场中进行测试
会发现由于前端服务器处理Content-Length,所以这个请求对于它来说是一个完整的请求,请求体的长度为6,也就是
1 | 0\r\n |
当请求包经过代理服务器转发给后端服务器时,后端服务器处理Transfer-Encoding,当它读取到0\r\n\r\n时,认为已经读取到结尾了,但是剩下的字母G就被留在了缓冲区中,等待后续请求的到来。当我们重复发送请求后,发送的请求在后端服务器拼接成了类似下面这种请求。
1 | GPOST / HTTP/1.1\r\n |
TE-CL
TE-CL,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding这一请求头,而后端服务器处理Content-Length请求头。
构造数据包
1 | POST / HTTP/1.1\r\n |
在bp靶场中测试
由于前端服务器处理Transfer-Encoding,当其读取到0\r\n\r\n时,认为是读取完毕了,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length请求头,当它读取完12\r\n之后,就认为这个请求已经结束了,后面的数据就认为是另一个请求了,也就是
1 | GPOST / HTTP/1.1\r\n |
TE-TE
TE-TE,也很容易理解,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding请求头,这确实是实现了RFC的标准。不过前后端服务器毕竟不是同一种,这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding进行某种混淆操作,从而使其中一个服务器不处理Transfer-Encoding请求头。从某种意义上还是CL-TE或者TE-CL
构造请求包
1 | POST / HTTP/1.1\r\n |
bp靶场
需要\r\n\r\n在后面加上尾随序列 0
检测请求走私
手动检测主要依靠计时技术和差异响应
计时技术检测CL-TE漏洞
如果应用程序容易受到请求走私的CL-TE变体的攻击,则发送如下所示的请求通常会导致时间延迟
1 | POST / HTTP/1.1 |
由于前端服务器使用Content-Length标头,因此它将仅转发此请求的一部分,而忽略X。后端服务器使用Transfer-Encoding标头,处理第一个块,然后等待下一个块到达。这将导致明显的时间延迟
计时技术检测TE-CL漏洞
如果应用程序容易受到TE-CL变种的请求走私攻击,则发送如下所示的请求通常会导致时间延迟
1 | POST / HTTP/1.1 |
于前端服务器使用Transfer-Encoding标头,因此它将仅转发此请求的一部分,而忽略X。后端服务器使用Content-Length标头,期望消息正文中有更多内容,然后等待其余内容到达。这将导致明显的时间延迟
如果应用程序容易受到该漏洞的CL-TE变体的攻击,则基于时间的TE-CL漏洞测试可能会破坏其他应用程序用户。因此,要隐身并最大程度地减少中断,应该首先使用CL-TE测试,只有在第一个测试失败的情况下才继续进行TE-CL测试
差异响应检测CL-TE漏洞
构造数据包
1 | POST / HTTP/1.1 |
如果攻击成功,则后端服务器会将此请求的最后两行视为属于接收到的下一个请求。这将导致随后的“正常”请求如下所示
1 | POST /404 HTTP/1.1 |
由于此请求现在包含无效的URL,因此服务器将以状态代码404进行响应,攻击请求确实对其进行了干扰
所以说这个请求包后续会回显一个error或者invalid request作为特征
差异响应检测TE-CL漏洞
构造如下请求包(需要\r\n\r\n在final 后面加上尾随序列0)
1 | POST / HTTP/1.1 |
如果攻击成功,则后端服务器将从GPOST / HTTP/1.1开始将所有内容视为属于接收到的下一个请求。这将导致随后的“正常”请求如下所示
即会回显出GPOST的request方式
工具检测
我们也可以利用工具进行检测
https://github.com/anshumanpattnaik/http-request-smuggling
或者直接搜bp插件,在BAPP上搜索HTTP Request Smuggler即可
全文几乎是”fork”自博客https://zhuanlan.zhihu.com/p/643981358,这篇文章讲的实在是精彩,而且通俗易懂