Bug #81986 Potential security concern - SYSTEM variables can be EXECUTE'd.
Submitted: 23 Jun 2016 11:55 Modified: 12 Aug 2016 14:07
Reporter: daniel reece Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Security: Audit Severity:S3 (Non-critical)
Version:All OS:Any
Assigned to: CPU Architecture:Any
Tags: Security, sql injection, variables

[23 Jun 2016 11:55] daniel reece
Description:
This is my first report so I apologize if I make any mistakes. I am also not a SQL ninja so its possible there are factual errors in this report. Although I believe this to be a 

I have found that it is possible to store a query as a string within some of the MySQL SYSTEM variables (those with global scope) such as init_slave, and then EXECUTE the contained query.

While this might just seem like something you "wouldnt want to do" rather than a security issue, it may actually open the door to a potentially new, yet obscure method of SQL injection, for some applications, and I believe this should be fixed at the DB level by preventing global variables from being able to be EXECUTE'd.

I wrote a short post this-morning describing the issue in greater detail:
http://hiburn8.org/?p=196

How to repeat:
Imagine you have an application vulnerable to SQLi at the beginning of the query. It would be possible for an attacker to form a query inside a system variable and execute it by turning the following lines into individual payloads and issuing them to the application in succession.
The main benefit of doing this is the ability to form long queries by hijacking the 'permanent; nature of global variables.

SET GLOBAL init_slave='select table_name from information_schema.tables limit 40,1'
PREPARE stmt1 FROM @@init_slave;
EXECUTE stmt1;

The attacker could also use this method to inject into areas protected by rudimentary WAFs/defenses using basic concatenation to remove full MySQL words like the following:

SET GLOBAL init_slave="selec"
SET GLOBAL init_slave=concat(@@init_slave,"e fro")
SET GLOBAL init_slave=concat(@@init_slave,"e m inforamtion_schem")
SET GLOBAL init_slave=concat(@@init_slave,"a.table")
SET GLOBAL init_slave=concat(@@init_slave,"s limi")
SET GLOBAL init_slave=concat(@@init_slave,"t 40,1")

Each of the lines above could be sent it a separate request and therefore make detection very difficult.

This would also provide a means to inject into very small (<50 char) input areas which may otherwise be unexploitable.
  

Suggested fix:
the EXECUTE function should not permit executing SYSTEM variables.
[23 Jun 2016 11:56] daniel reece
Although I believe this to be a.. "legitimate security issue." <- is what the report should say. Woops.
[24 Jul 2016 1:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[10 Aug 2016 21:50] daniel reece
Issue moved back to open to respond to a request for more information
[10 Aug 2016 22:56] daniel reece
In response to the question (copied below):

Ultimately there are two big reasons why an attacker would want to poison a SYSTEM variable with a SQL statement and execute that as opposed to a SESSION variable:

Firstly, it allows the attacker to slowly construct the SQL query by appending to the SYSTEM variable value over multiple connections before executing it. From the perspective of a vulnerable application for example, if an attacker makes multiple requests to the application containing SQLi payloads to concatenate/append text to a session variable... the variable would normally always reset after each database connection. Therefore the attacker is unable to append/update the variable. The SESSION variable retains its value over multiple connections.

This also has the benefit of being extremely difficult to detect as an attack, as only a few SQL keywords are needed to be sent in each payload to update the SYSTEM variable, like so: "SET GLOBAL init_slave=concat(@@init_slave,'x')". Potential filter/WAF evasion is of-course not a problem with MySQL itself, but is a potential reason why an attacker would prefer this method vs using SESSION variables.

Secondly, the above method allows injection into attacker-controlled input which is severely limited in length (sub 50 characters). Typically, with a SQL injectable query, the attacker would be expecting to need to input >100 characters in order to perform data-exfiltration attacks (and common SQLi exploitation tools like SQLmap will use far more than this). In fact a penetration testing company created a challenge where one of the key requirements was being able to perform targeted data-exfiltration in under 90 characters, which is not trivial (
 https://pentest.co.uk/events/bsidesmcr-2015.html).
Because of this there will be many applications using MySQL which attackers could believe are "unexploitable" with regards to performing targetted data-exfiltration due to input length restrictions.. but which they may now be able to revisit and exploit using this method. I imagine that we won't be talking a particularly large sum of applications here, but also not an insignificant amount. This reason I feel lies on MySQL for a fix, as the database has an unexpected behaviour which makes a number of previously unexploitable applications now vulnerable. I appreciate that the applications in question would all need to fall foul to some form of SQLi in the first place, but this behaviour definitely exacerbates the problem. 

Effectively we have a whole new "technique" of SQLi because of this behaviour, specific to MySQL, which can be easily removed by preventing SYSTEM variables from being execute'd.

----------------------------------------------
[23 Jun 14:23] Sinisa Milivojevic
Hi!

Why do you think that this feature is more dangerous then:

SET SESSION local_var='select table_name from information_schema.tables
limit 40,1'
PREPARE stmt1 FROM @session.local_var;
EXECUTE stmt1;
[11 Aug 2016 10:44] daniel reece
"The SESSION variable retains its value over multiple connections." should of course read "The SYSTEM... ".
[11 Aug 2016 15:33] MySQL Verification Team
Having in mind that privileges checking is performed during execution stage and NOT during parsing, can you explain why do you think that this is a security problem or why do you think that this is a bug.
[11 Aug 2016 16:13] daniel reece
Sure. 
Ok so, my feeling is that this is a security issue down to the misbehaviour of the database, allowing SYSTEM variables to be executed like any other variable. Thats the bottom line. And it leads to attackers being able to exploit very obscure SQLi scenarios which would otherwise be unexploitable using a different database.

This flaw does NOT allow an attacker to elevate any privileges of any kind on the database and is not a flaw in permissions. However, this behaviour could allow an attacker to bypass application-level restrictions set on clients of the database. Namely, this issue allows an attacker to bypass query length restrictions by using the "sticky" nature of SYSTEM variables over multiple DB connections to build up a query over multiple connections within a SYSTEM variable, and then execute it later.

Something I did not consider earlier which is another reason why this is an issue:

Because the query you want to store within a SYSTEM variable can be constructed over multiple database connections and the variable is something most database owners would not think to view... the attacker can send the requests to build the query over an extended period (concatenating a single letter per week for example) before finally executing it at their leisure. This effectively provides attackers with some level of stealth during exploitation. It might also be the case that the SYSTEM variable is not seen in any backups of the database and so might even complicate basic forensic analysis.

Ultimately, again, this behaviour does not lead to a more serious compromise over MySQL than you would expect when an attacker can control the query string, however it does make exploitation easier in many scenarios easier and, in some case, will only be possible because of it.
[11 Aug 2016 17:46] MySQL Verification Team
Application level problems are to be solved by application programmers, not by SQL server.

Next, we do not support SQLi.

Query length can not be bypassed with this method , due to the method of the checking, described in our user and internals manual.

Luckily, all your discussion is in vain as you need SUPER privileges to change system variables. We can not protect our product from malicious or ignorant DBAs.

Hence, this is not a bug. 

I recommend a full reading of both user and internals manual.
[11 Aug 2016 18:15] daniel reece
Sorry Sinisa, but I think you are mis-understanding the issue and its fairly obvious resolution.

The last question you asked leads me to believe you simply don't understand what I am describing here, as it holds no relevance to the issue at all.

This is a bug which facilitates a new method of SQLi. It isn't SQLi itself, or an application layer issue I am discussing. This is database behaviour which results in a new type of SQLi. Not supporting SQLi and actually creating a product that invents and new type of SQLi are different things. This door should be closed.

We are talking about a behaviour (executing system variables) that is a completely unnecessary "feature" in the first place after all (read the manual, there is no supported reason to ever do this).

Query length restrictions enforced on clients/applications CAN be bypassed with this method in the exact way I describe. I'm not talking about DB restrictions.

I am well aware of the level of privileges required for this issue to be abused successfully, and its ludicrous that you think that your product should not give, even the most ignorant of DBAs, the highest level of security you can offer.

I have discussed this with other security professionals, and this is indeed a bug. Regardless of wether you chose to believe me/us.
[11 Aug 2016 18:42] MySQL Verification Team
Hi!

It could be a bug, but not in our server nor our clients.

Some or one of the administrators must have all privileges, including SUPER. Hence, the others can not meddle with SYSTEM variables, as they do not have a privilege. If only DBA has SUPER privilege, and that is recommended practice (our manual), SYSTEM variables are quite safe.

There  could be a bug here. So, please create a new bug with a fully repeatable test case showing that query length restrictions enforced on clients/applications CAN be
bypassed with this method in the exact way. Prove it. Without having SUPER privilege.

We are responsible for providing security tools. We are not responsible for their misuse.

And this is not about belief. If you give great privileges to somebody, then that person can DROP all tables, databases, routines and you are left with nothing. We can not provide protection against it. And all this without using SYSTEM variables.

Not a bug.
[12 Aug 2016 6:44] daniel reece
Its called defense-in-depth. Saying, "oh, well, you would need to run as root and the manual says don't do that. those guys are already screwed" is completely ridiculous and not the answer you want from get an Oracle representative.

There may be particular edge-cases where the "drop all tables" scenario is not possible with standard injection methods. for example (but not limited to):

The word "DROP" is blocked by a waf.
The injection input area is 46 characters.
 
Dropping targeted tables/data would be possible with, and potentially only with, this method. This is the scenario YOU posed and then said "We can not provide protection against it". I have told you exactly what you could do to protect against it (to some extent).

I'll provide additional support to re-open this when I get chance, your answer is unsatisfactory.
[12 Aug 2016 13:40] MySQL Verification Team
I wish I could have convinced you of the simple fact that this is not a bug.
[12 Aug 2016 14:07] daniel reece
You're an unknown entity that made no attempt at solid convincing. You came across confused about the issue with your questions and extremely obnoxious. Regardless of who is right, you've made a fairly simple process quite unenjoyable and I'm unlikely to bother next time.

I've closed the issue on the grounds that we will have to agree to disagree.

Daniel Reece
IBM X-Force-Red