Multimaster
Summary
The MEGACORP.LOCAL domain controller (<retired-instance-ip>) was fully compromised through a web-to-Active-Directory attack chain.
An employee-lookup API on IIS accepted JSON search queries behind a WAF that blocked raw single quotes; substituting the Unicode look-alike character U+2019 (RIGHT SINGLE QUOTATION MARK) bypassed the filter and enabled a five-column MSSQL UNION injection that extracted Keccak-384 password hashes from the application login table.
Offline cracking with hashcat recovered several cleartext passwords, which were sprayed across SMB and WinRM against a domain user list also derived from the injection; MEGACORP.LOCAL\tushikikatomo with password [REDACTED: recovered credential] authenticated to WinRM and yielded user.txt.
Process enumeration from that foothold shell discovered a VS Code Electron process owned by developer cyork, launched with a Chrome DevTools remote-debugging port bound to localhost; injecting a PowerShell reverse shell through that unauthenticated debugger pivoted into cyork's context.
Reverse-engineering the .NET API DLL exposed a hardcoded SQL Server connection-string password belonging to MEGACORP.LOCAL\jorden, a member of the built-in Server Operators group.
That group's service-reconfiguration rights were abused to replace the Browser service binary path with a robocopy command that staged root.txt to a world-readable path as SYSTEM, completing full domain-controller compromise.
Attack path — how the box was taken
Fingerprinted all exposed services on the domain controller, then Bypassed the WAF via Unicode substitution and dumped password hashes via MSSQL UNION injection, then Cracked Keccak-384 hashes offline to recover multiple cleartext passwords, then Sprayed cracked passwords across AD services to gain a WinRM shell as tushikikatomo, then Found a VS Code Electron process with an unauthenticated remote debugger bound to localhost, then Injected a reverse shell via the Electron debugger and extracted hardcoded credentials from the API DLL, then Abused Server Operators service rights to run as SYSTEM and read root.txt.
Exact commands 2
nmap -sV -sC -T4 -p 53,80,88,135,139,389,445,464,593,636,1433,3268,3389,5985,9389 $TARGET -oN multimaster_nmap.txtecho "$TARGET MULTIMASTER.MEGACORP.LOCAL MEGACORP.LOCAL" | sudo tee -a /etc/hostsExact commands 2
curl -sS -X POST http://$TARGET/api/getColleagues -H 'Content-Type: application/json' -d '{"name":"\u2019 ORDER BY 5--"}'curl -sS -X POST http://$TARGET/api/getColleagues -H 'Content-Type: application/json' -d '{"name":"\u2019 UNION SELECT 1,username,password,4,5 FROM dbo.Logins--"}'Exact commands 2
hashcat -m 17900 -a 0 /tmp/multimaster_keccak384.hashes /usr/share/wordlists/rockyou.txt --quiet --potfile-path /tmp/multimaster_keccak384.pothashcat -m 17900 /tmp/multimaster_keccak384.hashes --show --potfile-path /tmp/multimaster_keccak384.potExact commands 1
curl -sS --max-time 5 http://$LOOPBACK:18112/json/listExact commands 2
iconv -f UTF-8 -t UTF-16LE /tmp/cyork_rev.ps1 | base64 -w0curl -sS http://$LOOPBACK:18112/json/list | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['webSocketDebuggerUrl'])"Attack patterns used
The transferable techniques behind the compromise.
MSSQL UNION-based SQL injection with Unicode WAF bypassExploitationT1190
What it is
The IIS site exposed an employee-search API at /api/getColleagues that accepted JSON POST bodies. The WAF rejected ASCII single quotes, but the Node.js layer decoded Unicode escape sequences before passing input to SQL Server, so replacing the apostrophe with its Unicode look-alike \u2019 bypassed the filter entirely. A five-column UNION SELECT confirmed injection and further queries extracted usernames and Keccak-384 hashes from dbo.Logins, plus domain SIDs via MSSQL built-in functions to build a username list for spraying.
Why it works
Replace all dynamic SQL string concatenation with parameterized queries using bound parameters — never interpolate user input into a SQL string. Add Unicode normalization at the API boundary that maps look-alike punctuation to ASCII equivalents before WAF inspection and before any SQL context. Apply a least-privilege SQL login for the web application that has SELECT rights only on the specific columns the API requires and no access to dbo.Logins, system tables, or xp_cmdshell.
Offline password cracking against unsalted Keccak-384Credential AccessT1110.002
What it is
The extracted digests used Keccak-384 without per-user salts. Because Keccak-384 is a general-purpose hash optimised for speed rather than password storage, a GPU running hashcat against rockyou.txt recovered multiple cleartext passwords within minutes — including [REDACTED: recovered credential], password1, and banking1 — each shared across several domain accounts, dramatically widening the spray surface.
Why it works
Migrate dbo.Logins to bcrypt (cost factor ≥ 12), PBKDF2-HMAC-SHA256 (≥ 600,000 iterations per NIST SP 800-132), or Argon2id, each with a unique random 16-byte salt per row stored alongside the hash. Force a mandatory password reset so every legacy Keccak-384 hash is replaced on next login. Treat every credential that appeared in the leaked hash set as compromised and rotate them immediately across all services.
Password sprayingInitial AccessT1110.003
What it is
The recovered cleartext passwords were paired with the username list from the MSSQL SID enumeration and sprayed across SMB, WinRM, LDAP, and MSSQL without triggering lockout. MEGACORP.LOCAL\tushikikatomo with password [REDACTED: recovered credential] authenticated on both SMB and WinRM (Pwn3d!). A WinRM command execution retrieved user.txt from the user's Desktop, establishing the initial foothold on the domain controller.
Why it works
Configure the Default Domain Policy (or Fine-Grained Password Policy for sensitive groups) to require a minimum of 14 characters and complexity, with a history of 24 passwords. Set account lockout to 5 failed attempts within a 30-minute observation window. Deploy Microsoft Entra Password Protection on-premises to block dictionary words and corporate-name variants. Restrict WinRM access via Windows Firewall and AllowHosts to management workstations only, so even valid credentials cannot be used from arbitrary hosts.
Process discovery and Chrome DevTools Protocol exposureDiscoveryT1057
What it is
From the tushikikatomo WinRM session (using a pass-the-hash derived NTLM value), process enumeration revealed a VS Code Electron binary (Code.exe, PID 6772) owned by the developer account cyork, started with the flag --remote-debugging-port=18112 bound to 127.0.0.1. Querying http://$LOOPBACK:18112/json/list from the target's loopback confirmed the Chrome DevTools Protocol endpoint was live and listed inspectable Electron contexts, accessible to any local process without authentication.
Why it works
Remove --remote-debugging-port from all production service start-up scripts, scheduled tasks, and developer shortcuts on domain-joined machines. If remote debugging is required during active development, bind only to 127.0.0.1 on a dedicated isolated workstation that is not domain-joined, require a pre-shared session token, and tear down the listener immediately after use. Add EDR detection rules that alert on any process spawned with --remote-debugging-port on domain hosts.
Chrome DevTools Protocol RCE and hardcoded credential extraction from compiled binaryLateral MovementT1059.007
What it is
Using the Chrome DevTools Protocol WebSocket on port 18112, a PowerShell reverse shell encoded as base64 UTF-16LE was delivered via a Runtime.evaluate call into the Electron renderer process, executing arbitrary commands as cyork. From that context the compiled .NET API assembly (MultimasterAPI.dll) was located on disk and decompiled with ILSpy, revealing a plain-text SQL Server connection string with the password [REDACTED: recovered credential] for the domain account MEGACORP.LOCAL\jorden. Authenticating to WinRM as jorden confirmed the password and showed membership in the built-in Server Operators group.
Why it works
Move all secrets — connection strings, API keys, service account passwords — out of source code and compiled binaries into a secrets manager such as Azure Key Vault or Windows DPAPI-protected configuration, retrieved at runtime via managed identity. Rotate the exposed password ([REDACTED: recovered credential]) immediately and audit every service that used it. Add a SAST step in the CI/CD pipeline that fails the build if connection-string literals or password patterns are detected in source or compiled output.
Server Operators service binary path hijack for SYSTEMPrivilege EscalationT1543.003
What it is
The Server Operators built-in group grants the right to stop, start, and reconfigure Windows services — including replacing the binary execution path — without holding local Administrator privileges. Authenticating as jorden, the Browser service binary path was replaced with a robocopy /B command that copies root.txt from the Administrator Desktop to a world-readable staging directory as SYSTEM. Stopping and restarting the service triggered execution. root.txt was then read from the staging path over WinRM, and the Browser service binary path was restored to its original value as part of post-exploitation cleanup.
Why it works
Audit Server Operators and remove every account that does not have a documented, approved need to manage services on domain controllers. For any remaining members, enforce Privileged Access Workstation (PAW) usage and multi-factor authentication before the account can authenticate to a Tier 0 asset. Apply Microsoft's Enterprise Access Model so Server Operators-class accounts never authenticate to Tier 1 or Tier 2 systems. Where specific service management is needed, use Just Enough Administration (JEA) to scope rights to named services rather than granting broad Server Operators membership.
Findings
Exposed services
| External surface | A full-port TCP sweep of <retired-instance-ip> identified a Windows Server 2016 domain controller serving the MEGACORP.LOCAL domain. Services of interest included IIS 10.0 on port 80 hosting a Node.js employee API, MSSQL 2017 on port 1433, WinRM on port 5985, SMB on port 445, Kerberos on port 88, and LDAP on ports 389 and 3268. The IIS stack fingerprint pointed directly at the web API as the primary attack surface. |