SQL约束攻击

    在做bugku的web题时发现一道sql约束的题,果断学习了一下sql约束攻击的知识,以下部分文字及代码引用网址:https://www.freebuf.com/articles/web/124537.html

    后台在接收到用户名与密码后使用了php的函数mysql_real_escape_string()处理,并使用单引号包裹。验证用户名与密码的代码如下:

<?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'];
  }
}

    按理说上述代码不会产生SQL注入等漏洞的啊,下面介绍几种关键知识:

    在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。例如如下代码:

SELECT userId from user where username = 'test            '

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

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

    当注册时,后台一般先select一下用户名看看是否存在,然后在insert一下。示例代码如下:

<?php
$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) {
  }
  else {
    $query = "INSERT INTO users(username, password)
              VALUES ('$username','$password')";

    这里注册时使用用户名+【大量空格】和随机密码注册即可完成攻击。

    主要原理就是insert时候有varchar(n)的限制,大于n的时候会截取前n个存入。在数据库对字符串进行比较时,即select操作,如果两个字符串的长度不一样,则会将较短的字符串末尾填充空格,使两个字符串的长度一致。注册时select语句不会将"admin+[大量空格]11"删减到n位,所以不会被select查出与admin重复,不会返回数据,接下来就可以插入admin+[空格](截取)11和自定义密码了。

    如果使用用户名“vampire”和密码“random_pass”登录的话,对比时是admin与admin+[大量空格],会将前面的admin添加空格与后面的长度相同在进行对比,那么返回的只能是我们自己注册的用户信息,而不会返回目标用户信息。SQL查询语句是一个and操作,如果密码不一样怎么会把目标用户的信息也返回回来?

    当登陆时使用admin与自定义密码登陆,数据库将返回我们自己注册的账户信息,但是注意此处的return $username,虽然此时查询出来的是我们自己的用户信息,但是返回的用户名则是目标的用户名。如果此后的业务逻辑直接以该用户名为准,则我们就达到了水平越权的目的。

    靶机地址:http://123.206.31.85:49163/

    admin+[大量空格]11与随机密码住注册:

     注册成功后用admin登陆:

    用admin用户名登陆成功。

    求助:这个CTF使用admin+一个空格也可以注册成功,求助这是为什么。字符串对比为什么相等了。

使用限制

  1. 服务端没有对用户名长度进行限制。如果服务端限制了用户名长度就不能导致数据库截断,也就没有利用条件。
  2. 登陆验证的SQL语句必须是用户名和密码一起验证。如果是验证流程是先根据用户名查找出对应的密码,然后再比对密码的话,那么也不能进行利用。因为当使用Dumb为用户名来查询密码的话,数据库此时就会返回两条记录,而一般取第一条则是目标用户的记录,那么你传输的密码肯定是和目标用户密码匹配不上的。
  3. 验证成功后返回的必须是用户传递进来的用户名,而不是从数据库取出的用户名。因为当我们以用户Dumb和密码123456登陆时,其实数据库返回的是我们自己的用户信息,而我们的用户名其实是[Dumb      ],如果此后的业务逻辑以该用户名为准,那么就不能达到越权的目的了。

防御 

  1. 将要求或者预期具有唯一性的那些列加上UNIQUE约束,由于’username’列具有UNIQUE约束,所以不能插入另一条记录。将会检测到两个相同的字符串,并且INSERT查询将失败。

  2. 最好使用’id’作为数据库表的主键。并且数据应该通过程序中的id进行跟踪。

  3. 限制输入长度。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值