Bug #78680 [PATCH]: mysqlnd's mysql_clear_password does not transmit null-terminated password

From: Date: Fri, 05 Feb 2021 21:38:51 +0000
Subject: Bug #78680 [PATCH]: mysqlnd's mysql_clear_password does not transmit null-terminated password
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-231962@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=78680&edit=1

 ID:                 78680
 Patch added by:     geoff.montee@gmail.com
 Reported by:        geoff dot montee at gmail dot com
 Summary:            mysqlnd's mysql_clear_password does not transmit
                     null-terminated password
 Status:             Open
 Type:               Bug
 Package:            MySQLi related
 Operating System:   Alpine Linux v3.10
 PHP Version:        7.3.10
 Block user comment: N
 Private report:     N

 New Comment:

The following pull request has been associated:

Patch Name: Fix #78680: mysqlnd pam plugin missing terminating null
On GitHub:  https://github.com/php/php-src/pull/6667
Patch:      https://github.com/php/php-src/pull/6667.patch


Previous Comments:
------------------------------------------------------------------------
[2021-01-13 16:36:33] cmb@php.net

Well, that looks indeed wrong in mysqldn.  Would you mind to
provide a pull request[1]?

[1] <https://github.com/php/php-src/pulls>

------------------------------------------------------------------------
[2019-10-17 19:34:45] 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

------------------------------------------------------------------------
[2019-10-17 18:47:07] 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



------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=78680&edit=1


Thread (5 messages)

« previous php.bugs (#231962) next »