Impacket Deep Dive Part 9: The Full Chain, Foothold to Domain Admin
Parts 2 through 8 each isolated one technique against CONTOSO.LOCAL. This post removes the isolation. Below is the same domain, the same accounts, the same lab from Part 1, run as one continuous chain — because that’s how these techniques actually get used, and because the chain itself teaches something none of the individual parts could: each stage only exists because the previous one succeeded, and a defender who breaks any single link stops the whole thing.
Stage 0: the foothold
Nothing in this series starts with an exploit. CONTOSO\j.reyes clicked a phishing link, and their workstation, WKS01, is now attacker-controlled — a starting position not far from the one AI Part 7 used for its own deliberately-vulnerable lab, and the honest starting point of most real intrusions, ransomware crews very much included. j.reyes is a standard domain user, local admin on WKS01 and nowhere else. That’s the entire starting privilege level for everything that follows.
Stage 1: recon, no exploit required (Part 2)
$ GetADUsers.py CONTOSO.LOCAL/j.reyes:'Summer2026!' -all -dc-ip 10.10.30.10
Output: the full account list, including svc-legacy-scan (stale password, no pre-auth required) and svc-backup (registered SPN, member of Backup Operators). lookupsid.py and samrdump.py round out the picture with RIDs and group membership, confirming Domain Admins’ RID (512) for use much later in this chain. No exploit, no cracked password yet — just an authenticated LDAP/SAMR walk any domain user can perform, and the single most important step in the whole chain, because it’s what points every later stage at the right two accounts instead of guessing blindly.
Stage 2: AS-REP roasting, a dead end that isn’t wasted (Part 3)
$ GetNPUsers.py CONTOSO.LOCAL/ -usersfile users.txt -no-pass -format hashcat -outputfile asrep.txt -dc-ip 10.10.30.10
$ hashcat -m 18200 asrep.txt rockyou.txt
svc-legacy-scan’s hash cracks to Sc4nn3r2019!. In this specific chain, that account turns out not to be locally privileged anywhere interesting — a real, common outcome, not a scripted one. It’s kept rather than discarded, because a second working domain credential is never wasted effort on an assessment; it just isn’t this chain’s critical path.
Stage 3: Kerberoasting, the pivotal credential (Part 4)
$ GetUserSPNs.py CONTOSO.LOCAL/j.reyes:'Summer2026!' -dc-ip 10.10.30.10 -request -outputfile spns.txt
$ hashcat -m 13100 spns.txt rockyou.txt
svc-backup cracks to B4ckup$SQL2024. This is the pivotal credential of the entire chain: a Backup Operators member with a registered SPN on FS01. Everything from here forward depends on this one account, which is exactly why Part 4’s defensive notes on gMSA migration matter more than they might have looked in isolation — removing this one account from Kerberoasting’s reach would have ended this chain at Stage 3.
Stage 4: a shell on FS01 (Part 6)
$ wmiexec.py CONTOSO/svc-backup:'B4ckup$SQL2024'@10.10.30.20
C:\Windows\system32> whoami
contoso\svc-backup
Quiet, no service creation, no dropped binary — wmiexec.py specifically, of the four remote-exec options in Part 6, chosen here for exactly the low-telemetry properties that post described. This is also the point where the chain could have taken a shortcut: ntlmrelayx.py from Part 5 offers a route that skips Stages 2 and 3 entirely if a coercible authentication and an unsigned SMB target are both available — this chain didn’t need it because Kerberoasting already produced a usable credential, but on a domain where every service account uses a gMSA (closing Stage 3) and legacy accounts are all pre-auth-enforced (closing Stage 2), relay is very often the technique that reopens a path that otherwise looks closed.
Stage 5: the domain’s password material (Part 7)
$ secretsdump.py CONTOSO/svc-backup:'B4ckup$SQL2024'@10.10.30.10 -just-dc-user krbtgt
svc-backup’s Backup Operators membership — spotted back in Stage 1, exploited for a shell in Stage 4 — turns out to also carry the DRS replication rights DCSync needs. This is the misconfiguration the whole chain has actually been building toward: a group whose intended purpose (backup and restore) happened to carry a permission (replicate directory changes) with a completely different, much larger blast radius. krbtgt’s NT hash and AES keys come back in one request.
Stage 6: persistence that outlives the assessment (Part 8)
$ ticketer.py -nthash <krbtgt-nthash> -domain-sid S-1-5-21-1957667318-3765306688-1889875232 \
-domain CONTOSO.LOCAL -groups 512,518,519,520 fake.admin
$ export KRB5CCNAME=fake.admin.ccache
A Golden Ticket, for an account that doesn’t exist, carrying Domain Admins/Enterprise Admins/Schema Admins/GPO Creator Owners group SIDs, valid for ten years by default. This is where the chain stops being “an attacker with a shell” and becomes “an attacker who no longer needs any of the credentials used to get here” — j.reyes’s password could be reset, svc-backup’s password could be rotated, and fake.admin’s forged ticket keeps working regardless, right up until krbtgt itself is rotated twice.
What this chain looks like from the network, briefly
This series is deliberately scoped to Impacket itself and doesn’t try to be a packet-capture deep dive — that’s a different, already well-covered part of this site. But it’s worth naming the connection explicitly for readers who’ve followed the Fortinet packet-flow series: every stage above is, underneath the Python, still just SMB, MSRPC, and Kerberos traffic traversing whatever’s in front of FS01 and DC01 — a firewall’s session table and security profiles have no idea any of this is a domain compromise in progress unless something is specifically watching for the patterns described in Parts 2 through 8’s defensive notes, not just the ports involved, since 445 and 88 are exactly as “normal” during an attack as during business as usual. And on the forensic side, tools built for a completely different kind of protocol-level scrutiny turn out to be relevant here too: rst-forensics, built to classify who actually sent a TCP reset, is exactly the kind of tooling that matters once a segmentation control starts blocking Stage 4’s lateral movement attempt and a defender needs to know whether that reset came from the host, a mid-path firewall, or the client — the same three-way ambiguity this chain’s attacker is hoping nobody bothers to untangle. pmtud-sweeper’s per-hop path fingerprinting is a similar story from the other direction — understanding exactly what a network path allows through, hop by hop, is as useful for a defender scoping segmentation as it is for an assessor mapping what’s reachable from a given foothold.
What actually would have stopped this chain
Six independent controls, each covered in its own part’s defensive notes, and each sufficient on its own to break the chain at a different stage:
Stage 1 — LDAP query auditing wouldn’t have stopped the recon, but would have flagged it, buying the earliest possible detection window.
Stage 2 — enforcing Kerberos pre-authentication on every account (there is essentially never a legitimate reason not to) removes svc-legacy-scan from the board entirely.
Stage 3 — migrating svc-backup to a gMSA removes the pivotal credential of this entire chain. This is arguably the single highest-leverage fix in the whole series, precisely because so much of what follows depends on this one account specifically.
Stage 4 — WMI-Activity operational log collection turns wmiexec.py’s quietest property (low telemetry by default) into a non-issue.
Stage 5 — restricting DCSync rights to Domain Admins, Enterprise Admins, and DCs only, audited on a real schedule, is the fix for the actual root-cause misconfiguration this chain exploited: Backup Operators carrying replication rights it never needed.
Stage 6 — rotating krbtgt twice, on a schedule is the backstop that limits how long any successful compromise, via this chain or any other, remains useful to an attacker — the difference between a ticket that’s a problem for ten years and one that’s a problem for a few hours.
No single control here is sufficient by itself against a determined, patient attacker — that’s the actual argument for defense in depth, not a slogan. Part 10 consolidates all of it — every defensive note from Parts 2 through 8, plus the event ID reference table this series has been building piece by piece — into one standalone hardening and detection reference.