CVE 2023-0567
В ПХП нашли достаточно серьёзный, на мой взгляд, баг — на некоторых повреждённых хешах функция password_verify возвращает true на любой пароль. Получается, хитрый хакер может оставить себе тайный ход — поменять в базе хеш на битый, и пользователь ничего не заметит — пароль-то по-прежнему подходит.
Вот как это выглядит:
var_dump(password_verify("foo", '$2y$04$00000000$')); // true
var_dump(password_verify("bar", '$2y$04$00000000$')); // true
Удивляет, что один из разработчиков попытался защитить текущее поведение интерпретатора:
The documentation for password_verify() clearly states that the $hash has to be valid:
> hash
> A hash created by password_hash().I fail to see how this is a bug if you feed it garbage; also the documentation to crypt states:
> Using characters outside of this range in the salt will cause crypt() to return a zero-length string. The two digit cost parameter is the base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithm and must be in range 04-31, values outside this range will cause crypt() to fail.
PHP clearly behaves as described.
Что бы ни было написано в документации, возвращать true на любой пароль из функции проверки правильности пароля — очень плохая идея, как мне кажется, это должно быть довольно очевидно.
При анализе оказалось, что баг занесён ещё в 2008-м году (!), причём исследовавший эту историю разработчик хоть и осторожен в выражениях, всё же похоже считает, что уязвимость появилась неслучайно:
PHP’s implementation of crypt_blowfish differs from the upstream Openwall version by adding a «PHP Hack», which allows one to cut short the BCrypt salt by including a $ character within the characters that represent the salt.
Hashes that are affected by the «PHP Hack» may erroneously validate any password as valid when used with password_verify and when comparing the return value of crypt() against the input.
The PHP Hack exists since the first version of PHP’s own crypt_blowfish implementation that was added in 1e820ec.
No clear reason is given for the PHP Hack’s existence. This commit removes it, because BCrypt hashes containing a $ character in their salt are not valid BCrypt hashes.