2019/2/18 11:32
前言
由于开发gbk编码并没有考虑到一些安全隐患,常常一些web的cms的gbk编码版本会在数据库中要求以GBK编码数据,并带来比较严重的SQL宽字节注入的隐患。
漏洞银行第三期的PPT原文
宽字节注入源于程序员设置MYSQL连接时错误配置为:
set character_set_client = gbk
这样配置会引发编码转换从而导致的注入漏洞。
具体原理如下:
①正常情况下当GPC开启或使用addslashes函数过滤GET或POST提交的参数时,黑客使用的单引号 ' 就会被转义为: \' (转义斜杠\和单引号')
②但如果存在宽字节注入,我们输入%df%27时首先经过上面提到的单引号转义变成了%df%5c%27(%5c时反斜杠\),之后在数据库查询前由于使用了GBK多字节编码,即在汉字编码范围内两个字节会被编码为一个汉字。然后MYSQL服务器会对查询语句进行GBK编码即%df%5c%转换成为汉字'运(繁体的)',而单引号逃逸了出来,从而造成注入漏洞。
大家需要注意的是,php在小于等于5.3.0版本的时候默认开启全局魔术引号(gpc),从5.4版本开始php废除全局魔术引号,人们则为了防止攻击者进行SQL注入而使用addslashes()函数来达到gpc的一个效果。
也就是说,当你输入http://xxx.com/x.php?title=1'这个url时,你输入的单引号会被php默认添加转译斜杠。
当遇到字符型文本的查询接口,会绕不开原本sql语句的单引号而无法实现注入。
语句执行过程
1.比如本来进入MYSQK执行的SQL语句为:
select * from news where title = ''
2.被php的gpc后为:
select * from news where title = '1\'' (这里查询的是 1\' ,url编码为1%5c%23)(%5c是斜杠,%23是单引号)
3.MYSQL实际查询语句:
select * from news where title = '1\''(大家要注意这是实际进入MYSQL的SQL语句)
要注意数据库没有gbk编码的话,php讲查询语句经过gpc(全局魔术引号)或 addslashes()函数处理的话,php处理过的语句就是MYSQL执行的语句。
其查找的内容为 1' (就是说你自己输入的单引号被添加转义符而成为了单引号实体) ,而数据库本来就没有 1' 这个内容。注入点自然而然是失效的。
但是,如果数据库本身被GBK编码,如在MYSQL中设置"set character_set_client = gbk",则会导致由于编码问题,SQL语句实际执行时吸收php程序带来的转义符号,使攻击者绕过php自身的gpc防护而直接进行注入。
如%df%5c,或者写成%df\(%df这个字节 和 转义斜杠 \),这个编码是 繁体的 '运' 字(%5c是转义斜杠的URL编码)。
则假设目前数据库是GBK编码。
上一段带来的案例:输入http://xxx.com/x.php?title=1'
被gpc后
MYSQL执行的语句为select * from news where title = '1\'',报错(错误原因在上文说过了)
语句执行过程
1.输入:
http://xx/com/x.php?title = %df%27(%27是单引号'的URL编码)
2.gpc后:
select * from news where title = '%df\''
3.MYSQL执行的语句为:
select * from news where title = '运'' ,报错
MYSQL执行的语句为select * from news where title = '运'',报错,即你输入的%df和gpc处理的转移斜杠在GBK编码的数据库中合并为一个字符,而你输入的引号会引起数据库的引号不闭合的语法报错。
上面这一句话至关重要,因为转义斜杠被吸收,从而有了注入单引号的可能。
原本的查询语句为:select * from news where title = ''
我们可以使用自己的单引号闭合前面的单引号,再注释掉后面的单引号,而中间我们可以插入自己想进行的语句。
语句执行过程
1.如union型查询语句的payload为:
.php?title = 1 %df%27 union select 1,user(),concat(name,pass) from admin %23
(%23 为 注释符号 #,注释掉后面的引号来使语句没有语法错误)
2.gpc处理后为:
select * from news where title ='1%df\' union select 1,user(),concat(name,'~',pass) from admin #'
3.MYSQL执行的语句:
select * from news where title ='1运' union select 1,user(),concat(name,'~',pass) from admin #'
此时union前面查不到 1运 这个内容,所以只会返回union后面能查的见的内容给我们。
注意,上面这一句可是语法正确的。加 # 是为了注释原本SQL语句的后面的单引号,消除语法错误。
哈哈哈,现在成功利用GBK编码绕开了后台SQL语句本身的两个引号,从而实现我们进行联合查询的可能。
所以,建站系统一般不要选择gbk编码的cms,因为这类cms通常会要求你的数据库也是gbk编码导致存在SQL注入隐患。
另外注意一点,gbk编码是存在数据库的编码才会引发SQL注入隐患,而php环境以及前端是gbk编码可是和SQL注入没有关系的!总之,只要数据库不是gbk编码,就不会存在宽字节注入了。
领取专属 10元无门槛券
私享最新 技术干货