Comment by kazinator
20 hours ago
Not really. This issue is caused purely by the handling of the too-long input in the wrong way.
Firstly, why do crypt functions return a valid string to indicate an error? The problem is that the classic null return makes some programs crash which are not expecting it.
musl has a correct protocol for the error string, similar to the *0/*1 convention. It also uses two symbols, * and +. If the salt string is *, then it uses \+ specifically to thwart this issue: the program blindly assuming that the password is correct because the output of the function matches the hashed password field.
Where it seems they screwed up is this:
crypt("long .... string", "*") -> "*"
I.e. in this special anti-DDoS measure that checks for a too long input, they forgot to implement the key piece of logic that the output of the function, when an error is being reported, must be different from its second argument (the "salt", which is usually the entire hashed password or the contents of that field from a password file).
What we want is:
crypt("long .... string", "*") -> "+"
crypt("long .... string", "+") -> "*"
Thus the application ends up comparing "*" and "+", or "+" and "*" so the authentication fails.
Under no circumstances should "*" be returned when the second argument is "*", or "+" when it is "+", because it must be assumed that the app doesn't do any sanity checking, and blindly compares the second argument to the return value.
musl does implement it this way.
However OpenSSH passes a different hash to musl’s crypt() than what it later uses to compare, so musl doesn’t switch to the alternate return output because from its perspective, it’s already guaranteed not to accidentally compare the same as the input hash.