分块传输理论知识

分块传输绕waf技术已经公开好几年,学习后作此总结。

HTTP/1.1中引入了分块传输编码的数据传输机制,允许客户端将请求体分块再传输,这得益于HTTP/1.1的长连接机制,分块传输的本意是为了提高效率,如将数据分块后再传输可以对每个数据块单独操作(如压缩解压缩、计算、整合等),而不需要等所有数据发送或接收完毕后再操作,大大节约时间空间成本。

分块传输的数据格式:

  • 请求响应头不需要指定Content-Length,但是需要加入Transfer-Encoding: chunked来表明本数据包使用分块传输;

  • 同时数据体分割为一系列数据块,每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括自己的结尾(rn),也不包括分块数据结尾的;

  • 最后一个分块长度值必须为 0,对应的分块数据没有内容(两个空行),表示实体结束。

1
2
3
4
5
6
7
8
9
Transfer-Encoding: chunked

4
abcd
3
abc
0


同时也可以在长度后加入注释内容,使用分号来表示注释开始

1
2
3
4
5
6
7
8
9
Transfer-Encoding: chunked

4;注释
abcd
3;zhushi1111111111111111
abc
0


根据上述规则对数据进行分块传输,wireshark抓包看到http请求中的分块传输数据,长度与Burp中编码后的一致

image-20220828235548476

对data做16进制转字符也能得到原始数据

image-20220828235503535

分块传输实践

分块传输过安全狗

这里用的安全狗(Apache服务器版)V4.0.18089进行测试,需要配置打开SQL注入的POST拦截

直接注入被拦截:

image-20220828123803752

对数据进行分块传输,不再拦截

image-20220828125023064

查当前用户:

1
id=2+and+extractvalue(1,concat(0x7e,(select+user()),0x7e))--+&submit=%E6%9F%A5%E8%AF%A2

拦截

image-20220828161548867

分块传输,不拦截

image-20220828161327563

当然也可以加入注释,即在每一个数据块大小后加入;注释字符,用来绕过检测分块传输的waf,不过早在几年前也已经被过滤了

image-20220828162322392

SQLMap联动分块传输插件

需要用到BurpSuite分块传输插件chunked-coding-converter,将SQLMap的流量代理到BurpSuite,BurpSuite中chunked-coding-converter config设置为Proxy自动分块

image-20220907231044077

此时只要是通过代理走BurpSuite的流量都会被分块传输

1
python .\sqlmap.py -r E:\Desktop\req.txt --batch --proxy http://127.0.0.1:8080 --dbs

image-20220828163554689

可以在Burp Logger中看到大量从SQLMap中过来的数据包,被插件进行分块传输编码,绕过waf注入

image-20220828164002974

延时分块传输

在普通分块传输、带注释污染数据的分块传输均已经被主流waf拼接数据后进行防护拦截,又出现了绕过方法,即延时分块。

延时分块绕过的原理:

  • 在原有分块传输的基础上每个分块加入延时,用以增加安全设备的等待时间,当等待时间超过安全设备的资源设定时间时,出于性能和业务的考量,安全设备会提前终止数据的接收拼接,即可实现脏数据的插入。

延时分块的注意点:

  • 块与块之间发送的时延必须要小于后端中间件的timeout,Tomcat默认是20s,WebLogic是30s。

延时分块的实际利用:

  • 同样可以使用BurpSuite分块传输插件chunked-coding-converter,c0ny1表哥在之前工具的基础上已经加入了延时功能,可设置分块长度以及每个分块的延时时间,并且会显示预计的分块数量和总耗时,配置好即可start进行延时注入

image-20220828215154250

所有分块发送完毕后在response处查看结果。

个人疑点之分块传输深度探究

看完分块传输技术以及分块传输绕过waf的文章,当然不仅仅指的是本文,不知道你是否有以下疑惑:

  1. 客户端发送一个分块编码的http请求,为什么服务端就会分块接收?
  2. 整个分块的数据请求还是同一个http包发送接收的,为什么能够边发送边接收、边计算、边整合?
  3. 底层究竟是如何分块发送、接收的?

我在网上查了一些文章,但始终没有查到这部分内容,大都直接讲分块传输的几大好处如边传输边压缩、边传输边计算等,因此无法彻底理解分块传输的原理、过程、效果,索性抓包探究一下。

这里使用Wiresshark抓包,动图演示一下分块传输的数据包过程,为了更直观此处使用的延时分块

GIF 2022-9-8 1-54-35

可以看到,每进行一次分块数据传输,就会发送几条对应的TCP请求响应包,看似是POST包,其实是传输层TCP层的数据包,只是Wireshark为了方便查看这样展示的,追踪TCP流后就会显示正常。

对分块传输的数据包分析如下图:

image-20220908020937087

第一步:点击发送以后,首先进行TCP的三次握手,随即用2个TCP包分别发送http请求的首行(请求行)和请求头+第一个数据块。

image-20220908104346863

第二步:用2个TCP请求实现一个数据块的传输,第一个TCP发送数据块大小,第二个TCP发送数据块内容。

原本的TCP MTU为1460,但是可以看到由于进行分块编码传输,所以每个包都没发满传输单元

image-20220908104833270

第三步:当所有分块数据都用步骤二发送完毕时,再发送一个数据结束标识符,即0\r\n\r\n,Wireshark进行了可视化组装,所以要在HTTP请求中看。

image-20220908144153726

这样一次分块传输的数据就发送完成了。

这样看来Wireshark中显示的HTTP数据包其实是自己组装起来展示的,因为它监听的是网卡数据,而发包时数据流向是自顶向下,即应用层->传输层->网络层->数据链路层->物理层,Wireshark接收到所有数据后进行组装,来做可视化展示。

经过以上实操学习,总结起来,个人的疑虑无非用一句话解释:分块传输发生在TCP传输层,HTTP应用层只负责提供格式和组装格式。因此在BurpSuite上看似点了一次Send,发了一个数据包,其实传输层才是对接收到的应用层数据进行分块处理的,因为TCP协议负责数据的分组和组装。

正因为如此,分块传输才能绕waf,当然现在来看也只能是绕过包过滤类型的防火墙,因为这种防火墙检测的是TCP、UDP、ICMP等网络层、传输层的数据包内容,不像应用代理防护墙,检测的是应用层的数据包内容。

参考

HTTP协议之chunk编码(分块传输编码)

HTTP首部——分块传输和持久连接

Java反序列化数据绕WAF之延时分块传输 | 回忆飘如雪