freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

应用层WAF绕过的若干种方式
2022-04-07 11:28:46
所属地 广东省

一、引言

WAF (Web Application Firewall)即应用防火墙。主要是用于HTTP(S)协议的校验、拦截恶意(攻击)请求,放行正常的业务请求。WAF的类型分为三类:网络层、应用层、云WAF。

本次分享主要是研究应用层的WAF绕过,对于应用层的WAF是指WAF解析的是NGINX或者Apache处理过的HTTP数据包,也就是中间件初步处理后转发给WAF处理。要想绕过WAF的过滤,那么就得研究NGINX解析数据包与后端PHP或者其他语言解析的数据包有何不同。我们通过他们差异绕过这些WAF的过滤。

1649301946_624e59bae8ef10f2a6cc1.png!small?1649301947213

二、基本理论

2.1 form-data

multipart/form-data会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。

1649301952_624e59c0a7c5c59c9df7d.png!small?1649301953255

2.2 x-www- form-urlencoded

application/x-www-from-urlencoded,会将表单内的数据转换为键值对,&分隔。 当form的action为get时,浏览器用x-www-form-urlencoded的编码方式,将表单数据编码为 (name1=value1&name2=value2…),然后把这个字符串append到url后面,用?分隔,跳转 到这个新的url。

1649301961_624e59c95b74ba2085d51.png!small?1649301961658

实战绕过

文件上传绕过

我们以ngx_lua_waf源码来学习WAF是如何判断上传文件后缀。 waf.lua 45-49 line.

1649301967_624e59cf95cfce90a1eff.png!small?1649301967899

我们可以看到WAF是通过这么一个正则来匹配到文件后缀的,这个正则的缺陷在于如果我们在,Content-Disposition中引入垃圾数据,会导致正则匹配失败。 但是在PHP这种引入垃圾数据的 Content-Disposition是可以解析成功的。这也是单一型Bypass绕过的常见技巧。

1649301972_624e59d494c524a270540.png!small?1649301972866

双写boundary绕过

WAF为了降低误报率并不会上传文件的内容进行过滤,那么我们能不能让WAF以为我们是在上传文件但是实际我们传输的是普通的POST数据包呢?答案是可以的,这是我们Bypass思想的核心所在。

例如靶机:gqleung/bypass_waf_1,我们双写了boundary,但是WAF会认为boundary=a才是真正的消息,而boundary=b仅仅是boundary=a的内容,但是PHP会根据 Content-Type中的boundary来确定是哪个boundary消息的。这样在上传文件包不被检查的时候可以导致POST包的过滤可以被Bypass。例如下面的HTTP数据包,真实的数据包就是b从而绕过WAF的拦截。如图所示:


1649301981_624e59dddaa9fb160206a.png!small?16493019821301649301990_624e59e6a0b18ab2b196b.png!small?1649301991042

构造假boundary绕过

如果数据包中存在两个相同的boundary块头PHP则会以第一个boundary头为主,内容则以第二个boundary块为主。但是某些WAF会以第第二个为主,即便WAF所有boundary块都检查,如果第二个是上传包根据我们前面的前提(WAF为了降低业务误报率,不检查上传的内容)也可以绕过WAF的检查。我们再次以靶机:gqleung/bypass_waf_1靶机为例子构造如下数据包:


1649302014_624e59fe05a0f1f1a8526.png!small?16493020143921649302020_624e5a04848d4fc76f68d.png!small?1649302020854

Content-Disposition引号闭合绕过

我们看到下面的数据包,第一个Content-Disposition: form-data; name='fla; filename="exp.fw",我们在name中删掉了一个引号,这样的话再PHP中解析就会闭合到最后一个引号。但是在WAF中仍然以为是上传文件。当然用双引号也是可以的,但是闭合会闭合到下一个双引号。

1649302034_624e5a127c97435dde7f6.png!small?1649302034971

参数溢出绕过

我们使用的WAF是基于lua-nginx-module-0.10.9rc7 开发,该模块存在的问题是最大能够获取的参数数量是100个,也就是说该WAF最大的检查数量是100个参数,如果是101个参数那么地101个起不会检查直接放行。这就是所谓的最大参数溢出绕过。

1649302040_624e5a18f3d2c1f22fcb7.png!small?1649302041721

以靶机gqleung/bypass_waf_3 为例,我们如果直接读取/etc/passwd会直接被WAF拦截,如果前面加一百个参数就可以绕过。

1649302047_624e5a1f5ac052704e84a.png!small?1649302047969

skip_upload

在PHP中存在一个叫skip_upload的变量来控制是否是上传。下面看一段PHP源码(php- 5.3.3/main/rfc1867.c line 991)从代码我们可以得知,只需要c小于0即可使得skip_upload=1,也就是跳过上传。在前面几个分支我们可以知道只要参数中存在]就会使得c--。

1649302056_624e5a28217c8d6adce8a.png!small?1649302056373

根据上面的理论分析,我们只需要构造两个Content-Disposition,其中一个是上传的,在他name中加入]符号让上传被忽略,另外Content-Disposition是正常的POST参数,这样我们在通过WAF时候WAF会认为我们的是上传文件而非POST数据,但是PHP中却跳过了上传最终导致了WAF的检查被绕过。

1649302062_624e5a2eae0ae68e5f862.png!small?1649302063018

在PHP源码中 rfc1867.c line 909 可以看到如果skip_upload=1的情况有一种是Maximum number of allowable file uploads has been exceeded ,也就是上传的文档数量超过了最大允许范围就会跳过超过数量的上传。那么这个最大文档数量是多少呢?他是由php.ini中max_file_uploads决定的默认值就是20.也就是说我们的上传文档数量超过20就会被忽略。

1649302069_624e5a35cda521980c507.png!small?1649302070155

我们同样以靶机gqleung/bypass_waf_3为例根据前面的理论分析我们构造上传包如下,第二十个我们可以使用正常的POST就可以收到参数。

1649302074_624e5a3af2b9c55dbbbce.png!small?1649302075430


# waf绕过 # 应用层安全 # 应用层
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录