
A Very Sleepy MySQL Attack - cottenio
https://blog.cotten.io/a-very-sleepy-mysql-attack-bff80975fda7
======
js4ever
The real problem here is SQL injection... Not sleep

~~~
erazor42
Agree, if you are vulnerable to this attack, you are probably vulnerable to a
good old ' or '1'; drop databases :D

~~~
wongarsu
Yes, but an attacker is more likely to try SLEEP(10) than DROP DATABASES,
because the attacker usually wants your data (and your server, but the data is
a bonus). So if disabling sleep makes a few bots miss an actual vulnerability,
it's a good step for defense in depth.

~~~
cottenio
Correct. It's more valuable, especially when trying to exfiltrate data or when
trying to inject XSS opportunities.

Plus, realistically, SLEEP allows you to scan for thousands of different test
cases in a quick period and measure the hang time to figure out which vector
worked.

------
userbinator
_why do vanilla MySQL packages come with SLEEP() even enabled? Why not make it
an option?_

Because it's a good "canary" for SQL injection: it doesn't do any real damage,
but it's noticeable enough to tell you that you have a possibly vulnerable
condition.

~~~
regecks
> it doesn't do any real damage

I'm not sure about that. You can perform blind exfiltration of row data by
using SLEEP. Handy in situations where you can run a query but can't get it
reflected in the server's output.

~~~
cottenio
This is a valuable point: you can absolutely exfiltrate data this way based on
timing, and it's fairly automated with tools at this point.

------
ishitatsuyuki
SQL injection is pretty non-existent these days as frameworks and WAF evolves
(assuming a company doing at least minimum of security practices). It doesn't
seem there's a point in blocking such attacks at the DBMS side.

Given the function has a valid use and there are other ways to do damage to
the database system, I don't see it's something that stands out. There are
numerous ways for doing database probe or even RCE, thus this is no more than
one of them.

~~~
smt88
> _assuming a company doing at least minimum of security practices_

This is not a sound assumption. SQL injection is still pretty common in
practice. Even frameworks that try to sanitize input may have a "roll your
own" approach that has flaws in it.

~~~
setr
At some point I realized sanitizing your input for SQL is one of the dumbest
ideas I've ever heard: you can trivially avoid the issue by parameterizing the
variable inputs, and explicitly telling the DB that this chunk ain't SQL.
Sanitizing is an absurd hack in any situation, in the fashion that parsing
html with regex is; But especially with generating SQL, any notion of
"sanitizing your input" should be considered a bug (perhaps a wetware one)[1]

Afaict the only reason this idea ever became widespread was because PHP's
native MySQL driver lacked support for it for ages (I guess till PHP5? Been
years since I looked into this)

[1] Obviously I'm not talking about validation eg validating a phone number;
anytime you're trying to embed strings within a program but have to be worry
that your string doesn't get read as part of the program, something has gone
horribly wrong

~~~
andyroid
There’s a whole class of actions and values that you can’t parameterize, like
anything resembling DDL queries. I have worked on several products where these
types of queries (like creating tables dynamically) have been an absolute
requirement. Sanitizing input is still very much a necessity there.

~~~
setr
I'm not sure I see anything in DDLs that denies parameterization of user
input, except that support might be currently non-existent; but if the support
is missing, it doesn't make sanitization a correct solution... it makes it a
necessary hack to work around a lacking communication protocol

Ofc if the user is putting in full custom queries, parameterization doesn't
help anything, but I'm not sure what you're even sanitizing at that point
(semantics? Afaik sanitization refers to syntax cleanup; It'd be even dumber
to avoid people dropping your important tables by parsing a SQL string,
instead of making use of the much more reliable DB permission systems...)

It's absurd: A constant source of vulnerability in websites across the world
is a _syntax error_.

It's the definition of accidental complexity -- A program with a valid
semantic understanding of what it has is somehow totally incapable of passing
on that wisdom except by code generation; and this is when it is free of the
burden of any real constraints beyond correctness -- its certainly not a fast
method of serializing/deserializing, it certainly doesn't minimize network-
size, it certainly isn't a safe or composable API... it's just a dumb,
horrible thing and we pretend its all ok because you just need to _sanitize
your input_.

I wouldn't really care if sanitization was just considered a necessary hack,
especially in certain corner-cases; but its not. It's thought of as _a good
thing to do_. In fact, _a best practice_.

------
pmontra
Btw, PostgreSQL has pg_sleep()

[https://www.postgresql.org/docs/current/functions-
datetime.h...](https://www.postgresql.org/docs/current/functions-
datetime.html)

    
    
        SELECT pg_sleep(1.5);
        SELECT pg_sleep_for('5 minutes');
        SELECT pg_sleep_until('tomorrow 03:00');
    

Maybe useful for debugging? [https://www.endpoint.com/blog/2012/11/05/how-to-
make-postgre...](https://www.endpoint.com/blog/2012/11/05/how-to-make-
postgresql-query-slow)

~~~
coder543
The article seems to be saying that MySQL's sleep function pauses the entire
database for the duration, whereas PostgreSQL's will just sleep that
connection for the specified duration and other connections can keep working.

------
amingilani
If you take away SLEEP, the attacker will exploit something else during their
test. Better SLEEP than really badly customized DROP or DELETE statements to
see if their last created resource is affected.

Why not monitor for SLEEP execution instead?

~~~
cottenio
These are valid points, but don't necessarily reflect the reality of a
production web environment whose user ONLY has SELECT access to read caches
and view data from the database.

Being able to enumerate vulnerable spots or exfiltrate data can arguably be
more devastating than performing a DROP that's noticed immediately and the LKG
table from backup is imported to fix it.

~~~
QuinnWilton
You can perform timing attacks without SLEEP by just writing slow queries. I
usually use the BECHMARK command to run a few million MD5 calculations:

    
    
      AND 1 IN (SELECT BENCHMARK(SOME_MULTIPLIER*15000000,MD5(CHAR(97))))--

~~~
cottenio
One suggestion is to allow further segregation of permissions for functions
like SLEEP, BENCHMARK, etc. A front-end request has no need for it.

It’s the exposition of things that “act” on lax query permission sets that
“appear” read-only (but in fact have interrupt style executions) that leads to
trivialization of abuse.

~~~
JetSpiegel
Even better is to whitelist all SQL than runs on the database using prepared
statements. Anything else is a hack.

------
sqldba
I don't get it. "This makes discovery very slightly easier (only in the most
awful sql-injection code you can imagine)". Why should we care about that?

------
tzury
If you are vulnerable to `sleep()` you are vulnerable to `drop table...` and
`select * from users...` . Sleep is not the issue at all.

~~~
sverhagen
A lot of other commands require parameters that the attacker may not know the
values for. Those require more knowledge about the system that first needs to
be exfiltrated. Not every (hacked) query has its output directly plastered
back in the UI, webpage or API response. So that would need more hacking, even
if the "sleep" tells the hacker they're on to something. Disabling "sleep"
would take away the canary, would it not? Maybe the hacker isn't even
interested in dropping tables.

~~~
PeterisP
Disabling sleep would not take away the canary, it would make it more
inconvenient - every instance of sleep can be replaced with some convoluted
query that does a very slow calculation.

------
hyperman1
Isn't there a way to make the database very slow by a complicated but generic
query. Thinking about e.g. oracle's connect by + dual

If this is the case, removing sleep doesnt help you. Just run a slow query

~~~
bufferoverflow
Yeah, MySQL has recursive queries.

[https://dev.mysql.com/doc/refman/8.0/en/with.html#common-
tab...](https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-
expressions-recursive)

Though one can set a limit on query run time via max_execution_time.

------
dbks
that is why you put your database behind a firewall and not expose its port to
the public internet. There is really no need except for a handful of really
edge cases where you have to expose the port to the internet even then you can
limit the access to specific hosts only.

~~~
bufferoverflow
That won't help you, because the author assumes an SQL injection is at play.
Which is quite a stretch. Who is dumping direct POST/GET data straight into
SQL without sanitation these days? Maybe some noobs, but then you have a
bigger problem.

~~~
lowercased
I still see it today, in code being written in 2018. One call say "noob",
but... every year there's new people coming in to the field. "Noobs" is an
evergreen problem.

