Magic hashes – PHP hash "collisions"
Switch branches/tags
Nothing to show
Clone or download
Latest commit 0a87d16 Jun 16, 2018

Magic hashes – PHP hash "collisions"

Register with password 1 and then sign in with password 2. If you're in then the storage uses specified algorithm to hash the password and PHP uses == to compare them (for MD5, SHA-1, and plaintext).

MD5 and SHA-1

For MD5 and SHA-1, it uses the long-known trick (it actually is a documented feature, see PHP type comparison tables & Floating point numbers) that for PHP '0e1' == '00e2' == '0', it just uses it for practical purposes. Any password matches any other password from the list. This is a different trick than integral strings overflowing into floating point numbers, just spot the difference between these two lines.


For plaintext, it uses various conversion tricks. First password will match just the second one. Tricks are grouped by PHP versions allowing them.


bcrypt truncates passwords to a maximum length of 72 characters. The passwords match if the first 72 characters of both passwords match.


If you use a password longer than 64 bytes and hash it with PBKDF2-HMAC-SHA1, it is first pre-hashed with SHA1, so PBKDF2-HMAC-SHA1(password1) === PBKDF2-HMAC-SHA1(password2) because sha1(password1) === bin2hex(password2).


Use === when comparing anything* in PHP, not ==. And use password_hash() and password_verify() for password hashing in PHP, don't use MD5 or SHA-1. *Use hash_equals() when comparing hashes.


It all started with this tweet, I've generated QNKCDZO and 240610708 in February 2014 and it has since spread all over the intertubes. Just google it.