php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78680 mysqlnd's mysql_clear_password does not transmit null-terminated password
Submitted: 2019-10-17 18:47 UTC Modified: -
From: geoff dot montee at gmail dot com Assigned:
Status: Open Package: MySQLi related
PHP Version: 7.3.10 OS: Alpine Linux v3.10
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-10-17 18:47 UTC] geoff dot montee at gmail dot com
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


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-10-17 19:34 UTC] geoff dot montee at gmail dot com
This problem was discovered due to the following two MariaDB bug reports:

https://jira.mariadb.org/browse/MDEV-19882

https://jira.mariadb.org/browse/MDEV-20571
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Sat Nov 16 21:01:32 2019 UTC