SQL Injection - MySQL comment: the double dash mystery

Intro#

When doing penetration testing using a black box approach, you may find a SQL injection (SLQi) by fuzzing with common payloads. Except if there is a verbose error disclosing the original SQL query, you are not aware of the query structure. Your input may be injected at the beginning of the query or multiple times in the query, you don't really know. So to avoid any uncontrolled and unexpected side effects, a pentester wants to end his payload with a comment to neutralize and end the query so the behavior becomes more predictable.

Which comment?#

Some DBMS (Database Management System) supports inline comments like # or --, some less common %00 comparable to a null byte injection, some supports multiline comments /* */, etc. and there are also some weirder uncommon syntax. There are many DBMS and the comment support is different for each one of them.

As with a black box approach one may not be aware of which DBMS is used and that detecting which one it is can be difficult, a pentester would prefer to use the most interoperable syntax.

We'll not use an unclosed multi-line comment as it may comment too much or even raise an error if not close.

MySQL (Oracle MySQL, MariaDB, Percona Server), Oracle Database, PostgreSQL, Microsoft SQL Server, SQLite, Apache Ignite, Firebird, IBM DB2, etc. use many different custom implementation of SQL (Structured Query Language).

The only inline comment in standard SQL in the double dash -- [1], this is also the only one supported by all DBMS. [2]

The double dash mystery#

So if -- is supported by all DBMS why do we see most of the payloads ending by -- - or --+ and not only -- alone?

We have to blame MySQL syntax for that!

When I said all DBMS supports the double dash syntax, it's not exactly true.

In fact MySQL is an exception. [3] [4]

From a -- sequence to the end of the line. In MySQL, the -- (double-dash) comment style requires the second dash to be followed by at least one whitespace or control character (such as a space, tab, newline, and so on). This syntax differs slightly from standard SQL comment syntax, as discussed in Section 1.8.2.4, "'--' as the Start of a Comment".

Yes, MySQL needs that the two dash are followed by a whitespace character (space, tab, new line, etc.). But most of the time, SQL injection are exploited over HTTP from a web application. This means that web browsers, web frameworks, application backends, proxies, underlying languages, may all trim trailing whitespaces and so a --<whitespace> may be transformed into -- and so MySQL seeing it as invalid.

But MySQL is one of the most popular DBMS so we need to have a generic payload working with it. That's why you often see -- -, adding any character ofter the whitespace so it is not trailing and won't be trimmed. It means that -- - is not different from -- a, -- Z, or -- !.

So why --+ exists? Because in the URL standard the space character is encoded as a plus sign [5], eg. for UTF-8 U+0020 SPACE will be encoded as U+002B (+). So it means a URL decoded will decode the plus sign as a space and will transform back --+ into --<space>.

Note: That's why base64url (a.k.a. URL-safe and filename-safe base64) is using - instead of + and _ instead of / (RFC 4648).

But if the --+ is encoded (eg. URL-encoded) --+ will be transformed into --%2B and so when it will be decoded --+ won't be recognized as valid by MySQL, that's why it is safer to use --<space><any_character> such as -- - because if URL-encoded into --%20- it will be still decoded as -- -.

Why MySQL requires a whitespace character after the double dash?#

By reading the MySQL documentation [4] we can read:

The space is required to prevent problems with automatically generated SQL queries that use constructs such as the following, where we automatically insert the value of the payment for payment:

1
UPDATE account SET credit=credit-payment

Consider about what happens if payment has a negative value such as -1:

1
UPDATE account SET credit=credit--1

credit--1 is a valid expression in SQL, but -- is interpreted as the start of a comment, part of the expression is discarded. The result is a statement that has a completely different meaning than intended:

1
UPDATE account SET credit=credit

The statement produces no change in value at all. This illustrates that permitting comments to start with -- can have serious consequences.

Using our implementation requires a space following the -- for it to be recognized as a start-comment sequence in MySQL Server. Therefore, credit--1 is safe to use.

Another safe feature is that the mysql command-line client ignores lines that start with --.

Conclusion#

One might want to use -- - as the most interoperable and safest inline SQL comment as -- won't work with MySQL and --+ will break if encoded.

Share