Constraint-Based SQL Attacks

foreword

The good news is that developers are now starting to pay attention to security issues when building websites. Most developers are aware of the existence of SQL injection vulnerabilities. In this article, I would like to discuss with readers another vulnerability related to SQL databases. Its harm is comparable to SQL injection, but it is less common. Next, I will show readers this attack method in detail, as well as the corresponding defense strategy.

Note: This article is not about SQL injection attacks

Background introduction

Recently, I came across an interesting code snippet where developers tried various methods to ensure secure access to the database. When a new user tries to sign up, the following code is run:

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

Use the following code to verify the login information:

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

Safety Considerations:

  • Filter user input parameters? - complete inspection

  • Use single quotes (') for added security? - complete inspection

Logically, it shouldn't go wrong, right?

However, an attacker can still log in as any user!

Attack method

Before talking about this attack method, first we need to understand a few key knowledge points.

  1. When performing string processing in SQL, spaces at the end of the string are removed. In other words "vampire" is equivalent to "vampire", which is true for most cases (such as strings in a WHERE clause or strings in an INSERT statement) such as the query result of the following statement, which is the same as using the user The result is the same when querying the name "vampire".

SELECT * FROM users WHERE username='vampire     ';
  1. But there are exceptions, the best example is the LIKE clause. Note that this trimming of trailing whitespace is mostly done during "string comparisons". This is because, SQL internally pads strings with spaces in order to make them the same length before comparing.

  2. In all INSERT queries, SQL will limit the maximum length of the string based on varchar(n). That is, if the length of the string is greater than "n" characters, then only the first "n" characters of the string are used. For example, the length of a specific column is limited to "5" characters, then when inserting the string "vampire", only the first 5 characters of the string, that is, "vampi", can actually be inserted.

Now, let's build a test database to demonstrate the specific attack process.

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

Then create a data table users, which contains username and password columns, and the maximum length of the field is limited to 25 characters. Then, I'll insert "vampire" into the username field and "my_password" into the password field.

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)

To demonstrate trimming of trailing whitespace characters, we can type the following command:

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

Now let's assume a vulnerable website uses the aforementioned PHP code to handle the user registration and login process. In order to break into any user's account ("vampire" in this case), simply sign up with the username "vampire[lots of blanks]1" and a random password. For the chosen username, the first 25 characters should only contain vampire and whitespace, doing this will help bypass queries that check if a particular username already exists.

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

It should be noted that when executing a SELECT query, SQL will not shorten the string to 25 characters. So here the full string will be used to search, so no matches will be found. Next, when the INSERT query statement is executed, it will only insert the first 25 characters.

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)

Great, now we retrieve "vampire", which will return two separate users. Note that the second username is actually "vampire" plus trailing 18 spaces. Now, if logged in with username "vampire" and password "random_pass", all SELECT queries that search for that username will return the first data record, which is the original data record. This way, the attacker can log in as the original user. This attack has been successfully tested on MySQL and SQLite. I believe it still applies in other situations.

means of defense

There is no doubt that when doing software development, attention needs to be paid to such security vulnerabilities. We can take the following steps to defend against:

  1. Add UNIQUE constraints to those columns that are required or expected to be unique. Actually this is an important rule when it comes to software development, even if your code has functions to maintain its integrity, you should define data appropriately. Another record cannot be inserted because the 'username' column has a UNIQUE constraint. Two identical strings will be detected and the INSERT query will fail.

  2. It is better to use 'id' as the primary key of the database table. And the data should be tracked by id in the program

  3. For more safety, you can also manually adjust the limit length of the input parameters (according to the database settings)

The article is referenced from: https://dhavalkapil.com/blogs/SQL-Attack-Constraint-Based/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325111795&siteId=291194637