在绕过雷池waf之前,我们大概会尝试多种方法进行绕过,详细绕过思路和方法如下:
一、0x00截断绕过
在此环境中,我们使用php+nginx进行搭建,故我们在此环境下绕过,其他的环境可以自行搭建。所谓的0x00截断攻击,是与我们的底层有一定的关系,不论是何种语言,到达底层无非是C语言和C++,那么这个0x00在底层便是截断的含义,在C语言中0x00便是截断,故此0x00是骗过waf进行后端绕过,给你一个双传接口,那么怎么进行绕过呢?
waf在对文件上传检测的时候,检测的力度没有那么强,那么在传参抓包的过程中,我们对filename字段进行修改,在filename下加上0x00,waf会认为这是普通的上传,不会对0x00进行识别,但是我们传递到后端PHP的代码中,底层看到0x00符号,那么便认为这不是普上传包,而是普通请求包,原因0x00已经将filename进行截断,那么我们将会绕过waf,从而是我们可控的数据传到后端,完美的绕过,那么对于语义化的雷池是否成立呢?我们来进行尝试。使用的靶场是上篇删除不必要数据的sql注入靶场十一关,因为雷池之前把get的型的注入已经修复,想要从get传参来进行绕过,可能性很小。
下面我们进行绕过,绕过之前检查一下环境。登录正常如下图1-1所示

图1-1(正常登录图)
正常登录如上图所示,尝试进行传注入参数,雷池是否拦截,如下图1-2,1-3所示:

图1-2(参数含有出入特征图)

图1-3(雷池拦截图)
下面我们就来进行抓包更改报的数据类型,通过waf对上传文件的参数限制没有那么死的情况下,使用上传数据包和0x00进行截断,从而来查看是否能够成功绕过雷池waf。对filename进行0x00截断,发现并未绕过雷池,如下图1-4所示:

图1-4(0x00雷池蓝截图)
第一种0x00绕过失败,下面我们进行修改请求包,进行第二种方法绕过。
二、双写描述行绕过
尝试使用双写描述行是否绕过,双写能够绕过的原理是HTTP解析不一致,在此环境下,这是因为在PHP+Nginx的环境下,PHP取第一个的原因是,在apache/nginx中间件传递给PHP时,Apache的ac_headers默认保留第一个,在Nginx环境下,fastcgi_param映射到$_server时也是取得第一个,故不论在何种环境下,在双写描述行的情况下,都是取第一条记录,那么在假如waf在不完全扫描请求包中的数据,我们双写的数据就会到达后端,那么我们就能绕过。
那么问题又来了,是所有的后端都是在取第一个嘛?其实大多数都是这样的,只有极少数的情况下,后端是在取后面一个,如下表所示。
| 后端/语言 | 行为 | 说明 |
|---|---|---|
| PHP | 取第一个 | Apache/Nginx 直接传递第一个值到 $_SERVER |
| Java (Servlet) | 取第一个 | 官方文档明确:getHeader() 返回第一个头 |
| Python (Flask) | 取第一个 | Werkzeug 的 request.headers 用 MultiDict,取第一个 |
| Node.js (Express) | 取第一个 | req.get() 返回第一个 |
| Ruby (Rails) | 取第一个 | request.headers[name] 取第一个 |
| Go | 取第一个 | Header.Get() 返回 Map 中的第一个 |
那么数据真的能到后端嘛?这就和waf的部署有关系,有的waf会全部扫请求包,只要一发现恶意数据,直接返回403,但是有的不会,这样我们数据就可以到达后端,后端取到。下面我们进行双写进行绕过,发现成功,如下图1-5所示:

图1-5(双写描述行绕过成功图)
三、构造假的part部分2进行绕过
我们在第二种数据包的进行构造假的part部分,使得waf在能拿到数据像拆快递一样,我们在构造的时候的大概思路是这样,当waf扫描的第一个零件的时候,发现name="uname"后面啥数据没有,则判断安全,当waf扫描第二个零件时,waf看到name="uname"后面跟着filename="1.png",雷池会误认为这是文件上传,那么我们的数据就回到后端,PHP的后端节快递的时候,看到第一个没有filename,于是把这个uname塞进了$_POST['uname'],但是$_POST['uname']是空的,当到达filename的时候,他会认定这是个文件,他会把我们的payload生成一个临时文件,让后会读取我们文件夹中的内容,之后全部拼接到sql语句中进行查询,那么这样我们完美绕过,拿到数据。如下图1-6所示:

图1-6(构造假的part绕过成功图)
以上是的一些思路,后续还会更新雷池waf的绕过思路和手法。