Ker
1. Kerberos "双跳"问题
当尝试跨两个(或更多)节点使用 Kerberos 认证时常会出现一个“双跳”问题的现象。该问题涉及 Kerberos 票据如何针对特定资源进行授权。
- Kerberos 票据不应被视作密码,而是由 KDC 签发的数据凭证,用于声明账户可访问的资源
- 执行 Kerberos 认证时,我们会获得一张允许访问目标资源
- 执行密码认证则会将NTLM哈希存储在会话中,并且可以在其他场景中无障碍使用
1.1. 背景
"双跳"问题在使用 WinRM/Powershell 时经常出现,因为默认的身份验证机制仅提供访问特定资源的票据。这在尝试进行横向移动甚至从远程 shell 访问文件共享时很可能会引发问题。在这种情况下,所使用的用户账户拥有执行操作的权限,但访问却被拒绝。
问题的关键在于,当使用 WinRM 通过两个或更多连接进行身份验证时,用户的密码永远不会作为登录的一部分被缓存。如果我们使用 Mimikatz 查看会话,会发现所有凭据都是空白的。
当我们使用 Kerberos 建立远程会话时,我们并未使用密码进行身份验证。而当使用密码认证时(例如使用 PSExec),NTLM 哈希值会存储在会话中,这样当我们访问另一个资源时,机器可以从内存中提取哈希值并为我们进行身份验证。
比如我们试用 WinRM通过身份认证登录到远程主机,然后运行mimikatz ,你会发现在内存中找不到我们认证用户的凭据,但是确可以发现远程主机上存在此用户的进程,比如wsmprovhost.exe(启动 Windows 远程 PowerShell 会话时生成的进程)
简单的说就是,我们的凭据无法在多服务器条件下,从一台机器发送到另外一台机器。
比如我们有三台主机: Attack host --> DEV01 --> DC01 ,我们已经获取到了一个域外主机的权限,并将其作为立足点。然后我们获取了一组域用户凭据,并发现其在 DEV01 上属于 Remote Management Users 组。我们希望使用 PowerView 来枚举域,这需要与域控制器 DC01 进行通信。
当我们使用诸如 evil-winrm 之类的工具连接到 DEV01 时,我们会通过网络身份验证进行连接,所以我们的凭据不会存储在内存中,系统中就没有此凭据,系统也无法代表用户去向其他资源发起身份验证。
当我们加载诸如 powerview 之类的工具并尝试查询 Active Directory 时,因为我们的TGT未发送到远程会话,所以用户无法向域控证明自己的身份,命令也不会在此用户的上下文中运行,也就无法访问到域中的资源。
换句话说,当向目标主机进行身份验证时,用户的票据授予服务(TGS)票证被发送到远程服务,从而允许命令执行,但用户的 TGT 票证并未发送。当用户尝试访问域中的后续资源时,其 TGT 不会出现在请求中,因此远程服务将无法证明身份验证尝试是有效的。
1.2. 例外:非约束委派
如果服务器上启用了非约束委派,很可能就不会遇到"双跳"问题。
在这种情况下,当用户发送其 TGS 票据以访问目标服务器时,他们的 TGT 票据将随请求一同发送。目标服务器现在内存中存有用户的 TGT 票据,并可在用户尝试访问下一台主机时代其请求 TGS 票据。换句话说,账户的 TGT 票据被缓存,该票据具备签署 TGS 票据并授予远程访问权限的能力。
但一般来说,如果你登陆的机器启用了无约束委派,实际上已经GameOver了,也不用再考虑这些了。
1.3. 解决方法
我们可以使用"嵌套" Invoke-Command 在每次请求时发送凭据(创建 PSCredential 对象后),这样当我们尝试从攻击主机向主机 A 进行身份验证并在主机 B 上运行命令时,就能获得许可。
1.3.1. 方法1: PSCredential 对象
通过主机 A 连接到远程主机,并设置一个 PSCredential 对象来再次传递我们的凭据
示例场景:通过凭据连接到主机后,我们试用powerview执行命令向域控查询SPN,出现了报错
*Evil-WinRM* PS C:\Users\backupadm\Documents> import-module .\PowerView.ps1
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
*Evil-WinRM* PS C:\Users\backupadm\Documents> get-domainuser -spn
Exception calling "FindAll" with "0" argument(s): "An operations error occurred.
"
At C:\Users\backupadm\Documents\PowerView.ps1:5253 char:20
+ else { $Results = $UserSearcher.FindAll() }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DirectoryServicesCOMException
通过klist命令发现只有当前服务器的Kerberos票据
*Evil-WinRM* PS C:\Users\backupadm\Documents> klist
Current LogonId is 0:0x57f8a
Cached Tickets: (1)
#0> Client: backupadm @ INLANEFREIGHT.LOCAL
Server: academy-aen-ms0$ @
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0xa10000 -> renewable pre_authent name_canonicalize
Start Time: 6/28/2022 7:31:53 (local)
End Time: 6/28/2022 7:46:53 (local)
Renew Time: 7/5/2022 7:31:18 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x4 -> S4U
Kdc Called: DC01.INLANEFREIGHT.LOCAL
然后我们通过 PSCredential 来再次尝试。首先设置一下身份验证
*Evil-WinRM* PS C:\Users\backupadm\Documents> $SecPassword = ConvertTo-SecureString '!qazXSW@' -AsPlainText -Force
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
*Evil-WinRM* PS C:\Users\backupadm\Documents> $Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\backupadm', $SecPassword)
然后再试用powerview查询SPN账户,发现成功了,因为我们在执行命令的同时,也传递了我们设置的身份验证。
*Evil-WinRM* PS C:\Users\backupadm\Documents> get-domainuser -spn -credential $Cred | select samaccountname
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
samaccountname
--------------
azureconnect
backupjob
krbtgt
mssqlsvc
sqltest
sqlqa
sqldev
mssqladm
svc_sql
sqlprod
sapsso
sapvc
vmwarescvc
如何我们不指定-credential再次尝试,会发现出现了报错
get-domainuser -spn | select
*Evil-WinRM* PS C:\Users\backupadm\Documents> get-domainuser -spn | select samaccountname
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
|S-chain|-<>-127.0.0.1:9051-<><>-172.16.8.50:5985-<><>-OK
Exception calling "FindAll" with "0" argument(s): "An operations error occurred.
"
At C:\Users\backupadm\Documents\PowerView.ps1:5253 char:20
+ else { $Results = $UserSearcher.FindAll() }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DirectoryServicesCOMException
此时,如果我们通过RDP链接到同一台主机,并通过klist查询会发现我们的票据已经被成功缓存了
1.3.2. 方法2:PSSession 配置
方法1主要讲的是如何在诸如 evil-winrm这类工具通过WINRM连接到主机的解决方法。
但是如果我们已经处于一个域内,并且可以通过WINRM链接到另一台主机,或者我们正在从一台Windows攻击机试用Enter-PSSession cmdlet通过WINRM连接到我们的目标。 这种情况下,我们还有另一种方式来改变我们的设置使得可以直接与域控、其他资源。主机进行交互,且无需设置PSCredential 对象并在每个命令中携带此凭据
首先在远程主机建立一个WINRM会话
PS C:\htb> Enter-PSSession -ComputerName ACADEMY-AEN-DEV01.INLANEFREIGHT.LOCAL -Credential inlanefreight\backupadm
此时用klist会发现,因为双跳问题,我们的凭据并没有缓存在此机器上,我们只能与当前会话中的资源进行交互,无法使用powerview访问域控,
[ACADEMY-AEN-DEV01.INLANEFREIGHT.LOCAL]: PS C:\Users\backupadm\Documents> klist
Current LogonId is 0:0x11e387
Cached Tickets: (1)
#0> Client: backupadm @ INLANEFREIGHT.LOCAL
Server: HTTP/ACADEMY-AEN-DEV01.INLANEFREIGHT.LOCAL @ INLANEFREIGHT.LOCAL KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 6/28/2022 9:09:19 (local)
End Time: 6/28/2022 19:09:19 (local)
Renew Time: 0
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x8 -> ASC
Kdc Called:
我们当前的 TGS 可以访问目标上的 HTTP 服务,因为WinRM 使用 XML 格式的 SOAP(简单对象访问协议)请求通过 HTTP 进行通信,所以我们是可以通过 WinRM 连接的。 这很合理
但是我们也是无法与DC进行交互的
PS C:\Users\backupadm\Documents> Import-Module .\PowerView.ps1
PS C:\Users\backupadm\Documents> get-domainuser -spn | select samaccountname
Exception calling "FindAll" with "0" argument(s): "An operations error occurred.
"
At C:\Users\backupadm\Documents\PowerView.ps1:5253 char:20
+ else { $Results = $UserSearcher.FindAll() }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DirectoryServicesCOMException
然后我们通过 Register-PSSessionConfiguration cmdlet 注册新的会话配置
PS C:\htb> Register-PSSessionConfiguration -Name backupadmsess -RunAsCredential inlanefreight\backupadm
WARNING: When RunAs is enabled in a Windows PowerShell session configuration, the Windows security model cannot enforce
a security boundary between different user sessions that are created by using this endpoint. Verify that the Windows
PowerShell runspace configuration is restricted to only the necessary set of cmdlets and capabilities.
WARNING: Register-PSSessionConfiguration may need to restart the WinRM service if a configuration using this name has
recently been unregistered, certain system data structures may still be cached. In that case, a restart of WinRM may be
required.
All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session
configurations that are created with the Register-PSSessionConfiguration cmdlet, are disconnected.
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin
Type Keys Name
---- ---- ----
Container {Name=backupadmsess} backupadmsess
执行完成后,再在PSSession中执行 Restart-Service WinRM ,然后再次链接的时候就会用之前设置的注册会话启用一个新的PSSession,在这个新会话中,主机已缓存了我们的票据,所以双跳问题也成功解决
PS C:\htb> Enter-PSSession -ComputerName DEV01 -Credential INLANEFREIGHT\backupadm -ConfigurationName backupadmsess
[DEV01]: PS C:\Users\backupadm\Documents> klist
Current LogonId is 0:0x2239ba
Cached Tickets: (1)
#0> Client: backupadm @ INLANEFREIGHT.LOCAL
Server: krbtgt/INLANEFREIGHT.LOCAL @ INLANEFREIGHT.LOCAL
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
Start Time: 6/28/2022 13:24:37 (local)
End Time: 6/28/2022 23:24:37 (local)
Renew Time: 7/5/2022 13:24:37 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x1 -> PRIMARY
Kdc Called: DC01
这样我们就可以不用创建 PSCredential对象,直接运行如powerview之类的工具了
注意: 无法在 evil-winrm shell 中使用 Register-PSSessionConfiguration,因为这样无法弹出凭据输入窗口。此外,如果尝试先创建一个 PSCredential 对象,然后通过传递凭据(如使用 -RunAsCredential $Cred 参数)来运行该命令,系统会报错,因为 RunAs 只能在提权的 PowerShell 终端中使用。因此,由于该方法需要 GUI 交互界面和规范的 PowerShell 控制台,在 evil-winrm 会话中是行不通的。
此外,在我们的测试中,由于 Linux 版 PowerShell 在处理 Kerberos 凭据时存在某些局限性,该方法也无法在 Parrot 或 Ubuntu 攻击机上运行。不过,如果你是从 Windows 攻击机进行测试,或者已经攻陷了一台主机并能通过 RDP(远程桌面)连接将其作为“跳板机”,进而对环境中的其他主机发起进一步攻击,那么这种方法依然非常有效。
