php语言中的addslashes()函数在指定的预定义字符前添加反斜杠,这些字符是单引号('),双引号("),反斜线(\)与NUL(NULL字符)。例如客户端提交的参数中如果含有单引号,双引号等这些特殊字符,addslashes函数则会在单引号前加反斜线“\”,将单引号转义成没有功能性的字符。
举个栗子:
以查询用户名为1’的信息为例,username中的参数为1',MySQL数据库在解析这条SQL语句时,会把1后面的单引号认为是闭合符号要求再输入一个单引号闭合,而不是当做username参数的一部分来处理,从而导致数据库只查询用户名为1的信息,而不是查询1'的信息。
在示例中数据库提示我们要求再输入一个单引号,然后输入分号“;”结束SQL语句,查询出来的结果为0,因为users表中确实没有用户名为1的信息。
如果想要把单引号作为username参数的一部分的话,可以使用反斜线对单引号进行转义,如下所示:
在单引号前面加一个反斜线后,数据库在解析SQL语句时就会将单引号作为一个普通字符对待,没有特殊含义,也不会把单引号识别为闭合方式,而是作为username参数中的一部分。
addslashes函数过滤的作用:当输入闭合符号'时把在'前加上反斜线\转义为普通字符,导致无法闭合。
在Less-23中源代码中输入?id=1\'进行测试:
发现后台仍然把我们输入的反斜线给转义过滤掉了,页面最终返回的是1\\\',第一个反斜线将第二个反斜线转义了,然后第三个反斜线把单引号给转义了。
分析Less-32源代码:
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;
}
从后台的过滤代码中可知,使用这种方式是不可能绕过的,当然addslashes()函数也会有局限性,一般我们会采取的方法:GBK字符编码和网页URL编码两种方式。
这里主要介绍GBK字符编码绕过:
GBK编码,是在GB2312-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准,支持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字——(摘自百度百科)。
字符反斜线“\” 的ASCII码值是5C,占用一个字节,GBK编码方式可以将反斜线“\”转换为一个服务器数据库不识别的汉字,即在5C前面拼接组合一个字符0xdf,那么数据库就会将0xdf5c转换为一个不识别的汉字,这样数据库就会将其忽略掉。
假设当前数据库使用的是GBK编码集,那么数据库会把两个字符识别为一个汉字,所以可以使用一些字符和经过转义后多出来的反斜线“\”组合成两个字符,从而变成数据库不识别的汉字字符,从而破坏对单引号,双引号的转义,使其参数闭合。
再举个栗子
假设当前数据库使用GBK编码集,数据库会将输入的参数%df%5c解析为两个字节:
其中%df为高位字节,编码位是223;%5c为低位字节,编码位是92;%df%5c的GBK编码取值范围就是:第一个字节是129—254,第二个字节是64—254,数据库会按照GBK编码将%df%5c解析成一个汉字,这样“\”就会失去原来的作用。
在上图中,数据库将参数%df%5c按照GBK编码集解析成上图中的汉字:運,这种方式就是宽字节注入。
宽字节注入有前提:要求目标MYSQL数据库的编码方式是GBK编码,并且客户端必须和数据库的编码方式一致,这样才能使用宽字节注入方式,宽字节注入过程如下所示:
输入参数:?id=1%df' and 1=1 --+,进行测试,结果如下
测试页面返回的结果是:1�\' and 1=1 --。
由于输入的参数中有单引号,后台使用了反斜线对单引号过滤,使得参数实际上替换成了1�\' and 1=1 --,并且数据库会将“�\”字符解析成一个汉字,也就是下图中红色部分,从而绕过WAF。
后台替换成的SQL语句是这样的:SELECT * FROM users WHERE id='1%df\' and 1=1 --+' LIMIT 0,1,并且该SQL语句可以正常执行:
总结:
宽字节注入有个前提:要求目标MYSQL数据库的编码方式是GBK编码,并且客户端必须和数据库的编码方式一致