login1(SKCTF) (sql约束攻击)

题目

image.png

背景知识

最近,我遇到了一段有趣的代码,它尝试尽一切可能来保护数据库的访问安全,例如每当新用户进行注册时,将运行以下代码:

<?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; 

攻击手法

首先,在处理SQL中的字符串时,字符串末尾的空格字符都会被删除。换句话说,“vampire”与“vampire ”几乎是等效的,这在大多数情况下是正确的,例如WHERE子句中的字符串或INSERT语句中的字符串。例如,以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。

       SELECT * FROM users WHERE username='vampire '; 
等同于  SELECT * FROM users WHERE username='vampire'; 

究其原因是因为在字符串比较的过程中,内部在比较之前先进行了补充,使其长度一致再进行比较。

下面再本地复现一遍。

image.png

image.png
SELECT username FROM users WHERE username='vampire' AND password='random_pass';

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

现在讲一下sql约束攻击的条件:

1.mysql处于ANSI模式。如果是TRADITIONAL模式或者STRICT_TRANS_TABLES模式会报错data too long for column。

2.服务端没有对用户名长度进行限制。如果服务端限制了用户名长度就自然就不客能导致数据库截断,也就没有利用条件。

3.登陆验证的SQL语句必须是用户名和密码一起验证。如果是验证流程是先根据用户名查找出对应的密码然后再比对密码,当使用vampire为用户名来查询密码的话,数据库此时就会返回两条记录,而一般取第一条即目标用户的记录,那么传输的密码肯定和目标用户密码匹配不上的。

4.验证成功后返回的必须是用户传递进来的用户名,而不是从数据库取出的用户名。因为当我们以用户vampire和密码random_pass登陆时,其实数据库返回的是我们自己的用户信息,而我们的用户名其实是vampire+若干个空格,如果此后的业务逻辑以该用户名为准,那么就不能达到越权的目的了。

回到题目之中。

我们注册一个如下账号


image.png

然后直接 username:admin password:As123123登陆


推荐阅读更多精彩内容