Swift defense to latest MySQL/MariaDB/Percona vulnerability

On September 12, Security Research’s Dawid Golunkski publicly released CVE-2016–6662, identifying a privilege-escalation exploit affecting all versions of MySQL <= 5.7.14, 5.6.32, and 5.5.51. This includes all of the common forks such as MariaDB and Percona.

What can an attacker do with this exploit?

Taking advantage of this vulnerability, an attacker could conceivably perform the following nefarious hacks:

  • Modify MySQL’s behavior by creating or modifying configuration files.
  • Force MySQL to execute a malicious payload as root when the service starts, giving the attacker full system control.
  • Combine with a weakly configured file and MySQL permissions, to escalate his privilege to root both remotely and locally.

How does it work?

This vulnerability cleverly exploits how MySQL and its forks load configuration files and a configuration directive, malloc_lib.

At boot MySQL will look for configuration files in a few places, such as /etc/my.cnf, ~/.my.cnf and your data directory (/var/lib/mysql/my.cnf).

A common mistake that system administrators make is allowing configuration files to be owned or written to by the mysql user. Consequently, if an attacker can execute queries to create an evil my.cnf file, he can use malloc_lib to force MySQL to load a malicious library the next time the server is restarted.

The common mysqld_safe wrapper used by many distros is generally run as root; thus, the next time MySQL boots, the evil library will execute, giving the attacker root access to your server.

You may wonder how an attacker can get a copy of the malicious library dropped on the system and insert the evil payload into my.cnf? The CVE summarizes three methods that we explain below.

A blackhat hacker could:

1. Use SELECT INTO OUTFILE to write a malicious configuration file and library. This requires the SELECT/FILE permissions and only works for non-existing my.cnf files (such as /var/lib/mysql/my.cnf).

2. Use general_log_file to write to an existing configuration file or create one with the proper permissions for MySQL to load. Access can be gained with only the SELECT/FILE permissions, assuming the attacker can write to another configuration file first to give himself access to a privileged MySQL user.

3. Use triggers to set the general_log_file variable to an existing my.cnf.

Which package versions are safe/patched?

Percona releases
• 5.5.51–38.1
• 5.6.32–78.0
• 5.7.14–7

MariaDB releases
• 5.5.51
• 10.1.17
• 10.0.27

MySQL releases
• 5.7.15
• 5.6.33
• 5.5.51

How can I protect my server before an official patch is available?

Percona released an insightful blog post outlining steps you can take to harden the vulnerability.

We’ve also whipped up a little bash script you can use to help detect those configuration files and folders that may leave you open to attack. This script follows Percona’s advice, ensuring that any existing configuration files are not writable by MySQL and that any configuration files that do not exist at MySQL boot are created.

You will need to run this script as root since it will be using sudo -u mysql find {paths} -writable in order to find configuration files that are writable by MySQL.

#!/bin/bash
# Try and find where my.cnf are loaded from, otherwise guess
MYSQLD_OUT=$(mysqld — help — verbose 2>/dev/null)
DATADIR=$(echo “$MYSQLD_OUT” | grep “datadir “ | tr -s ‘ ‘ | cut -d’ ‘ -f 2)
DATADIR=${DATADIR:=/var/lib/mysql}
FILES=$(echo “$MYSQLD_OUT” | awk ‘f{print;f=0} /Default options are read/{f=1}’)
FILES=${FILES:=/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf}
FILES=”$FILES $DATADIR/my.cnf $DATADIR/.my.cnf”
DIRS=$(dirname $FILES | sort | uniq)
COMMON_INCLUDE_DIRS=”/etc/mysql /etc/my.cnf.d /usr/etc/mysql /usr/etc/my.cnf.d /usr/local/etc/my.cnf.d /usr/local/etc/mysql $DATADIR”
echo ‘Writable Configuration Files:’
(cd / ; sudo -u mysql find $FILES -type f -writable ; sudo -u mysql find $COMMON_INCLUDE_DIRS -type f -name “*.cnf” -writable ) 2>/dev/null
echo
echo “Missing Configuration Files: “
for file in $FILES; do if [ ! -e “$file” ]; then echo $file; fi; done;

*Edit: You can find the fixed raw copy from the author here.

Keep in mind, this script is just a quick check. It does does not scan your !includedir directives for additional configuration paths/files that might be vulnerable. You will have to inspect those manually. It does include common config paths/files, such as /etc/my.cnf.d, though.

Once you’ve double-checked your permissions, you should then:

  • Make sure remote root login is disabled and local root login requires a password. You can do this automatically with mysql_secure_instalation if it is available on your distro.
  • Ensure that no users have FILE or SUPER permissions, unless they need it (SHOW GRANTS FOR user@host).
  • Manually patch mysqld_safe using the Maciej Dobrzanski’s guide.

We hope you can use this information. If you’d like to comment, please do so below. If you’d like to share, please do so on social media.

Like what you read? Give Linode a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.