
SQL injection with raw MD5 hashes - philfreo
http://cvk.posterous.com/sql-injection-with-raw-md5-hashes
======
tptacek
Summary: binary MD5 hashes are, in fact, binary, and any given MD5 hash has a
1/16 chance of containing a given SQL metacharacter. The CTF challenge here
required the calculation of a hash containing a whole 4-character injection
string; this is harder, but not Hard.

You should know that the exact same problem applies (moreso, in fact) to
encrypted strings. Developer laziness insulates most apps from raw MD5 digests
(most devs use the hex digest function, which returns human readable [and
safe] output). But the exact same "iterate 1 bit at a time until you hit a
jackpot block" trick works with almost every application that uses AES.

It's not just SQL, either; I've used it to get XSS out of corrupted AES
decryptions as well.

And, of course, the same trick works in the opposite direction. If you encrypt
a string with a quoting domain (say, where the character ';' needs to be
quoted '\;' to preserve an encoded tuple), attackers can pad inputs to get the
quote and the metacharacter to span blocks, then use block corruption to kill
the quote but not the metacharacter.

Have I mentioned today how you shouldn't be building crypto code? DON'T DATE
ROBOTS.

~~~
daeken
> It's not just SQL, either; I've used it to get XSS out of corrupted AES
> decryptions as well.

How would you go about such a thing? My initial thought is to simply permute
over the controllable bytes and see what comes out, looking for specific
characters that get you what you need, e.g. a quote to break out of an HTML
attribute, but I think I might be missing an easier path.

~~~
tptacek
Nope, that's how you do it. In the case I'm thinking of, I only needed one
character (but it needed to be the last byte).

------
aonic
In all my years of dealing with ugly and insecure PHP code, never have I seen
anyone using raw md5's in PHP

Sounds like a fabricated situation just for the game to me, versus something
trying to resemble real life situations. Not saying its not possible, but the
type of coders that would make a SQL injection oversight with something like
that would also not care to provide a non-default raw_output value to the
function for the heck of it

------
bl4k
I am more impressed by whoever came up with the challenge, although setting
the second parameter of md5 to 'true' made it obvious what the solution to the
puzzle was (nobody would ever have binary output on irl).

The French team came up with the solution quicker as they worked out that any
'=' would work - their keyspace search was thus an order of magnitude quicker:

<http://blog.nibbles.fr/2039>

~~~
sgronblo
I thought it required '='[^1-9] ? Because real 'password' = 'bogus crap' would
turn into 0 which would then be compared to a string starting with something
else than 1-9 which gets turned into a 0 as well.

------
photon_off
This might be only tangentially related, and I'm sure nearly everyone on HN
knows this, but salting MD5's is probably the easiest way to significantly
increase their security. By changing md5($var) to md5($var . "foo") this type
of attack could be prevented, assuming that the crackers don't have access to
the source code [in this challenge, they did].

To get an idea of what can be exposed if you don't salt, and thus use
predictable hashes, have a look here:
[http://www.google.com/#q=inurl:c4ca4238a0b923820dcc509a6f758...](http://www.google.com/#q=inurl:c4ca4238a0b923820dcc509a6f75849b)

md5(1) = c4ca4238...

~~~
timtadh
+1 to prodigal_erik

Also concatenating "foo" to the end of /every/ password is not salting your
hash. You need to have a suitably random string for it be considered salt.
Also you want to have a different random string for every password in your
database.

[+1 to tptacek for constantly saying don't write crypto code :-p]

~~~
photon_off
I should have noted that "foo" wasn't meant to be taken literally; clearly it
should be something that wouldn't show up in a dictionary. Even so, the point
was that _any_ salt is substantially better than none, and is easy to
implement.

------
philfreo
And it looks like an even faster solution, here, but in French.
<http://blog.nibbles.fr/2039>

~~~
gus_massa
Automatic Google Translation:
[http://translate.google.com/translate?js=n&prev=_t&h...](http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&layout=2&eotf=1&sl=fr&tl=en&u=http%3A%2F%2Fblog.nibbles.fr%2F2039&act=url)

------
sh1mmer
PHP contains filters for a reason. They are there to protect you.

While this was a clever challenge, in general you should sanitize all of your
input using filters.

~~~
pornel
Filtering of input is not appropriate way of ensuring that SQL queries are
safe, e.g. you'd be telling people named "O'Hara" that they're not SQL-
compatible or you'll fall into magic_quotes trap.

You should escape output.

In this case there isn't anything wrong with the input, and you can't say that
any byte of MD5 is wrong or dangerous.

It's just data that is used improperly.

Binary data in SQL queries is especially tricky, because strings may be
expected to be in specific character encoding (e.g. UTF-8), so you either need
to use prepared statements and pass argument explicitly as binary, or use
string-safe escaping (e.g. hex).

------
hackermom
This is all quite clever, but any wary developer makes sure to use either
properly sanitized inputs, or better still, prepared SQL statements (as f.e.
available through PHP's PDO method), so this trickery, no matter how clever,
is really not a big issue.

~~~
tptacek
"Any wary developer" ranks up there with "a sufficiently clever compiler"
among the True Scotsmen of our industry. I don't think you're right;
empirically, unsafe SQL is a very big issue, and the places where a QA team is
unlikely to stumble across injection vectors (ie, any vector where the string
"O'Malley" doesn't pop up an error to paste into a ticket) are worse still,
since teams don't find them.

~~~
frederique
i think you don't look outside your own "boxeola" too much. no all development
is done by a) clueless team that passes the software on to b) quality
assurance + bughunters. relying on or assuming that someone else will take
care of eventual loose ends is a very bad and ignorant approach to creating
software, and in my soon 15 years of experience as a european programmer this
is thankfully no where near the majority of cases.

~~~
tptacek
We're basically paid to look in other people's boxeolae.

Sorry, if your own personal experience suggests that most software is rigorous
with SQL and input validation, I think I have to assert a broader and more
accurate perspective on the issue. It feels statistically improbable to me
that we're just missing all the "good" software.

~~~
frederique
this could be a case of demographical difference. programming culture and
methods of approach is vastly different in europe, the americas, and asia as
indeed often told by migrating workers in our field. consequently we can
assert that it is equally likely that it is just you who have a narrow and
selfserving perspective of your business, and that there is more diversity out
there than what you specifically deal with for your living :-)

------
konad
I know there was already a shorter solution but

instead of '||'[1-9]

one could have searched for

'!=' or '<>' thus opening up the search space

