MySQL UDF提权本质是利用高权限MySQL进程加载恶意动态库执行系统命令,需INSERT/CREATE FUNCTION权限及文件读取权限;禁用方式包括设置plugin_dir为无效路径、启用--disable-plugin=udf或删除示例UDF文件。

MySQL UDF提权的本质是什么
UDF(User Defined Function)提权不是“调用一个函数就变root”,而是利用MySQL进程以高权限(通常是mysql用户,但可能被配置为root)运行的特性,加载恶意编译的动态库(.so或.dll),进而执行任意系统命令。关键前提是:攻击者需具备INSERT或CREATE FUNCTION权限,且MySQL服务进程有读取该动态库文件的权限(比如从/tmp或/var/lib/mysql下加载)。
彻底禁用UDF加载的实操方式
最直接有效的办法是启动时禁用自定义函数加载功能,而非依赖权限控制——因为只要CREATE FUNCTION权限存在,配合FILE权限或可写目录,仍可能绕过。
- 在
my.cnf的[mysqld]段中添加:secure_file_priv=/dev/null(限制LOAD_FILE()和SELECT ... INTO DUMPFILE,虽不直接禁UDF,但断掉常见payload落地路径) - 必须设置:
plugin_dir=/nonexistent/path(让MySQL找不到插件目录,使CREATE FUNCTION ... SONAME直接报错ERROR 1126 (HY000): Can't open shared library 'xxx.so'...) - 更彻底的做法:启动时加参数
--skip-grant-tables仅用于恢复场景;生产环境应配--disable-plugin=udf(MySQL 8.0.29+支持),或直接删除lib/plugin/udf_example.so等示例文件(但不能删lib/plugin/目录本身,否则影响其他插件)
FILE权限为什么必须严格管控
FILE权限本身不等于提权,但它让攻击者能:SELECT ... INTO OUTFILE写入动态库到MySQL可读路径,或LOAD DATA INFILE读取敏感文件辅助信息收集。一旦与UDF配合,就是完整链路。
- 回收所有非必要账号的
FILE权限:REVOKE FILE ON *.* FROM 'user'@'%'; - 检查当前哪些用户拥有该权限:
SELECT User,Host,File_priv FROM mysql.user WHERE File_priv='Y'; - 注意:
FILE是全局权限,无法按库/表收缩;哪怕只给SELECT权限的只读账号,若同时有FILE,也可能被利用
替代方案:用存储过程+系统表模拟受限系统调用
业务真需要“获取服务器时间”“读取配置”这类能力?别开放UDF,改用MySQL原生机制:
- 用
NOW()、SYSDATE()代替system("date") - 通过
INFORMATION_SCHEMA查连接数、慢查询状态,而不是system("ps aux | grep mysqld") - 如必须调外部命令(极少见),应在应用层做,由后端服务以最小权限账户执行,并严格校验参数,绝不经SQL透传
UDF从来就不是MySQL设计用来干系统管理的,把它当shell入口,等于主动拆掉沙箱墙。


















