BlueCMS v1.6 sp1 /admin/login.php SQL注入漏洞分析
略读代码:
开头包含了文件
require_once(dirname(__FILE__) . '/include/common.inc.php');
该文件中,全局数据转义
if(!get_magic_quotes_gpc())//如果没有开启
{
$_POST = deep_addslashes($_POST);
$_GET = deep_addslashes($_GET);
$_COOKIES = deep_addslashes($_COOKIES);
$_REQUEST = deep_addslashes($_REQUEST);
} //加上斜杠转义
输入了双引号,会被转义掉,那么此处就没办法简单地引入引号去控制Sql语句了。
转换思路:
这个时候发现自己没有思路了,只会单引号双引号。。。渣-c-
参考一下:【Code Review】bluecms v1.6 Sql Injection 分析
可以发现对数据的注入,进行了加斜杠转义的操作。那么接下来找注入思路主要有以下3点:
- 找整数型注入
- 整套cms默认gb2312编码,容易造成宽字节注入
- http头并不在转义的范围内,所以类似存入ip,reffer的位置也能发生注入
尝试宽字节注入:
- 抓包修改
admin_name=%df%27+or+1%3D1%23
- 明文就是
%df' or 1=1#
- 单引号被转义后变成
%df\' or 1=1#
- 宽字节注入是利用mysql的一个特性,因为gbk是多字节编码,他认为两个字节代表一个汉字,所以
%df
和后面的\
也就是%5c
变成了一个汉字“運”,而单引号逃逸了出来,就可以成功闭合sql语句了 - 再加上后面的
or 1=1 #
就构造成了永真语句,可以成功免密登录管理员后台了
理解宽字节:
- 本质是如何绕过addslashes函数:
- addslashes函数产生的效果就是,让
’
变成\’
,让引号变得不再是“单引号” 一般绕过方式就是,想办法处理
\’
前面的\
- 想办法给\前面再加一个\(或单数个即可),变成
\\’
,这样\
被转义了,’
逃出了限制 - 想办法把
\
弄没有。
- 想办法给\前面再加一个\(或单数个即可),变成
mysql怎么判断一个字符是不是汉字?
- 根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用
%df
,用%a1
也可以
- 根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用
gb2312和gbk的区别?
- gb2312编码的取值范围。它的高位范围是
0xA1~0xF7
,低位范围是0xA1~0xFE
,而\
是0x5c
,是不在低位范围中的。 0x5c
根本不是gb2312中的编码,所以自然也是不会被吃掉的。
- gb2312编码的取值范围。它的高位范围是
修复方案1:
- 先调用mysql_set_charset函数设置连接所使用的字符集为gbk
再调用mysql_real_escape_string来过滤用户输入。
这个方式是可行的,但有部分老的cms,在多处使用addslashes来过滤字符串,我们不可能去一个一个把addslashes都修改成mysql_real_escape_string。
所以有修复方案2:
- 将character_set_client设置为binary(二进制)。
- 只需在所有sql语句前指定一下连接的形式是二进制:
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $conn);
- 所有数据以二进制的形式传递,就能有效避免宽字符注入。
编写pocsuite插件:
requests不进行urldecode:
参考:如何在requests post时不做urlencode
There are many times that you want to send data that is not form-encoded. If you pass in a string instead of a dict , that data will be posted directly.
所以,只要直接传一个string作为payload数据,requests就不会做任何转换,直接发出去。
并且加上headers = {"Content-Type": "application/x-www-form-urlencoded"}
验证:
总结:
- 阅读源码的时候,先看看全局过滤
- gb2312、gbk编码的话,考虑宽字节注入
- 宽字节注入的原理是 gbk是多字节编码,他认为两个字节代表一个汉字,所以可以用
%df
和后面的\
也就是%5c
变成了一个汉字“運”,而单引号逃逸了出来