Skip to main content

Starting the box


Link to the box: https://app.hackthebox.com/machines/darkzero

Port Scan

We start off the box by running a port scan on the provided IP.
Attacker Linux
Output of Rustscan:
Terminal Output
A few key notes:
  • Port 88 is open, which means this is likely a Windows Domain Controller (DC).
  • Port 1433 is open, which is the usual port for MSSQL
  • Port 5985 is open, which is the usual port for WinRM.

Edit the Hosts file

As always, we edit the /etc/hosts file to add the hostname:
Attacker Linux
/etc/hosts
Nano Interface

Initial User


As is common in real life pentests, you will start the DarkZero box with credentials for the following account john.w / RFulUtONCOL!
We can use NetExec to check if the credentials are valid for AD:
Attacker Linux
  • NLTM authentication is allowed.
  • Only default shares are present.

Enumerating Active Directory Environment

Running Bloodhound

Let’s fix our clock synchronization before doing any AD enumerations:
Attacker Linux
We can run Bloodhound now:
Attacker Linux
Key Notes of the Bloodhound results:
  • No outbound control from john.w. No special groups too.
  • Only 3 domain users - john.w, administrator, and krbtgt.

Checking ADCS Attacks

Let’s check if there are any vulnerable ADCS templates:
Attacker Linux
  • No vulnerable template for our controlled user.

Enumerating MSSQL

Since Port 1433 (MSSQL) is open, we can try our credentials on it to see if our user has access to the MSSQL server:
Attacker Linux
We were able to successfully login to the MSSQL server as guest. We can start by enumerating the users. There is nothing of interest for now.
MSSQL Client

Trying NTLM coercion with MSSQL

Let’s do force authentication (coercion attacks) to our controlled server with xp_dirtree in MSSQL to see if the obtained hash is crackable. We’ll use impacket’s smbserver.py to capture the hash:
Attacker Linux
Then, on our MSSQL shell, we use xp_dirtree to list the directory of our SMB server, forcing a NLTM authentication to our server:
MSSQL Client
On our SMB server, we have successfully captured the Domain Controller’s machine hash, which is likely uncrackable.
SMBServer.py
We can try it with Hashcat anyway:
Attacker Windows
  • The rockyou.txt was exhausted. Let’s move on to other attack vectors.

Enumerating Linked Servers

Let’s check if there is any linked servers with our MSSQL instance.
MSSQL Client
Pay attention to the second half of the output:
MSSQL Client
  • This indicates that we will be authenticated as dc01_sql_svc when interacting with DC02.darkzero.ext.
Using this command ChatGPT provided, we are able to confirm that dc01_sql_svc is sysadmin on DC02.darkzero.ext:
MSSQL Client

Using Linked Server

Using the Linked Server on DC02:
From the impacket-MSSQL client menu, we can see that there is a use_link procedure.
MSSQL Client
  • We are in DC02 now.
Let’s check if we can enumerate any users. The results returned nothing of interest.
MSSQL Client
Enabling XP_CMDSHELL:
Since we are the sysadmin, we have to privilege to enable xp_cmdshell, which would allow us to execute system commands as the MSSQL server.
MSSQL Client
Success! We can run system command on DC02 now. Let’s run a quick whoami to check which user is running this MSSQL service. It looks like we have a service account.
MSSQL Client
Starting a reverse shell from MSSQL:
Let’s try to run a base64-encoded PowerShell reverse shell payload. However, it was not working properly here and it returned a broken shell.
MSSQL Client
We will simply download a Netcat binary and run a Netcat reverse shell. We successfully received a proper shell on our listener.
MSSQL Client

Enumerating DC02

We first run a quick WinPEAS to see if there is anything interesting. While there was no output that stood out, we can still try to crack the NetNTLMv2 hash of our controlled user regardless. We tried with Hashcat and it cannot be cracked. Let’s move on.
WinPEAS Output
The DNS cached output indicates that there is a 172.16.20.x internal network, and DC02 is running on 172.16.20.2.
WinPEAS Output

Running Ligolo to access the internal network

The easiest way to enumerate the internal network is to run Ligolo on our controlled machine. We will first start the proxy server on our attacker Linux:
Attacker Linux
Then, we will download the Ligolo agent to the victim machine, and run the agent to connect back to our proxy server.
Victim Windows (DC02)
Use the session command in the Ligolo Interface to interact with our connected agent.
Ligolo Interface
To tunnel our traffic through the victim machine like a VPN, we first have to build a network interface for Ligolo:
Ligolo Interface
We can run the add_route command to route our traffic to the corresponding subnet addresses. Here, for example, all traffics on our attacker Linux towards 172.16.20.0/16 will be routed to the victim machine via the ligolo interface, and act as we are on the same subnet as the victim machine.
Ligolo Interface

Running Bloodhound

This time, we will run Bloodhound with the Sharphound Ingestor on the victim Windows machine.
Victim Windows (DC02)
On our attacker Linux machine, we will set up an SMB server to receive the output file.
Attacker Linux
On the victim Windows, we will upload the resulting Bloodhound ZIP file to our SMB server.
Victim Windows (DC02)

Running ADCS Enumeration Tools

We will also download the Certify binary on the target Windows.
Victim Windows (DC02)
Enumerate Certificate Authorities:
We will check if the CA on DC02 is vulnerable to ADCS attacks. The output looks normal.
Victim Windows (DC02)
Enumerate Vulnerable ADCS Templates:
We will also check if there’re any vulnerable ADCS templates on DC02 is vulnerable. Again, no vulnerable templates were returned.
Victim Windows (DC02)

Checking the Policy_Backup.inf file:

We can see that there is a Policy_Backup.inf file in the root directory, which is uncommon.
Victim Windows (DC02)
The Policy_Backup.inf file contains the privileges on different accounts:
Policy_Backup.inf Snippet
From the policy backup file, our controlled account svc_sql should have SeServiceLogonRight . But running whoami /priv does not return the right. Our user is also in the S-1-5-6 is the NT AUTHORITY\SERVICE group, but again we are missing the privilege.
Policy_Backup.inf Snippet
Checking with whoami /all, we can see that our user is in the NT AUTHORITY\SERVICE group.
Victim Windows (DC02)
Again, since NT AUTHORITY\SERVICE has the SID S-1-5-6, in theory our user should have the SeImpersonatePrivilege. However we are missing the privileges. It is likely because our current logon token type has been restricted. A quick Google on restoring privilege sets for service account returned the following GitHub repo: This however didn’t work, likely because this was an old way to restore privilege and has likely been patched.
Victim Windows (DC02)

Retrieving NTLM hash of svc_sql

Dumping Cached Kerberos Ticket

After some research, we learn we have restricted privilege as our current token type is in the interactive logon type (2). To restore the service account’s full privilege, we need to login with a service logon type (5) token.
  • This can be done with a password login using RunasCs.exe to specify the logon type.
  • However, we don’t have password now.
By running klist, we note that we have a cached Kerberos ticket. This is good news since it means that we can likely dump out the ticket for Kerberos authentication.
Victim Windows (DC02)

Changing User Password with NTLM Hash

It is possible to change a user password without knowing the current password. We can do it in two ways:
  1. Using mimikatz’s lsadump::changentlm or lsadump::setntlmmodule on the Victim Windows machine, as long as we know the NTLM hash of the user, and the server accepts NTLM authentication.
  2. Using impacket’s changepasswd.py tool on the remote Attacker Linux. Works for both Kerberos & NTLM authentication.

We can run Certify.exe on Windows to extract the valid Kerberos ticket, then either:
  1. Run Rubeus.exe on Windows to extract the NTLM hash of the user.
  2. Use the valid ticket to run remote tools like impacket-changepasswd to directly change the password. In our current scenario, we would also have to run pivoting tools like Ligolo, since the DC is in the unreachable internal network.

Let’s first get Rubeus on the machine.
Victim Windows (DC02)
We will dump out the Kerberos ticket in the .kirbi format.
Victim Windows (DC02)
The KRB-CRED files (.kirbi) are output as base64 blobs and can be reused with the ptt function, or Mimikatz’s kerberos::ptt functionality.
  • Here, since the ticket’s LoginType is Service (Type 5), the tickets are non-exportable by default in Service Logon token. Therefore, even though we used the /outfile flag, no file was generated.
We got this error when we are trying to save the ticket manually, or using the base64 blob in the command line:
Victim Windows (DC02)
Since our reverse shell cannot take the long base64 string, we’ll create the ticket file on Linux, and upload the ticket file to the target system.
Attacker Linux
Victim Windows (DC02)
However, when we try to run Rubeus with the ticket file, the following error was returned:
Victim Windows (DC02)
  • From LLM: This ASN.1 “value overflow” error typically means the ticket you’re feeding into changepw is not a valid KRB_CRED structure, even if it looks like a ticket.
Oh, so the base64 blob is not a valid .kirbi file by itself. We have to decode it into the raw binary:
Attacker Linux
The decoded binary ticket is working now.
Victim Windows (DC02)

Running Certify.exe to request a valid login certificate:
Regardless, we can use Certify.exe to use the current cached ticket on Windows to request for a valid login certificate. We will run the enum-cas module to check the name of the CA, which is darkzero.ext\darkzero-ext-DC02-CA.
Victim Windows (DC02)
We will then request a valid user login certificate.
Victim Windows (DC02)
The above Base64 output can be used in Rubeus. But again due to the input limit, we can’t use the base64 string directly in our reverse shell. However, we can actually use the following command to extract the base64 ticket on Windows. We first save the whole Certify.exe output with --out-file:
Victim Windows (DC02)
We then use Regex to extract only the Base64 value from the output:
Victim Windows (DC02)
We still have to decode the base64 string to extract the certificate in binary form:
Victim Windows (DC02)
Now, we can use Rubeus’s asktgt module to extract the user’s NTLM hash using the /getcredentials flag. We have now extracted the svc_sql user’s NTLM hash, and we will use that to obtain a cleartext password for changing our logon type.
Victim Windows (DC02)

Changing svc_sql’s password with NTLM

We can use mimikatz’s lsadump::changentlm module to change our password using NLTM auth: changentlm | The Hacker Tools.
Victim Windows (DC02)
In our Mimikatz interface, we will run the following command.
mimikatz console

Logging in with Logon Type 5 (Service)

With the new password, we can now use RunasCs.exe:
Victim Windows (DC02)
We can run a shell to with logon type 5. We must run with the flag --bypass-uac to spawn the process without token limitations. This will essentially give us back our privileges.
Victim Windows (DC02)
We now got a privileged shell that we can run impersonation attacks with Potatoes.
Victim Windows (DC02)

Escalating to SYSTEM with SeImpersonatePrivilege

Getting GodPotato on the victim machine

With the SeImpersonate privilege, we can escalate our privilege to system using potato exploits. Here we’ll use GodPotato:
Victim Windows (DC02) - New Shell from RunasCs.exe
Note that .NET version of the GodPotato binary has to match with the .NET version installed on the target machine. We can check that with the following command.
Victim Windows (DC02) - New Shell from RunasCs.exe

Running God Potato

While you can do things like starting a reverse shell, I prefer adding a new administrator user, since GodPotato often cannot run stable reverse shells.
Victim Windows (DC02) - New Shell from RunasCs.exe

Switching to the admin shell

We will run the reverse shell with our new administrator user using RunasCs.exe again.
Victim Windows (DC02) - New Shell from RunasCs.exe
On our reverse shell listener on port 443, we have successfully received a system level reverse shell.
Victim Windows (DC02) - System Shell from RunasCs.exe

Unintended Path (CVE_2024_30088)

Exploiting Unpatched Windows Kernel Vulnerability

There is also an unintended privilege escalation path that exploits a kernel vulnerability. This can be discovered via Metasploit’s local_exploit_suggester module. We first generate a Meterpreter reverse shell payload for Windows. We then upload the generated payload to DC02.
Attacker Linux
We then start a multi/handler on Metasploit and start a Meterpreter shell. Remember to correct set the payload.
msfconsole
Then, we can use the following module to exploit this unpatched kernel exploit. I used windows/x64/shell_reverse_tcp as the payload and set up a non-Meterpreter listener to make things easier.
msfconsole
On our listener, we got a system shell.
Victim Windows (DC02)

Privilege Escalation


There is a cleanup.ps1 file in the Documents folder of the darkzero.ext admin.
  • Nothing of special interest. Just for cleaning up the box.

Dumping Administrator NTLM hash from DC02

Extracting SAM hive & System

With the system shell, we can dump the SAM hive locally to extract NTLM hashes. We will then use the same file transfer method to copy the dumped hives to our SMB share.
Victim Windows (DC02)
We can then extract the NTLM hashes on our Attacker Linux using impacket’s secretsdump.py.
Attacker Linux
Alternatively, we can dump credentials with mimikatz’s lsadump::sam module.
Victim Windows (DC02)
We can verify the admin hash using NetExec’s LDAP module. Note that we are directly authenticating to DC01 with the administrator credentials of DC02.
Attacker Linux

Enumerating Forest Trust

Since we are in a forest environment, we should enumerate the trust relationships & potential delegations between domains.

Searching for Unconstrained Delegation with NetExec

We can use NetExec’s built-in module to enumerate delegation (https://www.netexec.wiki/ldap-protocol/unconstrained-delegation). As we can see, the DC01$ machine has the flag TRUSTED_FOR_DELEGATION set.
Attacker Linux

Enumerating Domain Trust with NetExec

We can also use NetExec’s built-in module to enumerate domain trust (https://www.netexec.wiki/ldap-protocol/dc-list). We can read more about Domain Trust here: Trusts | The Hacker Recipes.

Attempting to request for login certificate as Administrator

Since we have cross-forest trust, maybe we can directly request for a domain administrator TGT? The answer is no, and this will fail since this is not how cross-domain trust works. Our DC02 admin credentials do not grant us domain administrator rights on DC01.
Attacker Linux
Since we do not have any actual permission on DC01, attacks like abusing write privileges with ESC4 will not work.
Attacker Linux

Abusing Unconstrained Delegation

After some Googling, we came across a great article on explain how we can abuse cross-forest trusts. Essentially, in a two-way (bidirectional) trusted forest, users from one forest can authenticate to another forest’s resource. Kerberos TGT issued by either forest can also flow between forest.
  • If we controlled one of the forest, and a privileged user of the other forest authenticate to our controlled forest with their TGT due to the trust relationship, we can capture and dump their ticket.
  • With the privileged ticket, we can then authenticate to the original forest as the privileged user.
  • Combining this with coercion attacks, we can essentially force the Domain Controller of target forest to authenticate to our controlled forest DC, and capture the TGT of the DC machine.
On our System shell of DC02, we can run Rubeus’s monitor module to capture any incoming authentication to capture their TGT. We will run Rubeus.exe on DC02 in an elevated shell (i.e. system shell).
Victim Windows (DC02) - System Shell
We now can force the target DC (DC01) to authenticate to DC02. We can try running SpoolSample.exe on another shell on DC02. Unfortunately this didn’t work, as the printspooler service was not running on the machine.
Victim Windows (DC02)

Check if the target is vulnerable to Force Authentication

Luckily, NetExec has a module that can perform all coerce attacks. While DC02 is not vulnerable to the printer bugs, it is vulnerable to the other coercion attacks.
Attacker Linux
There is also another coercion attack that targets any user currently logged on the same machine, but we did not test it here.

Running the Force Authentication attack

Again, on our System shell of DC02, we can run Rubeus’s monitor module to capture any incoming authentication to capture their TGT.
Victim Windows (DC02) - System Shell
We can use the same module from NetExec to initiate the authentication. The -o flag is used to specify the module options. Here, we have to set the L= for the target listener, i.e., where the victim machine will be authenticating to.
Attacker Linux

Using the Captured TGT

We successfully got our TGT on the Rubeus monitor after triggering the coercion attacks. This is the Base64 encoded blob of the TGT of DC01$.
Rubues Output
We can now renew and inject the TGT into our current machine (DC02$).
Victim Windows (DC02) - System Shell
We can validate if we have successfully injected the TGT using the klist command:
Victim Windows (DC02) - System Shell

Dumping Credentials with DCSync

Lastly, with the injected DC01$ machine TGT, we can perform a DCSync attack on DC01 using mimikatz. Remember to run privilege::debug to ensure we have enough privileges. We have successfully dumped NTLM hash of the Administrator of DC01.
Victim Windows (DC02) - System Shell
Lastly, we can dump out the root flag with NetExec.
Attacker Linux

Key Learning


1. Enumerate MSSQL Linked Servers

There is a built-in function, use_link in impacket’s mssqlclient.py, which makes interaction with linked servers way easier.

2. Always look for cached Kerberos tickets

The cached tickets can be dumped out be used on Linux, or to retrieve the NTLM hash if it belongs to a service account.

3. Retrieve NTLM hash with Kerberos Ticket

Using the “UnPAC the hash” technique, we can retrieve the NTLM hash of a controlled service account by retrieve its Kerberos ticket (either by dumping or requesting), request a client-authentication certificate, and request a TGT to extract the NTLM hashes within the ticket. We can achieve this by Certify.exe + Rubeus.exe on Windows.
Victim Windows (DC02)
  • The cached ticket is used automatically if we are running this on the machine.
We then use Regex to extract only the Base64 value from the output:
Victim Windows (DC02)
We still have to decode the base64 string to extract the certificate in binary form:
Victim Windows (DC02)
Now, we can use Rubeus’s asktgt module to extract the user’s NTLM hash using the /getcredentials flag:
Victim Windows (DC02)

4. Using Regex with Certify & Rubeus Output to extract Base64 values

We can use Regex to extract only the Base64 value from the output:
Victim Windows (DC02)
We then decode the base64 string to extract the output in binary form:
Victim Windows (DC02)

5. Changing Password with NTLM using Mimikatz

We can use mimikatz’s lsadump::changentlm module to change our password using the NLTM hash: changentlm | The Hacker Tools
Victim Windows (DC02)

6. Enumerate Windows Kernel Local Privilege Escalation (LPE) vulnerabilities

With Meterpreter shell, we can run post/multi/recon/local_exploit_suggester to check for all local privilege escalation vulnerabilities in Metasploit.

7. Unconstrained Delegation

For 2-way Cross Forest Trusts, we can abuse Unconstrained Delegation to obtain the TGT of another domain’s DC.
  • Basically we run a listener on our controlled DC, and force the target DC in the other forest to authenticate to our controlled DC. Since 2-way cross forest trusts are established, the target DC will authenticate to us using the same TGT that it will be using in it’s own forest. By capture the TGT, we can authenticate to the target forest as the target DC.

8. Run all Coercion Attacks

Always run all different coercion attacks when trying to trigger force authentication. Attacks like SpoolSample will not work if there is no printspooler service running on the machine.

Tags


Initial Access

#MSSQL #Linked_Servers #SQL #Ligolo #Service_Account #Logon_Type #Windows_Privilege #Restore_Privileges #Changing_Passwords #NTLM #Kerberos #Token_Impersonation #ADCS #Potato_Attacks #Kernel_Exploit #ActiveDirectory #Regex

Privilege Escalation

#Unconstrained_Delegation #Forest_Trust #Coersion_Attacks #Kerberos #DCSync
Last modified on May 24, 2026