WAF防护绕过技巧分析
一、WAF介绍与分类 (一)WAF简介 Web应用防护系统(Web Application Firewall,网站应用级入侵防御系统),是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的产品。 市场上的WAF产品有很多,像腾讯云,阿里云,长亭等,目前世界上常年排名第一的是以色列的 Imperva。 (二)WAF分类 规则实现 语义分析引擎WAF,国内大多数都是正则引擎,此外还有机器学习引擎。 部署方式 网络层WAF、应用层WAF、云WAF WAF部署方式 WAF大多是串联在这个链路中,起到一个阻断作用。就比如在Web Server和CGI之间的WAF,CGI这里特指PHP和ASP,像JSP一般就统一tomcat中间件了,就不需要CGI层了。 云部署一般先会起一个高防IP,然后用这个IP去连接WAF集群,一般来说都是从四层的流量解除七层的流量,然后再将正常的流量向后端转发,像这些企业A企业B可能在云上也可能不在。 二、网络层WAF Bypass (一)分包分组 通过调整MSS控制分包 控制MSS去调整TCP分包的大小 单个TCP会话可能含有多个HTTP会话:比如TCP先建立一个三次握手,建立之后发送多个HTTP请求,并没有断开,一般的设备都会去很好的解析处理,但是有一些古老的设备只会去解析第一个,现在已经很少了。 单个TCP包发送多组HTTP报文(Pipeline技巧以及HTTP请求走私):就是在DATA部分写多个http请求,有的设备就会认为第一个正常,那么后面的就类似于body部分,就会出现解析错误。 HTTP请求走私和Pipeline的区别就是请求走私利用不同的Content-Length引发歧义,比如下面这个,第一个content-length是包括了下面两个,或者content-length写一个1或者2,到底Web Server会取哪一个,需要针对不同的去研究,所以取值的解析差异,就会认为他是一整个或者是三个,利用这种方式就可以去迷惑WAF。 在标准的HTTP走私里面,一般content-length和Transfer-Encoding只会采纳一个,大部分优先是 Transfer-Encoding: chunked,当然也有一些两个都支持,就会出现一些问题。 chunked 利用chunked切分,比如下面是个最简单的chunked,对关键字进行一个拆分。 这里的5,4,3是以16进制写的,最后以0来结尾,如果是10个字符的话就要写A。 这种是只针对于网络层,应用层就不会出现这种问题,因为应用层是在完成chunked组包之后,才去解析,所以对应用层无效。 三、应用层WAF Bypass (一)multipart/form-data 理论知识 HTTP协议POST请求,除了常规的application/x-www-form-urlencoded以外,还有multipart/form-data这种形式,主要是为了解决上传文件场景下文件内容较大且内置字符不可控的问题。multipart/form-data格式也是可以传递POST参数的。对于Nginx+PHP的架构,Nginx实际上是不负责 解析multipart/form-data的body部分的,而是交由PHP来解析,因此WAF所获取的内容就很有可能与后端的PHP发生不一致。 使用以下脚本来进行测试 <?php echo file_get_contents("php://input"); var_dump($_POST); var_dump($_FILES); ?> 正常POST请求如下: change body encoding,如下: 只有input不太一样,一个有f=1一个没有,参数并没有进入Files数组,而是进入了_POST数据。那么,何时是上传文件?何时是POST参数呢?这个关键点在于有没有一个完整的filename=。这9个字符是经过反复测试的,缺一个字符不可,替换一个字符也不可,在其中添加一个字符更不可。 加上filename=之后: 可以看到这次并没有传给POST数组,而是传给了FILES数组变成了一个文件。 Bypass WAF的核心思想在于,一些WAF产品处于降低误报考虑,对用户上传文件的内容不做匹配,直接放行,比如一些压缩包图片之类的,在二进制流下面任意字符是不可控的,所以里面出现一些危险函数是很正常的。事实上,这些内容在绝大多数场景也无法引起攻击。所以让POST过去的数据去过那些规则,让FILES的只要符合白名单即可。 但关键问题在于,WAF能否准确有效识别出哪些内容是传给POST数组的,哪些传给_FILES数组?如果不能,那我们是否就可以想办法让WAF以为我们是在上传文件,而实际上却是在POST一个参数,这个参数可以是命令注入、SQL注入、SSRF等任意的一种攻击,这样就实现了通用WAF Bypass。 基础案例 0x00截断filename 截断之后发现传给了POST数组 有的WAF在处理包之前会将00删掉,再去解析会产生差异,所以有的地方00是不能删的,所以会产生bypass 双写上传描述行 双写后,一些WAF会取第二行,而实际PHP会获取第一行 双写整个part开头部分 可以看到取的还是第一行,只不过会将第二部分全部当成f的值,这里做SQL注入比较麻烦,需要将前面全都闭合掉,但是命令注入就很简单,直接将1给改成payload即可优先执行。 这里可以延伸出构造一个假的part 构造假的part 和上一个类似,少了一个换行,这样原本干扰的部分就不会取了 双写boundary 可以看到是以a为主 双写Content-Type 还是以a为主...