[Bug 1574911] Re: my_make_scrambled_password() is not a replacement for make_scrambled_password()
Andreas Hasenack
andreas at canonical.com
Tue May 16 21:04:15 UTC 2017
** Description changed:
artful libpam-mysql-0.8.0-1
pam_mysql, when crypt=2 is set in its configuration, it expects the
password to be hashed according to the server-side PASSWORD() SQL
function. From its README:
2 (or "mysql") = Use MySQL PASSWORD() function. It is possible that the
encryption function used by PAM-MySQL is different from that of the
MySQL server, as PAM-MySQL uses the function defined in MySQL's C-client
API instead of using PASSWORD() SQL function in the query.
pam_mysql is indeed using an incorrect hash function: it's using
my_make_scrambled_password() as a replacement for
make_scrambled_password() to locally hash the given password and compare
it with what is stored in the database:
- char buf[42];
- my_make_scrambled_password(buf, passwd, strlen(passwd));
- vresult = strcmp(row[0], buf);
+ char buf[42];
+ my_make_scrambled_password(buf, passwd, strlen(passwd));
+ vresult = strcmp(row[0], buf);
row[0] is the result of the SQL query that fetches the user's password
hash
There are two problems with this:
a) my_make_scrambled_password() writes CRYPT_MAX_PASSWORD_SIZE bytes to buf, and that's way more than 42. From the mysql source code:
#define CRYPT_SALT_LENGTH 20
#define CRYPT_MAGIC_LENGTH 3
#define CRYPT_PARAM_LENGTH 13
#define SHA256_HASH_LENGTH 43
#define CRYPT_MAX_PASSWORD_SIZE (CRYPT_SALT_LENGTH + \
- SHA256_HASH_LENGTH + \
- CRYPT_MAGIC_LENGTH + \
- CRYPT_PARAM_LENGTH)
+ SHA256_HASH_LENGTH + \
+ CRYPT_MAGIC_LENGTH + \
+ CRYPT_PARAM_LENGTH)
42 is the length of the hexified hash produced by
make_scrambled_password(), not my_make_scrambled_password().
b) the output of my_make_scrambled_password() is not a hex string like
"*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19", but something like
"$5$9Ws#033Q.TZtI4^?X#026y@@{e2$OxTGgW3PiJUVZ/AChiJgAdIWQ2u2B8kA/hHZgqNj.y.".
So even if buf had the correct size, the comparison would never match
what's produced by PASSWORD() on the server side. As the documentation
admitted could happen.
-
- If my_make_scrambled_password() is not found in the system mysqlclient library, pam_mysql will reimplement it, and funnily enough this reimplementation actually mimicks the desired behavior of make_scrambled_password() and produces an hexified hash compatible with the server's PASSWORD() function and with the right length of 42 bytes.
+ If my_make_scrambled_password() is not found in the system mysqlclient
+ library, pam_mysql will reimplement it, and funnily enough this
+ reimplementation actually mimicks the desired behavior of
+ make_scrambled_password() and produces an hexified hash compatible with
+ the server's PASSWORD() function and with the right length of 42 bytes.
So, if mysqlclient doesn't export my_make_scrambled_password(),
pam_mysql will work because it will use its own implementation. But in
the ubuntu case, my_make_scrambled_password() is exported and used, and
leads to this bug.
To reproduce this problem, setup mysql, vsftpd and libpam-mysql on
artful as explained in bug #1574900.
+
+ I cannot explain why vsftpd doesn't crash in this scenario in artful:
+ gcc's stack protector isn't triggered, nor is a segfault. In debugging I
+ can see the buf variable getting way more than 42 bytes written to it,
+ and if I add another stack variable next to it, it gets corrupted. But
+ no crashes, just an authentication error.
** Description changed:
artful libpam-mysql-0.8.0-1
+
+ TL;DR
+
+ pam_mysql in artful will in the best case scenario just fail to
+ authenticate users whose passwords were hashed with the server-side
+ PASSWORD() SQL function. There is a buffer overflow happening, but it
+ doesn't trigger a crash for some reason.
+
+ Detailed explanation follows.
pam_mysql, when crypt=2 is set in its configuration, it expects the
password to be hashed according to the server-side PASSWORD() SQL
function. From its README:
2 (or "mysql") = Use MySQL PASSWORD() function. It is possible that the
encryption function used by PAM-MySQL is different from that of the
MySQL server, as PAM-MySQL uses the function defined in MySQL's C-client
API instead of using PASSWORD() SQL function in the query.
pam_mysql is indeed using an incorrect hash function: it's using
my_make_scrambled_password() as a replacement for
make_scrambled_password() to locally hash the given password and compare
it with what is stored in the database:
char buf[42];
my_make_scrambled_password(buf, passwd, strlen(passwd));
vresult = strcmp(row[0], buf);
row[0] is the result of the SQL query that fetches the user's password
hash
There are two problems with this:
a) my_make_scrambled_password() writes CRYPT_MAX_PASSWORD_SIZE bytes to buf, and that's way more than 42. From the mysql source code:
#define CRYPT_SALT_LENGTH 20
#define CRYPT_MAGIC_LENGTH 3
#define CRYPT_PARAM_LENGTH 13
#define SHA256_HASH_LENGTH 43
#define CRYPT_MAX_PASSWORD_SIZE (CRYPT_SALT_LENGTH + \
SHA256_HASH_LENGTH + \
CRYPT_MAGIC_LENGTH + \
CRYPT_PARAM_LENGTH)
42 is the length of the hexified hash produced by
make_scrambled_password(), not my_make_scrambled_password().
b) the output of my_make_scrambled_password() is not a hex string like
"*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19", but something like
"$5$9Ws#033Q.TZtI4^?X#026y@@{e2$OxTGgW3PiJUVZ/AChiJgAdIWQ2u2B8kA/hHZgqNj.y.".
So even if buf had the correct size, the comparison would never match
what's produced by PASSWORD() on the server side. As the documentation
admitted could happen.
If my_make_scrambled_password() is not found in the system mysqlclient
library, pam_mysql will reimplement it, and funnily enough this
reimplementation actually mimicks the desired behavior of
make_scrambled_password() and produces an hexified hash compatible with
the server's PASSWORD() function and with the right length of 42 bytes.
So, if mysqlclient doesn't export my_make_scrambled_password(),
pam_mysql will work because it will use its own implementation. But in
the ubuntu case, my_make_scrambled_password() is exported and used, and
leads to this bug.
To reproduce this problem, setup mysql, vsftpd and libpam-mysql on
artful as explained in bug #1574900.
I cannot explain why vsftpd doesn't crash in this scenario in artful:
gcc's stack protector isn't triggered, nor is a segfault. In debugging I
can see the buf variable getting way more than 42 bytes written to it,
and if I add another stack variable next to it, it gets corrupted. But
no crashes, just an authentication error.
--
You received this bug notification because you are a member of Ubuntu
Server Team, which is subscribed to the bug report.
https://bugs.launchpad.net/bugs/1574911
Title:
my_make_scrambled_password() is not a replacement for
make_scrambled_password()
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/pam-mysql/+bug/1574911/+subscriptions
More information about the Ubuntu-server-bugs
mailing list