0x00 WAF分类

嵌入型

网站内置的WAF,直接将其镶嵌在代码中。

非嵌入型

分为硬件型WAF、软件型WAF和云WAF。

硬件WAF:以硬件形式部署在链路中,支持多种部署方式,串联可以拦截恶意流量,旁路监听时,只是记录攻击不拦截。比如绿盟、安恒、启明等厂商。

软件型WAF:以软件形式安装在服务器上,可以直接检测服务器是否存在Webshell、是否有文件被创建等。比如云锁、云盾、安全狗。

云WAF:一般以反向代理的形式工作,通过配置NS或CNAME记录,使得对网站的请求报文优先经过WAF主机,经过WAF主机过滤后,将被认为无害的请求报文发送给实际网站服务器进行请求(可以认为是自带防护功能的CDN)。如:阿里云WAF。

0x01 WAF指纹识别及探测

手动测试

在域名后面加入一个不存在的id参数+很明显的sql语句,这样一般WAF都可以识别到,在响应页面一般可以看到WAF的明显字/LOGO标识。

部分WAF也可以通过特定响应识别:

dotDefender用来防护.net的程序,会对恶意请求返回“dotDefender Blocked Your Request”的信息。

WebKnight是用来设计在IlS下面使用的WAF设备,较为常见。WebKnight会对恶意的请求返回“999 No Hacking”的信息。

自动测试

利用sqlmap检测目标是否存在WAF:

sqlmap --batch --identify --random-agent -u "http://www test.com"

wafw00f 检测插件(kali自带)

wafw00f 网站

0x02 BypassWAF

架构层绕过

当前多数云WAF架构,例如百度云加速、阿里云等等,都是通过更改DNS解析,把流量引入WAF集群,流量经过检测后转发请求到源站。

真实IP:如果获取到源站的真实IP的话,那它就不会通过DNS解析到WAF集群,会直接访问网站绕过WAF。

找寻真实IP:

  • 网站页面注销是否包含源站IP
  • GITHUB源代码泄露是否包含源站IP
  • 未接入WAF前,真实IP地址是否有历史解析记录
  • 旁站、C段、查看邮件源代码
  • 最后也可以通过穷举法,当然,费时间成功率低

同网段:攻击IP和目标IP在同一个网段中,它不会经过WAF。

SSRF漏洞:如果未能发现源站IP,可以尝试寻找子站的SSRF漏洞。如果子站访问目标站不经过WAF集群,可以利用SSRF漏洞来绕过WAF。

资源限制绕过:如果HTTP请求POSTBODY太大,检测所有的内容,WAF集群消耗太大的CPU、内存资源。因此许多WAF只检测前面的几K字节、1M、或2M。因此对于攻击者来说只需要在POSTBODY前面添加许多无用数据,把攻击payload放在最后即可绕过WAF检测。

协议层绕过

即使流量都确保经过WAF,如果WAF的防御策略根本就没有检测payload,那么也就能绕过WAF。协议层面绕过WAF,利用WAF解析协议的问题,使得payload被认为不是请求的HTTP请求的内容。

HTTP请求走私

在HTTP1.0之前的协议设计中,客户端每进行一次HTTP请求,就需要同服务器建立一个TCP链接。在HTTP1.1中,增加了Keep-Alive和pipeline这两个特性。

开启HTTP Keep-Alive之后,能复用已有的TCP链接,当前一个请求已经响应完毕,服务器端没有立即关闭TCP链接,而是等待一段时间接收浏览器端可能发送过来的第二个请求,通常浏览器在第一个请求返回之后会立即发送第二个请求,如果某一时刻只能有一个链接,同一个TCP链接处理的请求越多,开启KeepAlive能节省的TCP建立和关闭的消耗就越多。

当然通常会启用多个链接去从服务器上请求资源,但是开启了Keep-Alive之后,仍然能加快资源的加载速度。HTTP/1.1之后默认开启Keep-Alive, 在HTTP的头域中增加Connection选项。当设置为Connection:keep-alive表示开启,设置为Connection:close表示关闭。实际上HTTP的KeepAlive写法是Keep-Alive,跟TCP的KeepAlive写法上也有不同。所以TCP KeepAlive和HTTP的Keep-Alive不是同一回事情。

HTTP管线化(英语:HTTP pipelining)是将多个HTTP请求(request)整批提交的技术,而在发送过程中不需先等待服务器的回应。

请求结果管线化使得 HTML 网页加载时间动态提升,特别是在具体有高延迟的连接环境下。服务端要遵循 HTTP/1.1 协议,必须按照客户端发送的请求顺序来回复请求,这样整个连接还是先进先出的,

使用pipeline与不使用的对比:

向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代埋服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。

如图,攻击者使用前段请求的一部分被后端服务器解释为下一个请求的开始。它实际上是下一个请求之前,因此会干扰应用程序处理该请求的方式。

如何执行HTTP请求走私?最重要的是长度(Content-Length标头和Transfer-Encoding表头):

  • CL.TE:前端服务器使用Content-Length头,而后端服务器使用Transfer-Encoding头。
  • TE.CL:前端服务器使用Transfer-Encoding头,而后端服务器使用Content-Length头。
  • TE.TE:前端服务器和后端服务器均支持Transfer-Encoding标头,但是可以通过某种方式混淆标头来诱导其中一台服务器不对其进行处理。

当设置Transfer-Encoding:chunked后,请求主体按一系列块的形式发送,也就是分块,并将省略Content-Length。

在每个块的开头需要用十六进制数说明当前块的长度,数值后接\r\n(占2字节),然后是块的内容,再接\r\n表示此块结束。最后用长度为0的块表示终止块。终止块后一般跟空行。

一个标准的走私分块包格式如下:

POST/HTTP/1.1
Host:www-webtest.com
Content-Length:3
Transfer-Encoding:chunked

8;我是注释
SMUGGLED
12;我是注释
Love you too
0
空行

几乎所有可识别Transfer-Encoding数据包的WAF,都没有处理分块数据包中长度标识处的注释。

分块传输绕过burp插件:

https://github.com/c0ny1/chunked-coding-converter

绕过WAF文件上传的几个姿势

  • 文件覆盖绕过:把单个文件上传请求复制一份,变成双文件请求。第一个请求是正常的jpg请求,第二个改为真正的payload请求,waf可能只会识别前面的请求。
  • 去掉引号:filename=”shell.php”改为filename= shell.php
  • 增加等号:filename=”shell.php”改为filename===”shell.php”

规则层绕过

目前市面上的大多数的WAF都会基于规则。即WAF对接受数据收到的包进行正则匹配过滤,如果正则匹配到与现有漏洞规则库的攻击代码相同,则认为是恶意代码,从而进行阻断。

解析HTTP请求→匹配规则库→防御动作→记录日志

mysql注入绕过的一些小tips:

可利用其它控制字符替换空格:%09,%0a,%0b,%0c,%0d,%20,%a0
可利用注释符号:/**/、#test%0d%0a、--+a
可利用数学运算以及数据类型:news_id=1.1,news_id=1E0,news_id=\N
可利用括号:union(select 1,2)
还可以利用/!12345xxx/绕过,通过10000~99999之间的数字FUZZ测试可以绕过的数字通过burp遍历,得出可以绕过的值