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
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.
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.
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? 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.
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="
.
I guess you are doing something like this
Sql Demo
SELECT """="" and password="""="" -- this is equal to 0
from users
where (username = "anything") = false;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With