CVE漏洞中文网

0DayBank一个专门收集整理全球互联网漏洞的公开发布网站
  1. 首页
  2. 百科
  3. 正文

Sql 约束

2017年5月23日 766点热度 0人点赞 0条评论

Sql 约束

  • 首页
  • 分类阅读
  • 文库
  • 专栏
  • 公开课
  • 商城
  • 漏洞盒子
注册 | 登录
投稿

基于约束的SQL攻击

鸢尾2017-01-06共336686人围观 ,发现 29 个不明物体WEB安全

前言

值得庆幸的是如今开发者在构建网站时,已经开始注重安全问题了。绝大部分开发者都意识到SQL注入漏洞的存在,在本文我想与读者共同去探讨另一种与SQL数据库相关的漏洞,其危害与SQL注入不相上下,但却不太常见。接下来,我将为读者详细展示这种攻击手法,以及相应的防御策略。

注意:本文不是讲述SQL注入攻击

背景介绍

最近,我遇到了一个有趣的代码片段,开发者尝试各种方法来确保数据库的安全访问。当新用户尝试注册时,将运行以下代码:

<?php
// Checking whether a user with the same username exists
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT *
          FROM users
          WHERE username='$username'";
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) > 0) {
    // User exists, exit gracefully
    .
    .
  }
  else {
    // If not, only then insert a new entry
    $query = "INSERT INTO users(username, password)
              VALUES ('$username','$password')";
    .
    .
  }
}

使用以下代码验证登录信息:

<?php
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT username FROM users
          WHERE username='$username'
              AND password='$password' ";
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) > 0){
      $row = mysql_fetch_assoc($res);
      return $row['username'];
  }
}
return Null;

安全考虑:

  • 过滤用户输入参数了吗? — 完成检查
  • 使用单引号(’)来增加安全性了吗? — 完成检查

按理说应该不会出错了啊?

然而,攻击者依然能够以任意用户身份进行登录!

攻击手法

在谈论这种攻击手法之前,首先我们需要了解几个关键知识点。

  1. 在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”,对于绝大多数情况来说都是成立的(诸如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。
    SELECT * FROM users WHERE username='vampire     ';
    

    但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在“字符串比较”期间进行的。这是因为,SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。

  2. 在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“vampire”时,实际上只能插入字符串的前5个字符,即“vampi”。

现在,让我们建立一个测试数据库来演示具体攻击过程。

vampire@linux:~$ mysql -u root -p
mysql> CREATE DATABASE testing;
Query OK, 1 row affected (0.03 sec)
mysql> USE testing;
Database changed

接着创建一个数据表users,其包含username和password列,并且字段的最大长度限制为25个字符。然后,我将向username字段插入“vampire”,向password字段插入“my_password”。

mysql> CREATE TABLE users (
    ->   username varchar(25),
    ->   password varchar(25)
    -> );
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO users
    -> VALUES('vampire', 'my_password');
Query OK, 1 row affected (0.11 sec)
mysql> SELECT * FROM users;
+----------+-------------+
| username | password    |
+----------+-------------+
| vampire  | my_password |
+----------+-------------+
1 row in set (0.00 sec)

为了展示尾部空白字符的修剪情况,我们可以键入下列命令:

mysql> SELECT * FROM users
    -> WHERE username='vampire       ';
+----------+-------------+
| username | password    |
+----------+-------------+
| vampire  | my_password |
+----------+-------------+
1 row in set (0.00 sec)

现在我们假设一个存在漏洞的网站使用了前面提到的PHP代码来处理用户的注册及登录过程。为了侵入任意用户的帐户(在本例中为“vampire”),只需要使用用户名“vampire[许多空白符]1”和一个随机密码进行注册即可。对于选择的用户名,前25个字符应该只包含vampire和空白字符,这样做将有助于绕过检查特定用户名是否已存在的查询。

mysql> SELECT * FROM users
    -> WHERE username='vampire                   1';
Empty set (0.00 sec)

需要注意的是,在执行SELECT查询语句时,SQL是不会将字符串缩短为25个字符的。因此,这里将使用完整的字符串进行搜索,所以不会找到匹配的结果。接下来,当执行INSERT查询语句时,它只会插入前25个字符。

mysql>   INSERT INTO users(username, password)
    -> VALUES ('vampire                   1', 'random_pass');
Query OK, 1 row affected, 1 warning (0.05 sec)
mysql> SELECT * FROM users
    -> WHERE username='vampire';
+---------------------------+-------------+
| username                  | password    |
+---------------------------+-------------+
| vampire                   | my_password |
| vampire                   | random_pass |
+---------------------------+-------------+
2 rows in set (0.00 sec)

很好,现在我们检索“vampire”的,将返回两个独立用户。注意,第二个用户名实际上是“vampire”加上尾部的18个空格。现在,如果使用用户名“vampire”和密码“random_pass”登录的话,则所有搜索该用户名的SELECT查询都将返回第一个数据记录,也就是原始的数据记录。这样的话,攻击者就能够以原始用户身份登录。这个攻击已经在MySQL和SQLite上成功通过测试。我相信在其他情况下依旧适用。

防御手段

毫无疑问,在进行软件开发时,需要对此类安全漏洞引起注意。我们可采取以下几项措施进行防御:

  1. 将要求或者预期具有唯一性的那些列加上UNIQUE约束。实际上这是一个涉及软件开发的重要规则,即使你的代码有维持其完整性的功能,也应该恰当的定义数据。由于’username’列具有UNIQUE约束,所以不能插入另一条记录。将会检测到两个相同的字符串,并且INSERT查询将失败。
  2. 最好使用’id’作为数据库表的主键。并且数据应该通过程序中的id进行跟踪
  3. 为了更加安全,还可以用手动调整输入参数的限制长度(依照数据库设置)

*参考来源:dhavalkapil,FB小编鸢尾编译,转载请注明来自FreeBuf(FreeBuf.COM)

鸢尾

鸢尾169 篇文章等级: 8级
|
|
  • 上一篇:滥用Edge浏览器的“恶意站点警告”特性,实现地址栏欺骗
  • 下一篇:如何找到SQL注入中的盐

这些评论亮了

  • hewei1994(1级)回复
    新姿势get :idea:
    )10(亮了
  • 我就看看回复
    不行哦
    [SQL]insert into user (username) values ('13486192782 1');
    [Err] 1406 - Data too long for column 'userName' at row 1
    mysql 版本 5.6.27
    )10(亮了
  • X_man(1级)有些梦虽然遥不可及,但不是不可以实现,只要我足够的强。回复
    这个技巧不是早就有了么
    )7(亮了

发表评论

已有 29 条评论

  • hewei1994 (1级) 2017-01-06回复1楼

    新姿势get :idea:

    亮了(10)
  • 我就看看 2017-01-06回复2楼

    不行哦
    [SQL]insert into user (username) values (’13486192782 1′);
    [Err] 1406 – Data too long for column ‘userName’ at row 1

    mysql 版本 5.6.27

    亮了(10)
    • houjingyi (2级) 2017-01-06回复

      @ 我就看看 set @@sql_mode=ANSI;设置成宽松模式即可

      亮了(1)
  • 001 2017-01-06回复3楼

    厉害了,word哥

    亮了(2)
  • yichin 2017-01-06回复4楼

    猥琐

    亮了(1)
  • just test 2017-01-06回复5楼

    你好,请问你使用的是什么版本的数据库,我在Mysql 5.7.13中按照你说的步骤进行过测试,在插入`vampire 1`数据时数据库是不允许插入数据的,数据库会报数据过长的错误,

    亮了(5)
    • wizardforcel (1级) 2017-01-11回复

      @ just test 我这里 5.5.25 是截断

      亮了(0)
  • Be_easy (1级) 2017-01-06回复6楼

    谢谢,学习了

    亮了(2)
  • Murviet (2级)我除了帅还有什么优点 2017-01-06回复7楼

    select * from users WHERE username=’vampire’; 确实会返回两个,如果加上 AND password 条件的话,不会匹配第一个,我用的是mysq 5.6.25

    亮了(4)
    • vul9527 (1级) 2017-01-06回复

      @ Murviet  的确,如果同时匹配username和password是不会匹配出目标用户的,我还专门写了文章说这个事,http://goodwaf.com/2016/12/30/%E5%9F%BA%E4%BA%8E%E7%BA%A6%E6%9D%9F%E6%9D%A1%E4%BB%B6%E7%9A%84SQL%E6%94%BB%E5%87%BB/

      亮了(1)
      • Murviet (2级)我除了帅还有什么优点 2017-01-06回复

        @ vul9527  明白了,谢谢

        亮了(3)
      • shengulong (1级) 2017-01-11回复

        @ vul9527  我看了你的文章,对一些地方提了些疑问,麻烦看下

        亮了(1)
    • 五条杠 (1级) 2017-01-06回复

      @ Murviet  这里指的是原用户登录成功后,查询其他数据时以username作为主键查询会产生多个数据。。。。

      亮了(3)
      • Murviet (2级)我除了帅还有什么优点 2017-01-06回复

        @ 五条杠  懂了,谢谢

        亮了(3)
  • X_man (1级)有些梦虽然遥不可及,但不是不可以实现,只要我足够的强。 2017-01-06回复8楼

    这个技巧不是早就有了么

    亮了(7)
  • Xsensir (1级) 2017-01-06回复9楼

    这个只有网站存在sql注入才能创建这样的用户名(这种用户名本身就非法)
    既然你都能创建用户了 你应该还能做更多 没必要这么弄

    亮了(3)
    • hkt (2级)403-Forbidden 2017-01-06回复

      @ Xsensir  大哥你是没看懂吧

      亮了(3)
      • Xsensir (1级) 2017-01-06回复

        @ hkt
        怎么注册带空格的username ?

        亮了(3)
    • s4cr00t 2017-01-06回复

      @ Xsensir  为什么需要有SQL注入呢,而且也没懂你的“既然你都能创建用户了 你应该还能做更多 没必要这么弄”,用户注册不就是在创建用户吗,请问怎么做更多?

      亮了(3)
  • whitemonty (4级)这家伙很懒,就是不肯写个人说明! 2017-01-06回复10楼

    数据库“自动截断” 这种看似友好的处理方法,往往埋下了个坑,还是不要太“自作多情” ,该提示太长的时候,还是提示一下好

    亮了(2)
  • Wooyun 2017-01-06回复11楼

    早在nohack 的那本脚本黑客攻击大全有 WOoyun那个江南鱼还是江南的鱼有这个案例

    亮了(2)
  • Exp丶南寒之海 2017-01-07回复12楼

    转发微博

    亮了(1)
  • c0mrad3 2017-01-08回复13楼

    学习了
    但是现在大部分网站注册时候都有用户名长度限制啊

    亮了(0)
  • shadowblade (1级) 2017-01-09回复14楼

    特殊字符还是应该过滤处理的 一了百了

    亮了(2)
  • 541543557 2017-01-10回复15楼

    弱弱的问一句。若是注册的时候限定字符类型。怎么办。

    亮了(2)
    • 阿西吧 2017-01-10回复

      @ 541543557 貌似都是本地js吧

      亮了(1)
  • yfgeek (2级)极客一样的精神!黑客一样的感觉! 2017-01-11回复16楼

    新姿势

    亮了(1)
  • shengulong (1级) 2017-01-11回复17楼

    个人觉得,把这段代码的验证修改为只验证用户名,整篇文档就显得顺畅很多
    <?php
    $username = mysql_real_escape_string($_GET['username']);
    $password = mysql_real_escape_string($_GET['password']);
    $query = "SELECT username FROM users
    WHERE username=’$username’";
    $res = mysql_query($query, $database);
    if($res) {
    if(mysql_num_rows($res) > 0){
    $row = mysql_fetch_assoc($res);
    return $row['username'];
    }
    }
    return Null;

    亮了(3)
  • 8098 (1级)好好先生 2017-01-12回复18楼

    学习了

    亮了(2)

必须您当前尚未登录。登陆?注册

必须(保密)

表情插图

取消

鸢尾

鸢尾

打码改变人生

169 篇文章124 条评论

相关阅读

  • 如何攻击WEB应用程序(连载一)
  • 浏览器插件的攻击向量
  • 百度、阿里、腾讯在列:“水坑攻击”利用JSONP劫持跟踪用户
  • 玩转metasploit系列(第八集)
  • 如何为WordPress做安全防护?

特别推荐

关注我们 分享每日精选文章

不容错过

  • CVE-2016-5696漏洞分析:TCP侧信道安全Leon不会玩QEMU2016-08-19
  • 半开源Web安全测试与学习平台 – 蚁逅69氏2015-03-19
  • 2015年夏季国内外重磅黑客峰会参会指南明明知道2015-06-18
  • 【重磅】FreeBuf发布2017金融行业应用安全态势报告FreeBuf研究院2017-03-20

FREEBUF

  • 免责声明
  • 关于我们
  • 加入我们

广告及服务

  • 寻求报道
  • 广告合作
  • 联系我们
  • 友情链接

关注我们

  • 官方微信
  • 新浪微博
  • 腾讯微博
  • Twitter

赞助商

Copyright © 2013 WWW.FREEBUF.COM All Rights Reserved 沪ICP备13033796号

css.php

正在加载中...

0daybank

标签: 暂无
最后更新:2017年5月23日

小助手

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

COPYRIGHT © 2024 www.pdr.cn CVE漏洞中文网. ALL RIGHTS RESERVED.

鲁ICP备2022031030号

联系邮箱:wpbgssyubnmsxxxkkk@proton.me