Skip to main content
Background Image

Triathlon - Hack Smarter

·1486 words·7 mins
Brady McLaughlin
Author
Brady McLaughlin

This is the official write-up for the hard-rated “Triathlon” lab that I was invited to create for Hack Smarter’s new lab platform, available at courses.hacksmarter.org. Although I didn’t have to “solve” this lab (as the creator), I am documenting the process I would have used to find all information in this write-up WITHOUT including any flags, in the spirit of the game. However, following this process exactly should result in a full compromise of the target network.

If you’d prefer a more visual format, my YouTube video for this lab features a couple of Easter Eggs and information about the “lore” of the lab and the creation process.


Initial Scanning and Enumeration
#

My first step is to confirm that each machine is alive and responding. Since the machines may not all respond to pings, I moved on to a quick nmap scan of each:

Ports look to be standard for Windows machines, with one domain controller and two other servers. Since we are operating in a Windows environment, we will populate our /etc/hosts file, as we will likely be interacting with Kerberos, which prefers NetBIOS names over IP addresses. We can find these hostnames (unauthenticated) using netexec:

Now we can populate our /etc/hosts file using these hostnames. I prefer to use the format (plus for the domain controller) so that we can use hostnames for most of our commands going forward:

After confirming that there are no non-standard ports or services, we can proceed to domain enumeration.

Finding Valid Users
#

Reading the lab premise, we see that we only have access to the VPN, but no other information. This means that we don’t have any credentials or usernames to attack. The only information that we have is that we have been contracted by “an elite triathlon team from the United States.”

Note that the lab premise was slightly reworded during QA to hint toward the open-source intelligence (OSINT) vector a little bit more.

We won’t find any information on the machines until we have credentialed access, but the information we have about the organization allows us to begin gathering OSINT about the target.

Following the first search engine result leads us to a page with a “Meet the Team” link that may yield some potential usernames:

Note that this lab was created in 2025, so the 2025 team was used. I have archived this page, and we’ll add that to the lab if this information changes in the future. Coincidentally, the required users are in a common usernames wordlist, so the “spray-and-pray” method could also work, albeit a bit less scientific than the intended route.

This page has the names of several athletes, which we can use to create a wordlist of potential usernames.

This page lists nine athletes, which we will collate into a list of potential users:

Next, we can use popular open source tools like username-anarchy or UserlistGenerator to turn these first and last names into common username formats:

As you can see, the tools generate different lists, but either will be suitable for this lab.

We can use kerbrute to test whether any of the created usernames is valid in the “tri.lab” domain:

Initial Access
#

Most Active Directory hacking checklists will likely tell you that if you have valid usernames but no passwords, one of the first things to try is ASREP-roasting. We can test this using GetNPUsers.py:

However, this hash does not (and is not intended to) crack:

However, there is a less common technique that we can use here. Although we don’t have credentials to query the users with SPNs from the directory, if we have a user (like the “t.spivey” user) that does not require Kerberos pre-authentication, we can use this account to request a service ticket (ST) for a known account without having to supply any credentials. GetUserSPNs.py implements this using the -no-preauth flag:

This hash will crack, albeit with mutations. I used the “best66” hashcat rule, but others will likely work also.

We can confirm this password’s validity using netexec:

We can see that the “j.reed” account is not an administrator on any of the servers, but we do have valid domain credentials, which is a great start!

Lateral Movement
#

There is a 2025 CVE that I was unaware of while creating this lab, so it is not patched. See if you can find it, but I will not be demonstrating it in my official walkthrough 😅

Now that we have a domain user, we can attempt to move laterally to gain more access to the environment. Although enumerating SMB shares does not yield any helpful information, we do have write permissions on a file share on the “SWIM-SRV” machine:

We can attempt to use this access to coerce authentication using an LNK file attack or a similar method. We can set up a malicious LNK file using netexec’s “slinky” module and catching authentication using a tool like responder:

Note that we captured authentication from the “e.ackerlund” account, and the client IP address tells us that the authentication came from SWIM-SRV.

However, this hash also does not (and is not intended to) crack:

However, since SMB signing is not enabled on SWIM-SRV or BIKE-SRV, we can attempt to relay authentication from the “e.ackerlund” account on SWIM-SRV to the BIKE-SRV machine and see if this account has any permissions. We can use netexec to create a list of relay targets:

Note that since authentication can’t be relayed from a target to itself, we can manually remove SWIM-SRV’s IP address from our targets file to keep our output and screenshots clean.

After adjusting our /etc/responder/Responder.conf file (we will need to disable conflicting listeners to avoid error output), we can use ntlmrelayx.py to relay authentication. As it turns out, the “e.ackerlund” account is an administrator on BIKE-SRV, so ntlmrelayx will dump the hashes from the machine’s Security Account Manager (SAM):

The syntax used here was impacket-ntlmrelayx -tf targets.txt -smb2support, for reference.

We can confirm the hash for the local “Administrator” account is valid using netexec:

We can use administrative credentials to extract secrets using secretsdump.py:

Note here that we have a domain cached credential (DCC) for a new user, the “m.pearson” account.

This hash will crack using only a standard wordlist:

We can confirm this password, revealing that the “m.pearson” account is an administrator on SWIM-SRV:

Domain Escalation
#

Now that we have administrative access on both of the auxiliary servers, the only thing left to do is find a way onto the domain controller. With administrative access on a few machines, we may be able to access a Certificate Authority (CA) and abuse our permissions to escalate ourselves in the domain.

We can see that SWIM-SRV hosts tri-CA, the CA for tri.lab. Because we have control of an administrator for this server (the “m.pearson” account), there are two intended routes from here: ESC7 via the local Administrators group or a Golden Certificate attack.

First, we will need to find a suitable target. We can check bloodhound-ce for Domain Admins:

It looks like the “j.reed” account we observed earlier has an admin account called “j.reed_adm” that we can target for the next steps.

Golden Certificate Attack
#

Because we have full control over the server where the CA is running via membership in the local Administrators group, we can back up the CA’s certificate, allowing us to forge certificates (offline) on behalf of arbitrary principals:

We can now use certipy to authenticate with this certificate, gaining a TGT that we can use for domain authentication:

ESC7 Exploitation
#

As a member of the local Administrators group, we are automatically granted the ManageCA right and the ManageCertificates right on the CA. However, Certipy will not detect that the local Administrators group has these permissions, so we will have to rely upon the knowledge that these permissions are inherently granted to this group. Because of these permissions, we will be able to use one of the ESC7 escalation methods to gain Kerberos tickets for arbitrary principals via a certificate created using the “SubCA” certificate template.

We’ll first request a certificate using the SubCA template targeting the “j.reed_adm” user:

This request fails as expected, as the SubCA template is not enrollable by users not in the Domain Admins group or higher. However, because we have elevated rights on the CA, we can approve our own request and retrieve the certificate:

We can successfully authenticate with our certificate and get a TGT, granting us full access as a Domain Admin:

Lab Objective
#

Using our administrative rights on the domain controller, we can perform a DCSync, granting us the NTLM hashes of the “krbtgt” account, the target for this lab:

Thank you to Tyler at Hack Smarter for inviting me to create this lab - I had a lot of fun building and testing this one. Looking forward to the possibility of publishing something I’ll think up in the future!