Triathlon
Challenge Lab (Hard) - by Brady McLaughlin
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective / Scope
An elite triathlon team from the United States has requested a penetration test on their internal network. They have granted access to their network via VPN, but no other information has been provided. Successful testers should prove full compromise by providing the NTLM hash for the "krbtgt" account.
Summary
Recon
In our initial reconnaissance phase, we perform a port scan on every available machine and manually probe the services available.
SWIM-SRV
We use rustscan -b 500 -a SWIM-SRV -- -sC -sV -Pn to enumerate all TCP ports on the SWIM-SRV machine, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

On the SWIM-SRV machine we only have SMB, RDP and some RPC ports available. From this initial scan we can determine the acutal machine name and domain.

SMB
We try to log in to the SMB service as a guest and anonymously, but without success. Nevertheless we are able to spot the running Windows version and that SMB signing is disabled.

BIKE-SRV
We use rustscan -b 500 -a BIKE-SRV -- -sC -sV -Pn to enumerate all TCP ports on the BIKE-SRV machine, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

Unlike SWIM-SRV, BIKE-SRV also has a web server available on port 80 in addition to SMB, RDP, and the RPC ports. From this initial scan we can determine the acutal machine name and domain.

WEB
The web page is a simple IIS server with a normal landing page, but it has a JavaScript alert embedded in it that displays Goose_luvs_crocs.

SMB
We also try to log in to the SMB service as a guest and anonymously, but without success - again. Nevertheless we are able to spot the running Windows version and that SMB signing is disabled.

RUN-SRV
We use rustscan -b 500 -a RUN-SRV -- -sC -sV -Pn to enumerate all TCP ports on the RUN-SRV machine, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

The RUN-SRV appears to be the domain controller with exposed services include DNS 53, Kerberos 88/464, multiple MSRPC endpoints 135, 593, 49664+, SMB 139/445, LDAP and LDAPS 389/636/3268/3269 tied to Active Directory, RDP 3389, and .NET Remoting 9389. This indicates a fully integrated Windows AD environment where LDAP/LDAPS and Kerberos provide authentication, SMB and RPC enable remote management, and RDP/WinRM serve as remote access points.





Besides the actual machine name and domain we are also able to identify the Certificate Authority name:
User Enumeration via Kerbrute on RUN-SRV
Since we are obviously operating in an Active Directory context and were unable to identify any services with vulnerabilities in our initial enumeration that could be used to enumerate potential users, harvest credentials, or gain a foothold, we now need to enumerate the users.
The Orange Cyberdefense mind map can provide guidance on what you can do. It takes you by the hand depending on whether you already have a username, credentials, or nothing at at all, etc.

We can use kerbrute to enumerate users. Kerbrute works by sending Kerberos authentication requests to the domain controller and identifying valid usernames based on differences in the responses.
Unfortunately, we cannot identify users from the user lists in Seclists. From the scenario, we know that the USA Elite Triathlon Team has commissioned us. After a little research, we can identify the team and create a user list with possible usernames.
We run kerbrute...

... and are able to identify three valid usernames. We save them to a file called valid_users.txt.
AS-REP Roasting
Now that we have some usernames, we can try AS-REP Roasting by requesting a Kerberos AS-REP response for accounts that do not require pre-authentication, allowing us to capture the encrypted response and crack it offline to recover the user's password.

We use NetExec for AS-REP Roasting and are able to extract the blob from t.spivey.

We aren't able to crack it either using rockyou.txt or by crafting our own wordlist using cupp.


Blind Kerberoasting
Since the AS-REP blob can't be cracked, we move to blind Kerberoasting, where we request service tickets (TGS) for SPNs without knowing service account credentials and identify valid service accounts by the presence of Kerberos responses. Any authenticated domain user can request Kerberos service tickets for SPNs.
If we are able to capture TGS blobs we can try to crack them offline to recover service accounts passwords.

We try to perform a blind kerberoast for each user as t.spivey and are successful. We are able to retrieve the Kerberos 5, etype 23, TGS-REP blob of j.reed.

Access as j.reed
We try to crack it using rockyou.txt, again without success.

Next, we try to craft our own wordlist with the information publicly available. We use the following resource:
To craft the wordlist we use cupp again.

And again we are unsuccessful.

As a last resort we try to apply the /usr/share/hashcat/rules/best64.rule. And we are able to crack it.

Considering the rule, we would also be able to use rockyou.txt to crack the blob with the best64 rule.

We are able to authenticate against SMB on the domain controller with the credentials gathered.

With a brute force attack, we could now continue to enumerate users.

Furthermore, we can now also create an appropriate /etc/hosts entry using NetExec.

BloodHound Enumeration
With the credentials, we can now also enumerate the AD using BloodHound.

Unfortunately, our user does not have any special permissions that can be exploited and is not assigned to a privileged group.

As domain administrators, we identify the user j.reed_adm.

Certipy Enumeration
Since we didn't find anything using BloodHound, we'll try Certipy and search for possible misconfigured certificates...

... but we can't find anything here either. But we see that the CA is the SWIM-SERV machine.

NTLM Theft
When listing the individual shares on the servers, we see that we have read and write permissions for the TransitionZone$ share on SWIM-SRV.

We connect to the share, but we don't see anything on it.

But it enables us an NTLM theft attack through coercing. This is a technique where Windows is forced to authenticate to them using NTLM, allowing us to capture or relay the victim's NTLM credentials.
We can coerce for example via a .lnk file by placing a malicious shortcut in a writable share. When a user or service browses the folder, the .lnk file references a remote UNC path (e.g. \\attacker\share), causing Windows to automatically attempt NTLM authentication to that remote host—leaking the NTLM hash without any user interaction.

We prepare a link file pointing to our server with ntlm_thef.py.

We start responder...

... and place our .lnk file into the share.

After a short duration we are able to get the NetNTLMv2 hash of e.ackerlund. But we can't crack that hash either.

Access as local Administrator on BIKE-SRV via NTLM Relay
What we can do instead is relaying it to anther SMB service where SMB signing is not enabled.

Recalling the output of the SMB connection attempts to the servers we know that BIKE-SRV and SWIM-SRV have SMB signing switched off, which would allow relaying. So since we can't relay back to SWIM-SRV we try to relay the authentication over SMB to the BIKE-SRV and try to dump the SAM & LSA secrets, if the user e.ackerlund has the privileges to do so.
The following command will try to relay the authentication over SMB and attempt a remote dump of the SAM & LSA secrets from the target if the relayed victim has the right privileges.
We run the command like depicted in hackers recipes...

... but it fails, the target has SMBv1 maybe disabled.

We rerun ntlmrelayx.py now with smb2support.

After some time we are able to retrieve the local administrator hash on BIKE-SRV.

With that we are able to authenticate against the server.

Access as m.pearson
As a local administrator, we can extract the hashes from SAM and LSA.
For this we are using secretsdump.py. We are able to retrieve the DCC2 hash of m.pearson.

And this time, we are able to crack the Domain Cached Credentials 2 (DCC2), MS Cache 2 using rockyou.txt.

Next we test connection on each server. We are Administrator on SWIM-SRV.

Certipy Enumeration II
Now that we have administrator permissions as m.pearson on the CA, we run another scan using certipy, but again find no misconfigured templates.


Stolen CA Attack
After some research we come across the Stolen CA Attack.
The following quote from thehacker.recipes succinctly describes what is possible with it.
The Enterprise CA has a certificate and associated private key that exist on the CA server itself. (Certified_Pre-Owned.pdf)
If an attacker obtains control over a CA server, he may be able to retrieve the private key associated with the CA cert, and use that private key to generate and sign client certificates. This means he could forge (and sign) certificate to authenticate as a powerful user for example.
Extracting the DPAPI-protected CA cert private key can be done remotely from UNIX-like systems with Certipy (Python).
Then, forging (and signing) a certificate can be done as follows.
The certificate can then be used with Pass the Certificate.
With the administrator permissions on the CA we can now forge a ticket for a powerful user like a Domain Administrator. We recall the initial BloodHound enumeration and choose j.reed_adm as our target.

We extract the DPAPI-protected CA cert private key like depicted in our resource, but we fail.

Since the domain controller is not the same as the CA, we must define the CA as the target. We are able to extract the CA cert.

With the CA cert we try to forge a cert for the user j.reed_adm by the distinguished name.

Next, we pass the certificate, but it fails.

Next we try to forge the certificate for j.reed_adm with the SID instead. We can find it using our BloodHound data.


But it also fails again. The client is not trusted...

If we pass the following to our forge command -crl ldap:/// we are able to retrieve the hash of j.reed_adm. Kerberos is rejecting the last cert because it can't validate revocation status, so it treats the client as untrusted. When we add -crl ldap:///, we are giving the certificate a CRL distribution point that the DC accepts without trying to fetch an HTTP CRL. That seems enough to satisfy PKINITs trust checks.

With the gathered hash we are able to dump the SAM & LSA secrets on the domain controller including the krbtgt hash.


Last updated
Was this helpful?
