Bug #78680 [NEW]: mysqlnd's mysql_clear_password does not transmit null-terminated password
| From: | geoff dot montee at gmail dot com | Date: | Thu, 17 Oct 2019 18:47:07 +0000 |
| Subject: | Bug #78680 [NEW]: mysqlnd's mysql_clear_password does not transmit null-terminated password | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-223224@lists.php.net to get a copy of this message | ||
From: geoff dot montee at gmail dot com
Operating system: Alpine Linux v3.10
PHP version: 7.3.10
Package: MySQLi related
Bug Type: Bug
Bug description:mysqlnd's mysql_clear_password does not transmit null-terminated password
Description:
------------
The mysql_clear_password client authentication plugin is supposed to
transmit a null-terminated password to the server. This is described in
the following code comment:
" @startuml
Server->Client: 20 bytes of scramble to be ignored
Client->Server: The clear text password. null terminated.
@enduml"
https://github.com/mysql/mysql-server/blob/mysql-8.0.18/sql-common/client.cc#L8469
PHP's implementation of mysql_clear_password in the mysqlnd driver does
not seem to transmit the terminating NULL character with the password.
See here:
https://github.com/php/php-src/blob/php-7.3.10/ext/mysqlnd/mysqlnd_auth.c#L610
https://github.com/php/php-src/blob/php-7.3.10/ext/mysqlnd/mysqlnd_auth.c#L115
This can easily be reproduced.
---
Let's say that I have a server running MariaDB 10.4.8. We can configure
PAM authentication by performing the following steps:
1.) Create a Unix user account and set a password for the user:
sudo useradd alice
sudo passwd alice
The examples below assume that the password is "uGBXHxID3dJRALw2".
2.) Create the PAM service configuration:
sudo tee /etc/pam.d/mariadb <<EOF
auth required pam_unix.so audit
account required pam_unix.so audit
EOF
3.) Install the pam plugin:
sudo mysql --execute="INSTALL SONAME 'auth_pam'"
4.) Create the relevant user:
sudo mysql --execute="CREATE USER 'alice'@'localhost' IDENTIFIED VIA pam
USING 'mariadb'"
5.) Enable the pam_use_cleartext_plugin system variable:
$ sudo mysql -u root --execute="SHOW GLOBAL VARIABLES LIKE 'pam%'"
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| pam_use_cleartext_plugin | ON |
| pam_winbind_workaround | OFF |
+--------------------------+-------+
At this point, PAM is configured.
---
Let's say that I set up PHP 7.3.10 on the same server as the database.
The connectivity can easily be tested by creating the following test
script:
tee pamtest.php << EOF
<?php
\$link = mysqli_connect("127.0.0.1", "alice", "uGBXHxID3dJRALw2",
"test");
if (!\$link) {
echo "Error: Unable to connect to MySQL." . PHP_EOL;
echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL;
echo "Debugging error: " . mysqli_connect_error() . PHP_EOL;
exit;
}
echo "Success: A proper connection to MySQL was made! The my_db database
is great." . PHP_EOL;
echo "Host information: " . mysqli_get_host_info(\$link) . PHP_EOL;
mysqli_close(\$link);
?>
EOF
php -f pamtest.php
---
So let's run the test script, and do some debugging.
1.) First, let's attach strace to the mysqld process:
sudo mkdir strace/
cd strace/
sudo strace -o strace.out -f -ff -p $(pidof mysqld)
2.) And then let's also run the PHP script while attaching strace to
that process:
strace -o strace.out -f -ff php -f pamtest.php
Authentication will fail on MariaDB 10.4.8, since that MariaDB version
currently treats the NULL terminating character as mandatory:
Warning: mysqli_connect(): (HY000/1045): Access denied for user
'alice'@'localhost' (using password: NO) in /var/www/html/pamtest.php on
line 2
Error: Unable to connect to MySQL.
Debugging errno: 1045
Debugging error: Access denied for user 'alice'@'localhost' (using
password: NO)
The strace output of the PHP script shows that the NULL terminating
character is not set:
./strace.out.3393-recvfrom(3, "\26\0\0\2\376mysql_clear_password\0",
32768, MSG_DONTWAIT, NULL, NULL) = 26
./strace.out.3393:sendto(3, "\20\0\0\3uGBXHxID3dJRALw2", 20,
MSG_DONTWAIT, NULL, 0) = 20
And the strace output of mysqld shows the same thing:
sendto(154, "\26\0\0\2\376mysql_clear_password\0", 26, MSG_DONTWAIT,
NULL, 0) = 26
recvfrom(154, "\20\0\0\3", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(154, "uGBXHxID3dJRALw2", 16, MSG_DONTWAIT, NULL, NULL) = 16
In contrast, here's the strace output of mysqld with a "working"
client:
sendto(154, "\26\0\0\2\376mysql_clear_password\0", 26, MSG_DONTWAIT,
NULL, 0) = 26
recvfrom(154, "\21\0\0\3", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(154, "uGBXHxID3dJRALw2\0", 17, MSG_DONTWAIT, NULL, NULL) = 17
--
Edit bug report at https://bugs.php.net/bug.php?id=78680&edit=1
--
Fix committed: https://bugs.php.net/fix.php?id=78680&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=78680&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=78680&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=78680&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=78680&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=78680&r=support
Expected behavior: https://bugs.php.net/fix.php?id=78680&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=78680&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=78680&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=78680&r=globals
PHP version support discontinued: https://bugs.php.net/fix.php?id=78680&r=phptooold
Daylight Savings: https://bugs.php.net/fix.php?id=78680&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=78680&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=78680&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=78680&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=78680&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=78680&r=mysqlcfg