前言
提前声明,本文内容虽然主要针对的是 SQL WAF 的绕过演示,但由于是基于在 HTTP 协议层面绕过 Waf,因此所述技巧具有较高的通用性,所以理论上可以用于平时渗透时的方方面面,比如命令执行,代码注入,SQL注入等测试。
关于 Bypass WAF 先前已经写过两篇相关的文章可结合阅读:
- WAF绕过技术基础:渗透测试-浅析WAF绕过;
- WAF绕过进阶HPP:Bypass WAF-HTTP参数污染漏洞挖掘。
本文将介绍基于 HTTP 协议特性进行 SQL 注入过程的 WAF 绕过,主要包含以下几种技巧:
- pipline 隧道传输绕过;
- chunked 分块传输绕过;
- Content-Type 协议未覆盖绕过;
- 协议未覆盖+分块传输组合拳绕过;
- 分块传输使用注释混淆对抗WAF检测;
- 协议未覆盖绕过进阶——fliename 混淆伪装绕过。
以上技巧的本质原理都是给服务器发送经过基于 HTTP 协议特殊处理后的 Payload 数据包,使得 WAF 无法识别出带有脏数据的 Payload,但 Apache、Tomcat 等 Web 容器和 Mysql、Sqlserver 等数据库能正常解析其内容,如下图所示:
在此强烈推荐读者可学习下 B 站漏洞银行平台 1337G 大佬的一起分享视频(2倍播放速度食用更香):漏洞银行丨一般人我不告诉的WAF绕过新姿势-1337G丨咖面74期。
WAF绕过
WAF演示环境
本机 Win10、Xampp、某狗Web应用防火墙最新版。
1、为方便演示,存在 sql 注入的脚本中使用$_REQUEST["id"]
来接收 get 或者 post 提交的数据。WAF 配置为拦截 url 和 post 的 and or
注入,如图所示:
2、部署完WAF后,发送 get 请求或利用 hackbar 插件发送 post 请求时,含有脏数据的 payload 将被拦截,如图所示:
隧道传输绕过
【原理】HTTP 协议是由 TCP 协议封装而来,当浏览器发起一个 HTTP 请求时,浏览器先和服务器建立起连接 TCP 连接,然后发送 HTTP 数据包(即我们用burpsuite 截获的数据),其中包含了一个 Connection
字段,一般值为 close
,Apache 等 WEB 容器根据这个字段决定是保持该 TCP 连接或是断开。当发送的内容太大,超过一个 HTTP 包容量,需要分多次发送时,值会变成 keep-alive
,即本次发起的 HTTP 请求所建立的 TCP 连接不断开,直到所发送内容结束 Connection 为 close 为止。
1、在使用隧道传输之前,需要关闭 burp 中 Repeater 模块的 Content-Length 自动更新,如图所示,点击取消勾选 Repeater 下拉选项中的 update Content-Length
功能(这一步至关重要):
2、burp 通过 post 请求提 id=1 and 1=1
,显示被 WAF 拦截,如图所示:
3、利用隧道传输,同时发送两个数据包,将两个数据包提交的内容依次设置为id=1
和id=1 and 1=1
,再将数据包的 Content-Length 的值依次设置为其字符长度即 4 和 12,最后将Connection 字段值设为 keep-alive
。提交后如图所示,会返回两个响应包,分别对应两个请求:
【小结】
- 从结果上看,两个数据包都能到达服务器,第一个正常数据包返回了正确内容,第二个包含有效载荷的数据包被某狗 WAF 拦截(此处无法绕过),但是在面对其他 WAF 时有可能可以绕过。
- 无论如何这仍是一种可学习了解的绕过方法,且可以和接下来的方法进行组合使用绕过。
分块传输绕过
【原理】如果在 HTTP 头部加入 Transfer-Encoding: chunked
之后,就代表这个报文采用了分块编码。这时,post 请求报文中的数据部分需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的,也不包括分块数据结尾的,且最后需要用0
独占一行表示结束(同时末尾需要以两个换行结束)。
1、首先开启上个实验中已关闭的 content-length
自动更新。给 post 请求包加入Transfer-Encoding: chunked
请求头后,将数据部分id=1 and 1=1
进行分块传输,成功绕过 WAF,如图所示:
2、进一步将上图数据包的id=1 and 1=1
改为id=1 and 1=2
,分块传输发送 payload,服务器没有返回数据,说明 payload 生效:
【小结】分块传输绕过需要注意以下几点:
- 分块编码传输需要将关键字
and,or,select ,union
等关键字拆开编码,不然仍然会被waf拦截。 - 编码过程中长度需包括空格的长度。
- 最后用0表示编码结束,并在0后空两行表示数据包结束,不然点击提交按钮后会看到一直处于waiting状态。
协议未覆盖绕过
【原理】HTTP头里的Content-Type
请求头一般有application/x-www-form-urlencoded,multipart/form-data,text/plain
三种,其中multipart/form-data
表示数据被编码为一条消息,页上的每个控件对应消息中的一个部分。当 WAF 没有规则匹配该协议传输的数据时则可被绕过。
1、首先将 HTTP 请求头部Content-Type
改为multipart/form-data; boundary=69
,然后设置分割符内的Content-Disposition
的 name
为要传参数的名称,数据部分则放在分割结束符上一行:
由于是正常数据提交,所以从图中可知数据是能被 Apache 容器正确解析的,但尝试提交1 and 1=1
也会被某狗 WAF 拦截,但如果其他 WAF 没有规则拦截这种方式提交的数据包,那么同样能绕过。
【注意】实际上,上述将 POST 请求中传递的数据由
application/x-www-form-urlencoded
格式转换为文件上传包格式multipart/form-data
时,BurpSuite 已提供右键选择change body encoding
一键转换的功能,无需手动转换。
2、一般绕 WAF 往往需要多种方式结合使用,在上图所示实例中只需将数据部分1 and 1=1
用一个小数点”.”
当作连接符即1.and 1=1
就可以起到绕过作用。当然这只是用小数点当连接符所起的作用而已,如下图所示:
组合拳方式绕过
下面进一步尝试使用 分块编码+协议未覆盖组合绕过。
1、在协议未覆盖的数据包请求头中加入Transfer-Encoding: chunked
,然后将数据部分全部进行分块编码,同样可以过 WAF,如图所示(数据部分为1 and 1=1
):
2、上面的数据包需要注意标红圈出来的部分:第2、3、7、8块。
第2块,即格式声明部分,需满足:
长度值 空行 Content-Disposition: name="id" 空行
这种形式,且长度值要将两个空行的长度计算在内(空行长度为2)。
第3块,即数据开始部分,需满足:
长度值 空行 数据
这种形式,且需将空行计算在内。
第7块,即分割边界结束部分,需满足:
长度值 空行 分割结束符 空行
这种形式,且计算空行长度在内。
第8块,即传输数据的末尾部分,需满足
0 空行 空行
这种形式。如果不同时满足这四块的形式要求,payload将不会生效。
分块传输的混淆
一些比较好的 WAF(如Imperva,360等),已经对传输编码的分块传输做了处理,可以把分块组合成完整的 HTTP 数据包,这时直接使用常规的分块传输方法尝试绕过的话,会被 WAF 直接识别并阻断。
但是几乎所有可以识别传输编码数据包的 WAF,都没有处理分块数据包中长度标识处的注释,导致在分块数据包中加入注释的话,WAF 就识别不出这个数据包了。
1、我们先在使用了 Imperva 的应用防火墙的网站测试常规的分块传输数据包,将被 WAF 拦截:
2、接着我们在分块传输数据包中长度标识处的注释加入注释符,发现可以成功绕过 WAF:
Filename混淆绕过
以上环境并未演示到另外一种基于 HTTP 协议特性绕过 WAF 的方法(实际上是基于 “协议未覆盖绕过” 方法,属于它的升级改造版)—— filename 文件名混淆绕过。下面直接看漏洞银行大佬在视频中的实战利用演示。
1、大佬在视频中演示的已部署 WAF 的网站为:
2、直接传入带有脏数据的 payload,将被拦截:
3、先顺便演示下隧道传输成功绕过 WAF:
4、同时分块传输也可以绕过 WAF:
最后步入正题,使用 filename 文件名混淆绕过的方法。
5、首先将原始的带有脏数据的 payload 转换成文件上传包格式的协议:multipart/form-data
,如下图所示:
自动转换结果如下:
6、删除掉转换后末尾的空行,直接尝试发送 payload,发现被拦截了:
7、接着我们在 name="a”
后面添加 filename="123.jpg”
,将 Payload 伪装成图片的格式进行发送,发现 WAF 不拦截,但是此时 Payload 也会因为被当作图片而不被解析:
8、为了让 Payload 能够顺利解析,可以在 fliename="123.jpg"
的等号前面添加空格,让 fliename 文件名无法解析,从而使得 payload 即参数 a=1 union select……
可被服务器解析执行,最终达到绕过 WAF 同时执行 pqyload 注入的目的:
9、另外此处也可以在 filename 前方添加双引号,也可以实现上述执行 payload 的目的:
以上就是利用 filename 混淆绕过 WAF 的方法,也是成功率极高的一种绕过方式,它属于 “协议未覆盖绕过” 的一种演变和提升。
总结
- GIthub上提供了一款 BurpSuite 插件可帮助我们快速将数据包进行分块编码,地址为:Chunked coding converter v0.2.1。
- 以上是在 HTTP 协议层面绕过 WAF,因为比较通用,所以理论上可以用于平时渗透时的方方面面,如命令执行,代码注入,SQL注入等测试。
- 虽然以上演示环境(不含最后 filename 混淆绕过部分)中只有分块编码真正做到了绕过某狗,但其他两种方法在其他 WAF 绕过中可能仍然可用,而且可与其他绕过方法结合使用。