Nine attack phases, nine matching detections — red team and blue team, same person, same lab.

Most security labs pick a side. You either run the attack, or you build the detection. I wanted both — the same intrusion, executed stage by stage, with every step caught against real Windows Security, Sysmon, and OpenSSH telemetry, correlated into a MITRE ATT&CK matrix as I went.

The environment: a Windows Server 2022 domain controller (DC-01.corp.local, 192.168.56.110), a Windows 11 workstation (WS-01.corp.local, 192.168.56.130), and a Kali Linux attacker box (192.168.56.102), isolated on their own subnet. Nine stages, from initial foothold to full domain compromise and exfiltration.

Stage 1–2: Getting in without a password

Reconnaissance started with an aggressive Nmap scan across the subnet — out of scope for endpoint detection by design, since catching this stage needs network-level IDS/IPS, not host telemetry. That’s a real, deliberate gap in the matrix, not an oversight.

Initial access came from a protocol most networks still leave enabled by default: LLMNR, the fallback name-resolution broadcast Windows uses when DNS doesn’t answer. Responder poisoned that fallback and captured j.doe's NTLMv2 hash. Hashcat cracked it against a small wordlist almost immediately — the account's password wasn't complex. That hash got me an Evil-WinRM shell as j.doe on WS-01.

Detection: Windows Event ID 4624 (Logon Type 3 — network logon) and 4769 (Kerberos TGS ticket request) both fired the moment the WinRM connection landed, cleanly tying the session to the Kali IP.

Stage 3: The checkbox that shouldn’t have been checked

Enumerating further turned up a service account, svc_sql, with Kerberos pre-authentication disabled. That single flag is what makes AS-REP Roasting possible — instead of authenticating first, you can request a ticket for the account directly and crack it completely offline. Impacket's GetNPUsers pulled the ticket, hashcat cracked it, and I had svc_sql's real password. That password also turned out to grant Evil-WinRM access with local administrator rights on WS-01.

Detection: Event ID 91 (WSMan shell creation) paired with Event ID 4672 — “special privileges assigned to new logon” — is what actually confirms this stage from a defender’s chair. It’s not just a new session; it’s a new session that immediately got admin-level rights, which is the real signal.

Stage 4: The credential dump that found more than it was looking for

With local admin on WS-01, I ran Impacket's secretsdump against the local SAM database. This pulled local account hashes as expected — but it also surfaced something more valuable: a cached domain logon credential for CORP.LOCAL\Administrator, left behind because that account had logged into this workstation before. John the Ripper cracked it.

Detection: Event ID 5379 — Credential Manager credentials read — is the specific, correct signal here. It’s a quiet, easy-to-miss event in a sea of routine logons, which is exactly why it matters: the difference between a workstation dump and an admin credential dump often comes down to whether anyone’s actually watching for this one.

Stage 5: Confirming the blast radius

Using the cracked Administrator credentials, I ran NetExec against the domain controller’s LDAP service to enumerate every domain account — Administrator, krbtgt, and several standard users, confirming the scope of what a single cracked cached credential now exposed.

Detection: Sysmon Event ID 3 (network connection) caught the LDAP traffic to DC-01 — a workstation-originated PowerShell/tooling session reaching out to query the domain controller directly is exactly the kind of connection worth a detection rule on its own.

Stage 6: The pivot that shouldn’t have worked

This is the finding that mattered most: the Administrator account’s password matched the one already recovered from svc_sql. Password reuse across a privilege tier boundary — a Tier 0 domain admin credential and a Tier 2 service account sharing a password — is exactly the kind of gap that turns a single compromised workstation into a compromised domain. With that password, I SSH'd directly into DC-01 as Administrator — the domain controller was running OpenSSH, accepting the connection with no additional barrier.

Detection: OpenSSH Event ID 4 (accepted password) alongside Windows Event ID 4624 confirmed a Domain Admin authenticating over SSH from the known attacker IP — about as clean an anomaly signature as this kind of pivot produces.

Stage 7: Living off the land, on purpose

On the domain controller itself, I didn’t reach for Mimikatz first. I used rundll32.exe calling comsvcs.dll's MiniDump export — a legitimate Windows binary invoking a legitimate Windows DLL — to dump lsass.exe's memory to lsass.dmp. This is the "living off the land" pattern real attackers lean on specifically because it doesn't touch disk with anything a signature-based tool would flag.

Detection: Sysmon Event ID 1 (process creation) logged the exact command line anyway — rundll32.exe invoking comsvcs.dll against lsass.exe is a specific enough pattern that the legitimate-binary cover doesn't actually help the attacker once you know what to search for.

Stage 8: Domain takeover

With Administrator access to the DC, Impacket’s secretsdump in DCSync mode pulled the krbtgt hash directly from AD replication — the domain's master key for signing every Kerberos ticket. Mimikatz then forged a Golden Ticket: a Kerberos TGT valid for effectively any account, independent of actual password changes going forward.

Detection: Event ID 4662 — object access against the domain’s replication attributes — flagged the DCSync the moment it happened. A legitimate domain controller replicating with another DC looks nothing like a single workstation suddenly requesting replication data it has no operational reason to ask for.

Stage 9: Getting the data out

Last step: SCP, over the same SSH channel, pulling the dumped lsass.dmp file back from the domain controller to the Kali box.

Detection: Sysmon Event ID 3 again — a network connection over port 22, tied to the Administrator account, going to the same IP that’s now shown up at every other stage of this chain. By this point in the matrix, that IP alone is enough to justify pulling the full timeline.

What actually stood out, building this

The compromise didn’t depend on a single exotic technique. It depended on four ordinary misconfigurations stacking on top of each other: LLMNR left enabled, Kerberos pre-auth disabled on one account, a service account sitting in the Backup Operators group (a Tier 0-equivalent privilege that has no business being handed to a SQL service account), and a shared password crossing a privilege boundary that should never have been crossable. Any one of those alone is a moderate finding. Stacked, they’re a full domain compromise in under an hour.

What I’d fix, in priority order: remove svc_sql from Backup Operators and strip its local admin rights immediately; enforce Kerberos pre-authentication domain-wide, which eliminates the AS-REP Roasting path entirely; kill password reuse across privilege tiers with actual tiered administration; disable LLMNR and NBT-NS via Group Policy so name resolution can't be broadcast-poisoned; and enable Credential Guard and LSA Protection, which isolates LSASS memory at the hardware virtualization level and stops the comsvcs.dll technique cold.

This lab was built and detected entirely with native tooling — Windows Event Viewer and Sysmon, no custom platform involved. That was deliberate: before building detection logic into anything, I wanted to know exactly what the raw telemetry looks like at the source. It’s also, separately, where the detection patterns behind a SIEM project I built afterward actually came from — the Kerberoasting and DCSync-style detection rules in that tool trace directly back to the Event IDs in this matrix.

Full technical report — raw tool output, every event log capture, complete MITRE correlation matrix — is on GitHub: github.com/sodik-tursunboev/ad-attack-simulation-lab