由一道ctf引发的关于SQL约束攻击的思考

SQL约束攻击

Posted by WHF Blog on August 30, 2018

SQL约束攻击

最近在刷bugku的ctf题的时候,遇到一道SQL约束攻击的题目,那就正好借着这个题目,来深入学习下SQL约束攻击。

贴个题目的链接:http://118.89.219.210:49163/index.php

简介:

关于SQL的攻击行为,注入可以说是接触最多,也是容易利用且危害较大那种,但是SQL约束攻击,其实并不常见,说实在的我是第一次遇到这种类型的问题,但是它的严重性并不比注入低。 首先了解几个关键知识点:

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

     SELECT * FROM users WHERE username='admin     ';
    
  • 贴两段代码:

    1.注册:

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

    2.登录:

     <?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;
    
  • 根据代码,我们可以看到开发人员有一些安全的考虑,使用mysql_real_escape_string()过滤用户输入参数,使用单引号(’)来增加安全性。

  • 当我们检索“admin”的,将返回两个用户。第二个用户名实际上是“admin+若干空格”。现在,如果使用用户名“admin”和“admin+若干空格”的密码登录的话,则所有搜索该用户名的SELECT查询都将返回第一个数据记录,也就是“admin”的数据记录。这样的话,攻击者就能够以“admin”身份登录。这个攻击已经在MySQL和SQLite上成功通过测试。

  • 但是正因为上述的几个关键知识点,我们可以使用“admin+若干空格”绕过第一步用户是否存在的检验而成功注册,而当登录时,“admin”等同于“admin ”,于是“admin ”则可以以“admin”成功登录系统。