PHP bug: Password_verify() always return true with some hash
bugs.php.net
bugs.php.net
Returning the input unmodified is not failure, but success. That's how you check that a password is valid without having a specialized API.
<strike>crypt is the hashing function, not the password checking function</strike>
So returning the original hash for a valid password is the success case.
What an awful response to someone reporting a pretty serious security vulnerability.
If you've never been on the other end of this - the number of false security reports with minimal details popular open source projects get are staggering. Many are unrealistic. People saying things like, if i give the attacker my password then the attacker has my password.
Assigning impact, even only as a measure of risk, is not the responsibility of the reporter.
A reporter must provide a fair description and a proof of concept. Calculating impact involves much more than that.
Hell, without impact, its not even a normal bug, let alone a security bug. The fundamentals of a bug report are "I expect X to happen when I do Y, but instead Z happens". Without impact, all you are saying is "I expect X to happen".
That seems fine to me, not every programming language has to be defensive about bad inputs, lord knows C isn’t. It seems like he got caught between two conflicting pieces of documentation one having stronger guarantees.
If they have write access they can already just set the hash to a known value for the same result.
It’s a bug certainly but of very little practical security concern.
I wonder how long it would take for someone to spot and report “I entered my password wrong and it worked anyway”
I was thinking of an attacker with specific goals of accessing things who doesn’t want to be found out.
Your hypothetical attacker would be more of a general chaos agent.
I have certainly encountered far more of the latter.
seems to be caused by a strange non-std php-specific crypto implementation
> The “PHP Hack” exists since the very first version of PHP’s own crypt_blowfish implementation and no clear reasoning is given for its existence in the commentary or commit history.
As the advisory states I don't know about the why, but I have a suspicion. PHP initially didn't implement BCrypt itself, but delegated to the system crypt, making the behavior of crypt() system-dependent. Now the PHP manual for crypt() showcases this example:
crypt('rasmuslerdorf', '$2a$07$usesomesillystringforsalt$');
which uses a horrible salt that incidentally ends with a dollar sign. I suspect to keep compatibility for users that thought the dollar sign would be necessary at the end of the salt, the “PHP Hack” was included.In fact such broken hashes appear to actually exist in the wild as showcased by this Stack Overflow question: https://stackoverflow.com/q/75519073/782822
But gosh, between this and the sha with null truncating bcrypt bug, php has had bad luck implementing password routines.
> In PHP 8.0.X before 8.0.28, 8.1.X before 8.1.16 and 8.2.X before 8.2.3, password_verify() function may accept some invalid Blowfish hashes as valid. If such invalid hash ever ends up in the password database, it may lead to an application allowing any password for this entry as valid.
[0] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0567
Again - how would that possibly be a security vulnerability? Like, its a really interesting security adjacent bug, but clearly not a security issue.
If the attacker has the ability to set a hash, they can just set the hash to a known password.
The one thing this does get you is that the original password would still work (technically any password would still work) so it may make it harder to detect since the user wouldn't "suddenly be locked out"...
I would first of all, wonder why i would want that. Why access someone's account when i could just dump the DB. Obviously it depends on context, but most of the time, DB access is more valuable than account access.
I would check if the DB is misconfigured (e.g. In mysql, does the DB user have File or Super rights?)
I would dump all the passwords and see if anyone's is weak enough to suffer from a crack attempt
I would check if there is anything in the DB that looks like php serialized data (People are saying unfair things about PHP like it being the king of sql injection, but its probably fair to say that unsafe deserialization is pretty common in php).
As a last resort, i would check if there is anything that looks like HTML or JS in the database, and see if i could get an XSS to leverage into an account take over.
you could say the same about python, javascript, ruby.. didn't implement a calculator at high school in C++?
> the king of SQL injections
that would be bob https://xkcd.com/327/
That requires the attacker top also have access to the salt
I smell an underlying sentiment of "if the attacker has access to the DB, then it is broken anyways". This is not entirely true. Think a gateway service that lets the user to something on another service with access without access to the database immediately giving access to the system.
This is definitely a security bug.
To be more clear, my position is - if the service allows you to set the password for an arbitrary user, then it is broken anyways.
Either you allow bcrypt hashes, or this bug is inapplicable. If you are encrypting your hashes or something, then this bug cannot be leveraged.
Which you must presume they do. If any part of your security relies on the salt being secret, that's a much bigger vulnerability than this.
That said, I do think there's a potential vulnerability here, because it allows you to break in if you can only corrupt another user's password hash (rather than controlling it entirely). Think a rowhammer attack or something.
For example, a service might import hashed passwords from a directory, and an attacker has limited influence on the network connection to cause some random-ish data corruption.
> Like, its a really interesting security adjacent bug, but clearly not a security issue.
I kinda disagree. We often think of security in layers, and an unexpected fail-open behavior in any layer should be treated as a (potential) security issue.
The impact might be low because you expect another layer (like protection of the password database) to prevent exploits, but there could always be corner cases where that assumption doesn't hold 100%, especially in something as fundamental as a language built-in, a system call or something like that.
So IMHO it's pretty low severity, but still a security issue.
Why are all bugs security bugs? Because security depends on the actual behaviour of the software, and bugs cause this behaviour to deviate from your intended and documented behaviour in unknown ways which means they have unknown impact on security. Figuring out whether any user of the software actually incurs a security impact as a result of any particular bug is likely to be far more work than fixing it, so just fix it.
Which is not at all what I was getting at. Again, don't spend time trying to argue why this or that bug is probably fine actually and not "really" a security problem, fix it and then it isn't.
This issue is caused by a PHP specific modification to the crypt_blowfish implementation
that is fittingly named “PHP hack”:
php-src/ext/standard/crypt_blowfish.c
Line 374 in 2740920
if (tmp == '$') break; /* PHP hack */
Cheeky hacker.The first comment on the bug report is pretty depressing.
I mean, i suppose, but such a setup is so broken does it matter?
PHP reminds me of my socially awkward uncle who is endearing and means well and caused many cringes & me and my sister to laugh with his faux pas.
I love reading articles about its bugs. The Mr Bean of programming languages.
We need PHP just as the film industry needs its gaffer tape. It's just that we have a very good standard of Gaffer tape (357 or "perl" in programming). It is kinda expensive though in dollars or cognitive cycles. So sometimes we use the inferior stuff that is not the standard 357. But then, we find, after the film bumps out - it caused you to rip the paint off the floor in the venue the film hired and not get your $10,000k deposit back.
We need to have our humour.
There will be a few HN commenters who say they still use Laravel or something, but in reality it's a tiny percentage of people using it now.
Something I found the other day, typed parameters won't error if you change the type, even with strict_types turned on:
function foo(string $foo) {
$foo = 10;
}Do I think dynamic languages are terrible and hate all three of the above? Yes.
Do I think modern, idiomatic PHP still suffers from most of TFA's examples of bad design? No.
P.H.P
DYNAMITE