利用普通用户账户攻击RBCD的技术解析

本文详细分析了如何利用普通用户账户通过资源基于约束委派(RBCD)进行权限提升的技术原理,包括S4U扩展、U2U票据和密码修改等技术细节,揭示了在RC4加密仍启用环境下的一种新型攻击向量。

利用普通用户账户攻击RBCD*

*适用注意事项

资源基于约束委派(RBCD)权限提升技术,由Elad Shamir在"Wagging the Dog"博客文章中首次描述,是一种利用Kerberos在本地Windows机器上提升权限的巧妙方法。该方法只需要对本地计算机的域账户具有写权限,即可修改msDS-AllowedToActOnBehalfOfOtherIdentity LDAP属性,添加其他账户的SID。然后,您可以使用该账户通过服务为用户(S4U)协议获取本地机器的Kerberos服务票据,包括本地管理员在内的域内任何用户。

关键问题是如何在本地计算机的域账户下写入LDAP服务器。已有各种方法通常滥用身份验证中继。例如,我描述过一种滥用DCOM的中继向量。其他人随后将其整合到一个交钥匙工具KrbRelayUp中。

此攻击生效的另一个条件是能够访问另一个计算机账户来执行攻击。严格来说这并不完全正确,因为有影子凭证攻击允许您重用相同的本地计算机账户,但通常您需要一个您控制的计算机账户。通常这不是问题,因为DC允许普通用户创建新的计算机账户,上限由域的ms-DS-MachineAccountQuota属性值设置。此属性默认为10,但管理员可以将其设置为0来阻止攻击,这可能是推荐的做法。

但我想知道为什么这不能作为普通用户工作。msDS-AllowedToActOnBehalfOfOtherIdentity属性只需要允许委派到计算机的账户的SID。为什么我们不能只添加用户的SID并执行S4U流程?为了给我们最好的机会,我假设我们知道用户的密码,您如何获得这完全取决于您。通过Rubeus运行攻击显示了我们的问题。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS C:\> Rubeus.exe s4u /user:charlie /domain:domain.local /dc:primarydc.domain.local /rc4:79bf93c9501b151506adc21ba0397b33 /impersonateuser:Administrator /msdsspn:cifs/WIN10TEST.domain.local
   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

 v2.0.3

[*] Action: S4U

[*] Using rc4_hmac hash: 79bf93c9501b151506adc21ba0397b33
[*] Building AS-REQ (w/ preauth) for: 'domain.local\charlie'
[*] Using domain controller: 10.0.0.10:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
      doIFc...
[*] Action: S4U
[*] Building S4U2self request for: 'charlie@DOMAIN.LOCAL'
[*] Using domain controller: primarydc.domain.local (10.0.0.10)
[*] Sending S4U2self request to 10.0.0.10:88
[X] KRB-ERROR (7) : KDC_ERR_S_PRINCIPAL_UNKNOWN
[X] S4U2Self failed, unable to perform S4U2Proxy.

我们甚至没有通过攻击的第一个S4U2Self阶段,它以KDC_ERR_S_PRINCIPAL_UNKNOWN错误失败。此错误通常表示KDC不知道为生成的票据使用什么加密密钥。但是,如果您向用户账户添加SPN,一切都会成功。这意味着这不是用户账户本身的问题,而是KDC无法选择正确密钥的问题。

从技术上讲,如果您请求其UPN的票据,KDC没有理由不能使用用户的长期密钥,但它没有(与我前几天在/r/netsec上与某人的争论相反,该人坚持认为SPN是便利性的问题,而不是Kerberos的基本要求)。

那么该怎么办?有一种通过使用用户到用户(U2U)扩展获取为UPN加密的票据的方法。这在这里有效吗?查看Rubeus代码,似乎支持请求U2U S4U2Self票据,但未为S4U攻击设置参数。让我们设置这些参数来请求U2U票据,看看是否有效。

1
2
3
4
5
6
7
8
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'charlie@DOMAIN.LOCAL'
[*] base64(ticket.kirbi): doIF...bGll
[*] Impersonating user 'Administrator' to target SPN 'cifs/WIN10TEST.domain.local'
[*] Building S4U2proxy request for service: 'cifs/WIN10TEST.domain.local'
[*] Using domain controller: primarydc.domain.local (10.0.0.10)
[*] Sending S4U2proxy request to domain controller 10.0.0.10:88
[X] KRB-ERROR (13) : KDC_ERR_BADOPTION

好的,我们越来越接近了。S4U2Self请求成功,不幸的是S4U2Proxy请求没有成功,以KDC_ERR_BADOPTION错误失败。经过一些尝试后,这几乎可以肯定是因为KDC无法解密S4U2Proxy请求中发送的票据。它将尝试用户的长期密钥,但这显然会失败。我尝试查看是否可以在请求中发送用户的TGT(除了S4U2Self服务票据),但仍然失败。这不可能吗?

再考虑一下,我想知道,我能否解密S4U2Self票据,然后用我已经知道的用户的长期密钥加密?从技术上讲,这将创建一个有效的Kerberos票据,但不会创建有效的PAC。这是因为PAC包含一个服务器签名,该签名是使用用于加密票据的密钥对PAC进行的HMAC。KDC检查此值以确保PAC未被修改或放入新票据中,如果不正确,请求将失败。

由于我们知道密钥,我们可以更新此值。但是,服务器签名受KDC签名保护,该签名是使用KDC自己的密钥进行的HMAC。我们不知道这个密钥,因此无法更新第二个签名以匹配修改后的服务器签名。看起来我们卡住了。

尽管如此,如果用户的长期密钥恰好与我们用于加密S4U2Self票据的TGT会话密钥匹配,会发生什么?偶然发生这种情况的可能性很小,但通过了解用户的密码,我们可以在S4U2Self和S4U2Proxy请求之间在DC上更改用户的密码,以便在提交票据时KDC可以解密它,也许我们可以成功获得委派票据。

由于我们知道TGT的会话密钥,一种明显的方法是将哈希值"破解"回有效的Unicode密码。对于AES密钥,我认为这将很困难,即使成功也可能耗时。然而,RC4密钥只是MD4哈希,没有额外的暴力破解保护。幸运的是,Rubeus中的代码默认请求TGT的RC4会话密钥,并且微软尚未在Windows域中默认禁用RC4。这似乎是可行的,即使需要很长时间。我们还需要"破解"的密码符合域的密码策略,这增加了额外的复杂性。

但是,我记得在使用SAM RPC API时,有一个SamrChangePasswordUser方法可以将用户的密码更改为任意NT哈希。唯一的要求是了解现有的NT哈希,我们可以设置任何我们喜欢的新NT哈希。这不需要遵守密码策略,除了最短使用期限设置。我们甚至不需要处理如何正确调用RPC API,因为SAM DLL导出了完成所有艰苦工作的SamiChangePasswordUser API。

我采用了一些由Vincent Le Toux编写的示例C#代码,并在正确点将其插入Rubeus,传递当前TGT的会话密钥作为新的NT哈希。让我们看看是否有效:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
SamConnect OK
SamrOpenDomain OK
rid is 1208
SamOpenUser OK
SamiChangePasswordUser OK
[*] Impersonating user 'Administrator' to target SPN 'cifs/WIN10TEST.domain.local'
[*] Building S4U2proxy request for service: 'cifs/WIN10TEST.domain.local'
[*] Using domain controller: primarydc.domain.local (10.0.0.10)
[*] Sending S4U2proxy request to domain controller 10.0.0.10:88
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'cifs/WIN10TEST.domain.local':
      doIG3...

它确实有效!现在注意事项:

  • 这显然只在域上仍启用RC4时有效。
  • 您将需要用户的密码或NT哈希。我想不出一种仅使用有效TGT的方法。
  • 用户是牺牲品,之后可能很难使用密码登录。
  • 如果由于域的策略无法立即重置密码,用户可能完全损坏。
  • 这不是很隐蔽,但这不是我的问题。
  • 如果启用了PKINIT,您可能最好只进行影子凭证攻击。

由于我感到懒惰,我不打算提供对Rubeus的更改。除了调用SamiChangePasswordUser外,执行攻击的所有代码已经存在,只需要连接起来。我相信他们会欢迎这个补充。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计