Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ""=" exploit this MySQL Query?

On a MySQL 5.6 database, I build this simple table and insert a row:

CREATE TABLE `users` ( 
`username` varchar(64) DEFAULT NULL, 
`password` varchar(64) DEFAULT NULL 
);

INSERT INTO users VALUES ('bob', 'pass');

Then I set up a query in PHP like so:

$query = "SELECT * from users where username=\"".$username."\" and password=\"".$password."\"";

When $username and $password are both equal to ""=", the resulting query is SELECT * from users where username="""="" and password="""="". When that's used to query the table set up before, the row in the table is returned.

The question is, how is MySQL evaluating that query such that it considers the query valid and that the WHERE statement is true? Assuming all double-quotes are matched with the nearest untaken adjacent double-quote, I would have expected the query to be interpreted something like this, which looks like it should be considered gibberish:

SELECT * from users where username=""
"="
" and password="
""
=
""

Here's an example of this behavior on a MySQL 5.6 DB: http://sqlfiddle.com/#!9/02e606/2

like image 575
Daniel Maxson Avatar asked Oct 07 '16 18:10

Daniel Maxson


People also ask

What is exploited by an SQL injection?

SQL injection, also known as SQLI, is a common attack vector that uses malicious SQL code for backend database manipulation to access information that was not intended to be displayed. This information may include any number of items, including sensitive company data, user lists or private customer details.

What are MySQL vulnerabilities?

Easily exploitable vulnerability allows high privileged attacker with network access via multiple protocols to compromise MySQL Server. Successful attacks of this vulnerability can result in unauthorized ability to cause a hang or frequently repeatable crash (complete DOS) of MySQL Server.

How can SQL injection be prevented?

The only sure way to prevent SQL Injection attacks is input validation and parametrized queries including prepared statements. The application code should never use the input directly. The developer must sanitize all input, not only web form inputs such as login forms.

What is SQL injection vulnerability?

What is SQL Injection? SQL injection attacks, also called SQLi attacks, are a type of vulnerability in the code of websites and web apps that allows attackers to hijack back-end processes and access, extract, and delete confidential information from your databases.


2 Answers

It's because MySQL allows "" as an alternative for \".

mysql> select '"foo"' = """foo""", '"foo"' = "\"foo\"", 'foo' = """foo""";
+---------------------+---------------------+-------------------+
| '"foo"' = """foo""" | '"foo"' = "\"foo\"" | 'foo' = """foo""" |
+---------------------+---------------------+-------------------+
|                   1 |                   1 |                 0 |
+---------------------+---------------------+-------------------+
1 row in set (0.00 sec)

In your specific case:

SELECT * from users where username="""="" and password="""=""

would be the same as (if I'm parsing this correctly in my head):

SELECT * from users where (username='"="" and passsword="') = ""

A three-way equality test IS syntactically correct, but does not evaluate as expected

mysql> select 'a' = 'a' = 'a';
+-----------------+
| 'a' = 'a' = 'a' |
+-----------------+
|               0 |
+-----------------+

because that parses as (a=a)=a -> true=a -> false

-- comment follow up for @juan:

mysql> select 'a'='a'='a', 'a'='a'='b', 'a'='b'='a', 'b'='a'='a', 'b'='b'='a';
+-------------+-------------+-------------+-------------+-------------+
| 'a'='a'='a' | 'a'='a'='b' | 'a'='b'='a' | 'b'='a'='a' | 'b'='b'='a' |
+-------------+-------------+-------------+-------------+-------------+
|           0 |           0 |           1 |           1 |           0 |
+-------------+-------------+-------------+-------------+-------------+

It's non-intuitive, because

mysql> select 'a'=('a'='b'), ('a'='a')='b', true='b', 'a'=false;
+---------------+---------------+----------+-----------+
| 'a'=('a'='b') | ('a'='a')='b' | true='b' | 'a'=false |
+---------------+---------------+----------+-----------+
|             1 |             0 |        0 |         1 |
+---------------+---------------+----------+-----------+

--- followup to the followup: again, your original query:

SELECT * from users where username="""="" and password="""=""

will run as

SELECT * from users where (username='"="" and passsword="') = ""
SELECT * from users where (false) = ""
SELECT * from users where true

because false ="" in mysql evaluates to TRUE, therefore ALL rows get included, unless you have a user whose username is literally "="" and password=".

like image 101
Marc B Avatar answered Oct 06 '22 21:10

Marc B


I guess you are doing something like this

Sql Demo

SELECT """="" and password="""=""   -- this is equal to 0
from users 
where (username = "anything") = false;

enter image description here

like image 22
Juan Carlos Oropeza Avatar answered Oct 06 '22 23:10

Juan Carlos Oropeza